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