Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ clap = { version = "4.5.39", features = ["derive"] }
criterion = { version = "0.6.0", features = ["html_reports"] }
derive_more = { version = "2.0.1", features = ["deref", "deref_mut", "from", "constructor"] }
derive_builder = { version = "0.20.2" }
either = "1.15.0"
strsim = "0.11.1"
factorial = "0.4.0"
itertools = "0.14.0"
Expand Down
1 change: 0 additions & 1 deletion ndc_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ ahash = { workspace = true, optional = true }
anyhow.workspace = true
derive_more.workspace = true
derive_builder.workspace = true
either.workspace = true
factorial.workspace = true
itertools.workspace = true
miette.workspace = true
Expand Down
41 changes: 6 additions & 35 deletions ndc_lib/src/ast/expression.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::ast::operator::{BinaryOperator, LogicalOperator, UnaryOperator};
use crate::ast::operator::LogicalOperator;
use crate::ast::parser::Error as ParseError;
use crate::interpreter::evaluate::EvaluationError;
use crate::lexer::Span;
use either::Either;
use num::BigInt;
use num::complex::Complex64;
use std::fmt;
Expand All @@ -25,17 +24,7 @@ pub enum Expression {
BigIntLiteral(BigInt),
ComplexLiteral(Complex64),
Identifier(String),
//
Statement(Box<ExpressionLocation>),
Unary {
operator: UnaryOperator,
expression: Box<ExpressionLocation>,
},
Binary {
left: Box<ExpressionLocation>,
operator: BinaryOperator,
right: Box<ExpressionLocation>,
},
Logical {
left: Box<ExpressionLocation>,
operator: LogicalOperator,
Expand All @@ -52,14 +41,14 @@ pub enum Expression {
},
OpAssignment {
l_value: Lvalue,
value: Box<ExpressionLocation>,
operation: Either<BinaryOperator, String>,
r_value: Box<ExpressionLocation>,
operation: String,
},
FunctionDeclaration {
name: Option<Box<ExpressionLocation>>,
arguments: Box<ExpressionLocation>,
body: Rc<ExpressionLocation>, //TODO what happens if we remove the Rc?
pure: bool, // TODO: maybe have flags instead of booleans?
body: Rc<ExpressionLocation>,
pure: bool,
},
Block {
statements: Vec<ExpressionLocation>,
Expand Down Expand Up @@ -288,24 +277,6 @@ impl fmt::Debug for ExpressionLocation {
.debug_struct("Statement")
.field("expression", &expression_location)
.finish(),
Expression::Unary {
operator,
expression,
} => f
.debug_struct("Unary")
.field("operator", operator)
.field("expression", expression)
.finish(),
Expression::Binary {
left,
operator,
right,
} => f
.debug_struct("Binary")
.field("left", left)
.field("operator", operator)
.field("right", right)
.finish(),
Expression::Logical {
left,
operator,
Expand All @@ -332,7 +303,7 @@ impl fmt::Debug for ExpressionLocation {
.finish(),
Expression::OpAssignment {
l_value,
value,
r_value: value,
operation,
} => f
.debug_struct("OpAssignment")
Expand Down
105 changes: 62 additions & 43 deletions ndc_lib/src/ast/parser.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::fmt::Write;
use std::rc::Rc;

use either::Either;
use miette::Diagnostic;

use crate::ast::Expression;
Expand Down Expand Up @@ -166,7 +165,7 @@ impl Parser {
}

while let Some(token_location) = self.consume_token_if(&extended_valid_tokens) {
let (invert, token_location) = if token_location.token == Token::LogicNot {
let (invert, operator_token_loc) = if token_location.token == Token::LogicNot {
let augmented = self.consume_token_if(valid_tokens).ok_or_else(|| {
Error::text(
format!(
Expand All @@ -185,28 +184,38 @@ impl Parser {
(None, token_location)
};

let operator: BinaryOperator = token_location.clone().try_into().unwrap_or_else(|_| {
panic!(
"cannot convert '{}' into a binary operator",
token_location.token
)
});
let operator: BinaryOperator =
operator_token_loc.clone().try_into().unwrap_or_else(|_| {
panic!(
"cannot convert '{}' into a binary operator",
operator_token_loc.token
)
});
let right = next(self)?;
// IS this new span logic sound?
let new_span = left.span.merge(right.span);
left = Expression::Binary {
left: Box::new(left),
operator,
right: Box::new(right),

// Is this always the same
debug_assert_eq!(operator.to_string(), operator_token_loc.token.to_string());

left = Expression::Call {
function: Box::new(
Expression::Identifier(operator_token_loc.token.to_string())
.to_location(operator_token_loc.span),
),
arguments: vec![left, right],
}
.to_location(new_span);

if let Some(invert) = invert {
left = Expression::Unary {
expression: Box::new(left),
operator: UnaryOperator::Not,
if let Some(not_token) = invert {
left = Expression::Call {
function: Box::new(
Expression::Identifier(not_token.token.to_string())
.to_location(not_token.span),
),
arguments: vec![left],
}
.to_location(new_span.merge(invert.span));
.to_location(new_span.merge(not_token.span));
}
}
Ok(left)
Expand All @@ -221,15 +230,18 @@ impl Parser {
let left = next(self)?;

if let Some(token_location) = self.consume_token_if(valid_tokens) {
let operator_span = token_location.span;
let operator = BinaryOperator::try_from(token_location)
.expect("COMPILER ERROR: consume_token_if must guarantee the correct token");
let right = current(self)?;

let new_span = left.span.merge(right.span);
return Ok(Expression::Binary {
left: Box::new(left),
operator,
right: Box::new(right),

return Ok(Expression::Call {
function: Box::new(
Expression::Identifier(operator.to_string()).to_location(operator_span),
),
arguments: vec![left, right],
}
.to_location(new_span));
}
Expand Down Expand Up @@ -295,7 +307,7 @@ impl Parser {
return Err(Error::with_help(
"Invalid assignment target".to_string(),
lvalue_span,
"Assignment target is not a valid lvalue. Only a few expressions can be assigned a value. Check that the left-hand side of the assignment is a valid target.".to_string()
"Assignment target is not a valid lvalue. Only a few expressions can be assigned a value. Check that the left-hand side of the assignment is a valid target.".to_string(),
));
};

Expand Down Expand Up @@ -334,7 +346,7 @@ impl Parser {
Some(Token::EqualsSign) => Err(Error::with_help(
"Invalid assignment target".to_string(),
maybe_lvalue.span,
"Assignment target is not a valid lvalue. Only a few expressions can be assigned a value. Check that the left-hand side of the assignment is a valid target.".to_string()
"Assignment target is not a valid lvalue. Only a few expressions can be assigned a value. Check that the left-hand side of the assignment is a valid target.".to_string(),
)),
_ => Ok(maybe_lvalue),
};
Expand All @@ -355,19 +367,16 @@ impl Parser {
Ok(assignment_expression.to_location(start.merge(end)))
}
Some(Token::OpAssign(inner)) => {
let thing = match &inner.token {
Token::Identifier(identifier) => Either::Right(identifier.to_string()),
_ => Either::Left((*inner.clone()).try_into()?),
};
let operation_identifier = inner.token.to_string();

self.advance();
let expression = self.tuple_expression(Self::single_expression, false)?;
let end = expression.span;
let op_assign = Expression::OpAssignment {
l_value: Lvalue::try_from(maybe_lvalue)
.expect("guaranteed to produce an lvalue"),
value: Box::new(expression),
operation: thing,
r_value: Box::new(expression),
operation: operation_identifier,
};

Ok(op_assign.to_location(start.merge(end)))
Expand Down Expand Up @@ -450,17 +459,22 @@ impl Parser {
// x := not foo in bar
// ```
fn logic_not(&mut self) -> Result<ExpressionLocation, Error> {
if let Some(token) = self.consume_token_if(&[Token::LogicNot]) {
let operator: UnaryOperator = token
if let Some(operator_token_loc) = self.consume_token_if(&[Token::LogicNot]) {
let operator_span = operator_token_loc.span;
let _: UnaryOperator = operator_token_loc
.clone()
.try_into()
.expect("consume_operator_if guaranteed us that this token can be UnaryOperator");

let right = self.logic_not()?;
let span = right.span;

Ok(Expression::Unary {
operator,
expression: Box::new(right),
Ok(Expression::Call {
function: Box::new(
Expression::Identifier(operator_token_loc.token.to_string())
.to_location(operator_span),
),
arguments: vec![right],
}
.to_location(span))
} else {
Expand Down Expand Up @@ -571,18 +585,20 @@ impl Parser {
}

fn tight_unary(&mut self) -> Result<ExpressionLocation, Error> {
if let Some(token) = self.consume_token_if(&[Token::Bang, Token::Minus, Token::Tilde]) {
let token_span = token.span;
let operator: UnaryOperator = token
.try_into()
.expect("consume_operator_if guaranteed us that the next token is an Operator");
if let Some(operator_token_loc) =
self.consume_token_if(&[Token::Bang, Token::Minus, Token::Tilde])
{
let token_span = operator_token_loc.span;

let right = self.tight_unary()?;
let span = right.span;

Ok(Expression::Unary {
operator,
expression: Box::new(right),
Ok(Expression::Call {
function: Box::new(
Expression::Identifier(operator_token_loc.token.to_string())
.to_location(token_span),
),
arguments: vec![right],
}
.to_location(span.merge(token_span)))
} else {
Expand Down Expand Up @@ -1084,7 +1100,10 @@ impl Parser {
// Next we either expect a body block `{ ... }` or a fat arrow followed by a single expression `=> ...`

let body = match self.peek_current_token() {
Some(Token::FatArrow) => { self.advance(); self.single_expression()?},
Some(Token::FatArrow) => {
self.advance();
self.single_expression()?
}
Some(Token::LeftCurlyBracket) => self.block()?,
Some(token) => {
return Err(Error::with_help(
Expand Down
11 changes: 5 additions & 6 deletions ndc_lib/src/hash_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ pub use std::hash::DefaultHasher;

use std::hash::Hash;

#[allow(dead_code)]
pub trait HashMapExt<K, V> {
fn union(&mut self, right: HashMap<K, V>)
fn union(&mut self, right: Self)
where
K: Hash + Eq;
fn difference(&mut self, right: HashMap<K, V>)
fn difference(&mut self, right: &Self)
where
K: Hash + Eq;
fn intersection(&mut self, right: HashMap<K, V>)
fn intersection(&mut self, right: &Self)
where
K: Hash + Eq;
}
Expand All @@ -33,14 +32,14 @@ impl<K, V> HashMapExt<K, V> for HashMap<K, V> {
}
}

fn difference(&mut self, other: Self)
fn difference(&mut self, other: &Self)
where
K: Hash + Eq,
{
self.retain(|key, _| !other.contains_key(key));
}

fn intersection(&mut self, other: Self)
fn intersection(&mut self, other: &Self)
where
K: Hash + Eq,
{
Expand Down
Loading