Rewrote the parser

This commit is contained in:
Jesse Braham 2024-12-24 09:02:18 +01:00
parent 96d1311e09
commit 88912bfa39
4 changed files with 335 additions and 289 deletions

View File

@ -59,6 +59,12 @@ impl<'lexer> Lexer<'lexer> {
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.
#[must_use]
fn current(&self) -> Option<char> {

View File

@ -4,9 +4,123 @@ use crate::{
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.
#[derive(Debug, Clone, PartialEq)]
pub enum Atom {
pub(crate) enum Atom {
/// Boolean, e.g. `true`, `false`
Bool(bool),
/// Character, e.g. `'c'`, `'\n'`
@ -45,7 +159,7 @@ impl std::fmt::Display for Atom {
/// An expression.
#[derive(Debug, Clone, PartialEq)]
pub enum NodeKind {
pub(crate) enum Expr {
/// An atomic value.
Atom(Atom),
/// A list of nodes.
@ -58,13 +172,25 @@ pub enum NodeKind {
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 {
Self::Atom(atom)
}
}
impl TryFrom<Token> for NodeKind {
impl TryFrom<Token> for Expr {
type Error = ParserError;
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::Nil => Atom::Nil,
_ => {
return Err(ParserError::new(
ParserErrorKind::UnexpectedState,
token.span,
))
// FIXME
// return Err(ParserError::new(
// ParserErrorKind::UnexpectedState,
// token.span,
// ))
todo!()
}
};
@ -90,9 +218,9 @@ impl TryFrom<Token> for NodeKind {
}
#[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 {
use NodeKind::*;
use Expr::*;
match self {
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))
}
}

View File

@ -5,19 +5,16 @@ use crate::{lexer::LexerError, span::Span};
pub enum ParserErrorKind {
/// An error which ocurred during lexical analysis.
Lexer(LexerError),
/// Expected a value for key in map, but no value was found.
/// Key in map is missing its corresponding value.
MissingValueInMap,
/// An unexpecting closing parenthesis/brace/bracket was encountered.
UnexpectedCloseBracket,
/// Unexpectedly reached the end of the input.
/// Opening delimiter does not have a matching closing delimiter.
UnclosedSequence,
/// An unexpected closing delimiter was found.
UnexpectedClosingDelimiter,
/// Unexpectedly reached end of input.
UnexpectedEof,
/// Unexpected parser state reached.
UnexpectedState,
/// Opening parenthesis/brace/bracket does not have a matching closing
/// parenthesis/brace/bracket.
UnclosedBracket,
/// An unmatched parenthesis/brace/bracket was encountered.
UnmatchedBracket,
/// An unmatched closing delimiter was found.
UnmatchedClosingDelimiter,
}
/// Parser error, with a start and end location.
@ -30,13 +27,20 @@ pub struct ParserError {
}
impl ParserError {
/// Construct a new instance of `ParserErorr`.
/// Construct a new instance of `ParserError`.
#[must_use]
pub const fn new(kind: ParserErrorKind, span: Span) -> Self {
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 {}
#[cfg(not(tarpaulin_include))]
@ -46,19 +50,14 @@ impl std::fmt::Display for ParserError {
match &self.kind {
Lexer(err) => write!(f, "{err}"),
MissingValueInMap => write!(f, "Key in map is missing its value"),
UnexpectedCloseBracket => write!(f, "Unexpected closing bracket"),
UnexpectedEof => write!(f, "Unexpected reached end of input"),
UnexpectedState => write!(f, "Unexpected parsing state reached"),
UnclosedBracket => write!(f, "Unclosed bracket"),
UnmatchedBracket => write!(f, "Unmatched bracket"),
MissingValueInMap => write!(f, "Key in map is missing its corresponding value"),
UnclosedSequence => write!(
f,
"Opening delimiter does not have a matching closing delimiter"
),
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)
}
}

View File

@ -1,154 +1,154 @@
pub use self::{
use self::{
ast::{Ast, Expr, Node},
error::{ParserError, ParserErrorKind},
node::{Node, NodeKind},
};
use crate::lexer::{Lexer, TokenKind};
use crate::{
lexer::{Lexer, TokenKind},
span::Span,
};
mod ast;
mod error;
mod node;
/// Parser for converting Onihime source code into an Abstract Syntax Tree
/// (AST).
#[derive(Debug)]
pub struct Parser<'parser> {
pub(crate) struct Parser<'parser> {
lexer: Lexer<'parser>,
parents: Vec<Node>,
current: Node,
}
impl<'parser> Parser<'parser> {
/// Create a new parser instance from a string.
#[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 {
lexer: Lexer::new(input),
lexer,
parents: Vec::new(),
current,
}
}
/// 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);
}
/// Parse the input string into an AST.
pub fn parse(&mut self) -> Result<Vec<Node>, ParserError> {
let mut parents = Vec::new();
let mut cur_node = Node::new(NodeKind::List(Vec::new()), self.lexer.span());
while let Some(token) = self.lexer.read()? {
match token.kind {
TokenKind::BlockComment(_) | TokenKind::LineComment(_) => {}
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)?;
}
/// Produce an Abstract Syntax Tree (AST) from the source input.
#[must_use]
pub(crate) fn parse(mut self) -> Result<Ast, ParserError> {
// This parser is actually quite simple!Recursively parse expressions until we
// run out of tokens, or an error occurs:
while !self.lexer.eof() {
if let Some(node) = self.expr()? {
self.current.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(
ParserErrorKind::UnclosedBracket,
cur_node.span,
ParserErrorKind::UnclosedSequence,
self.current.span,
));
}
if let NodeKind::List(body) = cur_node.kind {
Ok(body)
// Since we created an initial `Expr::List` node to hold the parsed contents
// (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 {
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)]
@ -156,8 +156,7 @@ mod tests {
use super::*;
use crate::{
lexer::{LexerError, LexerErrorKind, Symbol},
parser::node::Atom,
span::Span,
parser::ast::Atom,
};
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(
ParserErrorKind::Lexer(LexerError::new(
@ -181,35 +180,35 @@ mod tests {
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(
NodeKind::List(vec![
Expr::List(vec![
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(2).into(), Span::new(5..6, src.clone())),
]),
Span::new(0..7, src)
)
]));
])));
test!(error_list_unmatched_bracket: "(]", src => Err(ParserError::new(
ParserErrorKind::UnmatchedBracket,
ParserErrorKind::UnmatchedClosingDelimiter,
Span::new(1..2, src),
)));
test!(error_list_missing_close_paren: "(true", src => Err(ParserError::new(
ParserErrorKind::UnclosedBracket,
Span::new(0..1, src),
ParserErrorKind::UnclosedSequence,
Span::new(0..5, src),
)));
test!(error_list_unexpected_close_paren: ")", src => Err(ParserError::new(
ParserErrorKind::UnexpectedCloseBracket,
ParserErrorKind::UnexpectedClosingDelimiter,
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(
NodeKind::Map(vec![
Expr::Map(vec![
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::Keyword(Symbol::from("b")).into(), Span::new(9..11, src.clone())),
@ -217,7 +216,7 @@ mod tests {
]),
Span::new(0..16, src)
)
]));
])));
test!(error_map_missing_value: "#{:x}", src => Err(ParserError::new(
ParserErrorKind::MissingValueInMap,
@ -225,74 +224,74 @@ mod tests {
)));
test!(error_map_unmatched_bracket: "#{)", src => Err(ParserError::new(
ParserErrorKind::UnmatchedBracket,
ParserErrorKind::UnmatchedClosingDelimiter,
Span::new(2..3, src),
)));
test!(error_map_missing_close_brace: "#{", src => Err(ParserError::new(
ParserErrorKind::UnclosedBracket,
ParserErrorKind::UnclosedSequence,
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(
NodeKind::Set(vec![
Node::new(NodeKind::Set(vec![]), Span::new(1..3, src.clone())),
Node::new(NodeKind::Atom(Atom::Nil), Span::new(4..7, src.clone())),
Expr::Set(vec![
Node::new(Expr::Set(vec![]), Span::new(1..3, src.clone())),
Node::new(Expr::Atom(Atom::Nil), Span::new(4..7, src.clone())),
]),
Span::new(0..8, src),
)
]));
])));
test!(error_set_unmatched_bracket: "{]", src => Err(ParserError::new(
ParserErrorKind::UnmatchedBracket,
ParserErrorKind::UnmatchedClosingDelimiter,
Span::new(1..2, src),
)));
test!(error_set_missing_close_brace: "{", src => Err(ParserError::new(
ParserErrorKind::UnclosedBracket,
ParserErrorKind::UnclosedSequence,
Span::new(0..1, src),
)));
test!(error_map_set_unexpected_close_brace: "}", src => Err(ParserError::new(
ParserErrorKind::UnexpectedCloseBracket,
Span::new(0..1, src)
)));
test!(vector: "['a' 'b' 'c']", src => Ok(vec![
test!(vector: "['a' 'b' 'c']", src => Ok(Ast::from(vec![
Node::new(
NodeKind::Vector(vec![
Node::new(NodeKind::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(NodeKind::Atom(Atom::Char('c')), Span::new(9..12, src.clone())),
Expr::Vector(vec![
Node::new(Expr::Atom(Atom::Char('a')), Span::new(1..4, src.clone())),
Node::new(Expr::Atom(Atom::Char('b')), Span::new(5..8, src.clone())),
Node::new(Expr::Atom(Atom::Char('c')), Span::new(9..12, src.clone())),
]),
Span::new(0..13, src),
)
]));
])));
test!(error_vector_unmatched_bracket: "[}", src => Err(ParserError::new(
ParserErrorKind::UnmatchedBracket,
ParserErrorKind::UnmatchedClosingDelimiter,
Span::new(1..2, src),
)));
test!(error_vector_missing_close_bracket: "{", src => Err(ParserError::new(
ParserErrorKind::UnclosedBracket,
test!(error_vector_missing_close_bracket: "[", src => Err(ParserError::new(
ParserErrorKind::UnclosedSequence,
Span::new(0..1, src),
)));
test!(error_vector_unexpected_close_bracket: "]", src => Err(ParserError::new(
ParserErrorKind::UnexpectedCloseBracket,
ParserErrorKind::UnexpectedClosingDelimiter,
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(
NodeKind::List(vec![
Expr::List(vec![
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(3).into(), Span::new(5..6, src.clone())),
Node::new(
NodeKind::List(vec![
Expr::List(vec![
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(2).into(), Span::new(12..13, src.clone())),
@ -303,7 +302,7 @@ mod tests {
Span::new(0..15, src.clone())
),
Node::new(
NodeKind::List(vec![
Expr::List(vec![
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(5).into(), Span::new(21..22, src.clone())),
@ -311,21 +310,21 @@ mod tests {
Span::new(16..23, src.clone())
),
Node::new(
NodeKind::List(vec![
Expr::List(vec![
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(5).into(), Span::new(30..31, src.clone())),
]),
Span::new(24..32, src)
),
]));
])));
test!(function_application: "(join \"foo\" \"bar\")", src => Ok(vec![Node::new(
NodeKind::List(vec![
test!(function_application: "(join \"foo\" \"bar\")", src => Ok(Ast::from(vec![Node::new(
Expr::List(vec![
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("bar".into()).into(), Span::new(12..17, src.clone())),
]),
Span::new(0..18, src)
)]));
)])));
}