Add parsing for mutable assignment

This commit is contained in:
Jeff 2024-08-14 03:53:15 -04:00
parent 3ff3a7568c
commit 8666f1cd9b
5 changed files with 144 additions and 40 deletions

View File

@ -54,6 +54,10 @@ pub enum Statement {
operator: Node<AssignmentOperator>,
value: Box<Node<Statement>>,
},
MutAssignment {
identifier: Node<Identifier>,
value: Box<Node<Statement>>,
},
// Statement blocks, delimited by curly braces
AsyncBlock(Vec<Node<Statement>>),
@ -214,6 +218,7 @@ impl Statement {
Some(Type::Map(types))
}
Statement::MutAssignment { .. } => None,
Statement::Nil(_) => None,
Statement::UnaryOperation { operator, operand } => match operator.inner {
UnaryOperator::Negate => Some(operand.inner.expected_type(context)?),
@ -447,6 +452,9 @@ impl Display for Statement {
write!(f, "}}")
}
Statement::MutAssignment { identifier, value } => {
write!(f, "mut {identifier} = {value}")
}
Statement::Nil(node) => write!(f, "{node};"),
Statement::UnaryOperation { operator, operand } => {
let operator = match operator.inner {

View File

@ -90,15 +90,11 @@ impl<'a> Analyzer<'a> {
actual: value.as_ref().clone(),
});
}
return Ok(());
}
Statement::AsyncBlock(statements) => {
for statement in statements {
self.analyze_statement(statement)?;
}
return Ok(());
}
Statement::BinaryOperation {
left,
@ -483,6 +479,20 @@ impl<'a> Analyzer<'a> {
self.analyze_statement(value_node)?;
}
}
Statement::MutAssignment { identifier, value } => {
self.analyze_statement(value)?;
let value_type = value.inner.expected_type(self.context);
if let Some(r#type) = value_type {
self.context
.set_type(identifier.inner.clone(), r#type, identifier.position);
} else {
return Err(AnalyzerError::ExpectedValue {
actual: value.as_ref().clone(),
});
}
}
Statement::Nil(node) => {
self.analyze_statement(node)?;
}

View File

@ -125,7 +125,7 @@ pub struct Parser<'src> {
source: &'src str,
lexer: Lexer,
current: (Token<'src>, Span),
context: ParserContext,
mode: ParserMode,
}
impl<'src> Parser<'src> {
@ -137,7 +137,7 @@ impl<'src> Parser<'src> {
source,
lexer,
current,
context: ParserContext::None,
mode: ParserMode::None,
}
}
@ -158,12 +158,8 @@ impl<'src> Parser<'src> {
fn parse_statement(&mut self, mut precedence: u8) -> Result<Node<Statement>, ParseError> {
// Parse a statement starting from the current node.
let mut left = if self.current.0.is_prefix() {
log::trace!("Parsing {} as prefix operator", self.current.0);
self.parse_prefix()?
} else {
log::trace!("Parsing {} as primary", self.current.0);
self.parse_primary()?
};
@ -171,26 +167,45 @@ impl<'src> Parser<'src> {
while precedence < self.current.0.precedence() {
// Give precedence to postfix operations
left = if self.current.0.is_postfix() {
log::trace!("Parsing {} as postfix operator", self.current.0);
// Replace the left-hand side with the postfix operation
let statement = self.parse_postfix(left)?;
precedence = self.current.0.precedence();
// Replace the left-hand side with the postfix operation
statement
} else {
log::trace!("Parsing {} as infix operator", self.current.0);
// Replace the left-hand side with the infix operation
self.parse_infix(left)?
};
}
log::trace!(
"{}'s precedence is lower than or equal to {}",
self.current.0,
precedence
);
Ok(left)
}
fn parse_statement_in_mode(
&mut self,
mode: ParserMode,
precedence: u8,
) -> Result<Node<Statement>, ParseError> {
let old_mode = self.mode;
self.mode = mode;
let result = self.parse_statement(precedence);
self.mode = old_mode;
result
}
fn parse_prefix(&mut self) -> Result<Node<Statement>, ParseError> {
log::trace!("Parsing {} as prefix operator", self.current.0);
match self.current {
(Token::Bang, position) => {
self.next_token()?;
@ -228,6 +243,8 @@ impl<'src> Parser<'src> {
}
fn parse_primary(&mut self) -> Result<Node<Statement>, ParseError> {
log::trace!("Parsing {} as primary", self.current.0);
match self.current {
(Token::Async, position) => {
self.next_token()?;
@ -287,7 +304,7 @@ impl<'src> Parser<'src> {
(Token::Identifier(text), position) => {
self.next_token()?;
if let ParserContext::IfElseStatement = self.context {
if let ParserMode::Condition = self.mode {
return Ok(Node::new(
Statement::Identifier(Identifier::new(text)),
position,
@ -379,9 +396,7 @@ impl<'src> Parser<'src> {
(Token::If, position) => {
self.next_token()?;
self.context = ParserContext::IfElseStatement;
let condition = Box::new(self.parse_statement(0)?);
let condition = Box::new(self.parse_statement_in_mode(ParserMode::Condition, 0)?);
let if_body = Box::new(self.parse_block()?);
if let Token::Else = self.current.0 {
@ -390,7 +405,10 @@ impl<'src> Parser<'src> {
if let Token::If = self.current.0 {
self.next_token()?;
let first_else_if = (self.parse_statement(0)?, self.parse_statement(0)?);
let first_else_if = (
self.parse_statement_in_mode(ParserMode::Condition, 0)?,
self.parse_statement(0)?,
);
let mut else_ifs = vec![first_else_if];
loop {
@ -410,15 +428,16 @@ impl<'src> Parser<'src> {
if let Token::If = self.current.0 {
self.next_token()?;
let else_if = (self.parse_statement(0)?, self.parse_statement(0)?);
let else_if = (
self.parse_statement_in_mode(ParserMode::Condition, 0)?,
self.parse_statement(0)?,
);
else_ifs.push(else_if);
} else {
let else_body = Box::new(self.parse_block()?);
let else_end = else_body.position.1;
self.context = ParserContext::None;
return Ok(Node::new(
Statement::IfElseIfElse {
condition,
@ -434,8 +453,6 @@ impl<'src> Parser<'src> {
let else_body = Box::new(self.parse_block()?);
let else_end = else_body.position.1;
self.context = ParserContext::None;
Ok(Node::new(
Statement::IfElse {
condition,
@ -448,7 +465,7 @@ impl<'src> Parser<'src> {
} else {
let if_end = if_body.position.1;
self.context = ParserContext::None;
self.mode = ParserMode::None;
Ok(Node::new(
Statement::If {
@ -676,6 +693,29 @@ impl<'src> Parser<'src> {
left_position,
))
}
(Token::Mut, left_position) => {
self.next_token()?;
let identifier = self.parse_identifier()?;
if let (Token::Equal, _) = self.current {
self.next_token()?;
} else {
return Err(ParseError::ExpectedToken {
expected: TokenKind::Equal,
actual: self.current.0.to_owned(),
position: self.current.1,
});
}
let value = Box::new(self.parse_statement(0)?);
let value_end = value.position.1;
Ok(Node::new(
Statement::MutAssignment { identifier, value },
(left_position.0, value_end),
))
}
(Token::Struct, left_position) => {
self.next_token()?;
@ -769,7 +809,7 @@ impl<'src> Parser<'src> {
(Token::While, left_position) => {
self.next_token()?;
let condition = self.parse_statement(0)?;
let condition = self.parse_statement_in_mode(ParserMode::Condition, 0)?;
let body = self.parse_block()?;
let body_end = body.position.1;
@ -790,6 +830,8 @@ impl<'src> Parser<'src> {
}
fn parse_infix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
log::trace!("Parsing {} as infix operator", self.current.0);
let operator_precedence = self.current.0.precedence()
- if self.current.0.is_right_associative() {
1
@ -935,6 +977,8 @@ impl<'src> Parser<'src> {
}
fn parse_postfix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
log::trace!("Parsing {} as postfix operator", self.current.0);
let left_start = left.position.0;
let statement = match &self.current.0 {
@ -1095,8 +1139,9 @@ impl<'src> Parser<'src> {
}
}
enum ParserContext {
IfElseStatement,
#[derive(Debug, PartialEq, Clone, Copy)]
enum ParserMode {
Condition,
None,
}
@ -1219,9 +1264,8 @@ mod tests {
parse(input),
Ok(AbstractSyntaxTree {
nodes: [Node::new(
Statement::Assignment {
Statement::MutAssignment {
identifier: Node::new(Identifier::new("x"), (4, 5)),
operator: Node::new(AssignmentOperator::Assign, (6, 7)),
value: Box::new(Node::new(
Statement::Constant(Value::integer(42)),
(8, 10)
@ -1278,7 +1322,12 @@ mod tests {
#[test]
fn tuple_struct_access() {
let input = "Foo(42, 'bar').0";
let input = "(Foo(42, 'bar')).0";
let mut tree = AbstractSyntaxTree::new();
if parse_into(input, &mut tree).is_err() {
println!("{tree:?}")
}
assert_eq!(
parse(input),
@ -1289,23 +1338,23 @@ mod tests {
Statement::Invokation {
invokee: Box::new(Node::new(
Statement::Identifier(Identifier::new("Foo")),
(0, 3)
(1, 4)
)),
type_arguments: None,
value_arguments: Some(vec![
Node::new(Statement::Constant(Value::integer(42)), (4, 6)),
Node::new(Statement::Constant(Value::string("bar")), (8, 11))
Node::new(Statement::Constant(Value::integer(42)), (5, 7)),
Node::new(Statement::Constant(Value::string("bar")), (9, 14))
]),
},
(0, 12)
(0, 16)
)),
operator: Node::new(BinaryOperator::FieldAccess, (13, 14)),
operator: Node::new(BinaryOperator::FieldAccess, (16, 17)),
right: Box::new(Node::new(
Statement::Constant(Value::integer(0)),
(15, 16)
(17, 18)
))
},
(0, 16)
(0, 18)
)]
.into()
})

View File

@ -95,6 +95,31 @@ impl Value {
Value::Mutable(Arc::new(RwLock::new(ValueData::Boolean(boolean))))
}
pub fn to_mut(self) -> Self {
match self {
Value::Immutable(inner) => {
Value::Mutable(Arc::new(RwLock::new(inner.as_ref().clone())))
}
_ => self,
}
}
pub fn mutate(&self, other: &Value) -> Result<(), VmError> {
let other_data = match other {
Value::Immutable(inner) => inner.as_ref().clone(),
Value::Mutable(inner_locked) => inner_locked.read().unwrap().clone(),
};
match self {
Value::Mutable(locked) => {
*locked.write().unwrap() = other_data;
Ok(())
}
Value::Immutable(_) => todo!(),
}
}
pub fn r#type(&self) -> Type {
match self {
Value::Immutable(inner) => inner.r#type(),

View File

@ -360,7 +360,7 @@ impl Vm {
Ok(function_call_return)
}
Statement::Constant(value) => Ok(Some(value.clone())),
Statement::Constant(value) => Ok(Some(value)),
Statement::FieldsStructInstantiation { name, fields } => {
let mut values = Vec::new();
@ -649,6 +649,18 @@ impl Vm {
Ok(Some(Value::map(values)))
}
Statement::MutAssignment { identifier, value } => {
let position = value.position;
let value = if let Some(value) = self.run_statement(*value)? {
value.to_mut()
} else {
return Err(VmError::ExpectedValue { position });
};
self.context.set_value(identifier.inner, value);
Ok(None)
}
Statement::Nil(node) => {
let _return = self.run_statement(*node)?;