Add parsing for mutable assignment
This commit is contained in:
parent
3ff3a7568c
commit
8666f1cd9b
@ -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 {
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
@ -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()
|
||||
})
|
||||
|
@ -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(),
|
||||
|
@ -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)?;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user