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

View File

@ -90,15 +90,11 @@ impl<'a> Analyzer<'a> {
actual: value.as_ref().clone(), actual: value.as_ref().clone(),
}); });
} }
return Ok(());
} }
Statement::AsyncBlock(statements) => { Statement::AsyncBlock(statements) => {
for statement in statements { for statement in statements {
self.analyze_statement(statement)?; self.analyze_statement(statement)?;
} }
return Ok(());
} }
Statement::BinaryOperation { Statement::BinaryOperation {
left, left,
@ -483,6 +479,20 @@ impl<'a> Analyzer<'a> {
self.analyze_statement(value_node)?; 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) => { Statement::Nil(node) => {
self.analyze_statement(node)?; self.analyze_statement(node)?;
} }

View File

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

View File

@ -95,6 +95,31 @@ impl Value {
Value::Mutable(Arc::new(RwLock::new(ValueData::Boolean(boolean)))) 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 { pub fn r#type(&self) -> Type {
match self { match self {
Value::Immutable(inner) => inner.r#type(), Value::Immutable(inner) => inner.r#type(),

View File

@ -360,7 +360,7 @@ impl Vm {
Ok(function_call_return) Ok(function_call_return)
} }
Statement::Constant(value) => Ok(Some(value.clone())), Statement::Constant(value) => Ok(Some(value)),
Statement::FieldsStructInstantiation { name, fields } => { Statement::FieldsStructInstantiation { name, fields } => {
let mut values = Vec::new(); let mut values = Vec::new();
@ -649,6 +649,18 @@ impl Vm {
Ok(Some(Value::map(values))) 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) => { Statement::Nil(node) => {
let _return = self.run_statement(*node)?; let _return = self.run_statement(*node)?;