Add defereference expressions

This commit is contained in:
Jeff 2024-08-28 11:31:47 -04:00
parent 5f733ba1dd
commit b02e5244f2
6 changed files with 85 additions and 18 deletions

View File

@ -314,6 +314,9 @@ impl<'a> Analyzer<'a> {
self.analyze_expression(argument, statement_position); self.analyze_expression(argument, statement_position);
} }
} }
Expression::Dereference(expression) => {
self.analyze_expression(&expression.inner, statement_position);
}
Expression::FieldAccess(field_access_expression) => { Expression::FieldAccess(field_access_expression) => {
let FieldAccessExpression { container, field } = let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref(); field_access_expression.inner.as_ref();

View File

@ -18,6 +18,7 @@ pub enum Expression {
Block(Node<Box<BlockExpression>>), Block(Node<Box<BlockExpression>>),
Break(Node<Option<Box<Expression>>>), Break(Node<Option<Box<Expression>>>),
Call(Node<Box<CallExpression>>), Call(Node<Box<CallExpression>>),
Dereference(Node<Box<Expression>>),
FieldAccess(Node<Box<FieldAccessExpression>>), FieldAccess(Node<Box<FieldAccessExpression>>),
Grouped(Node<Box<Expression>>), Grouped(Node<Box<Expression>>),
Identifier(Node<Identifier>), Identifier(Node<Identifier>),
@ -34,6 +35,10 @@ pub enum Expression {
} }
impl Expression { impl Expression {
pub fn dereference(expression: Expression, position: Span) -> Self {
Self::Dereference(Node::new(Box::new(expression), position))
}
pub fn r#break(expression: Option<Expression>, position: Span) -> Self { pub fn r#break(expression: Option<Expression>, position: Span) -> Self {
Self::Break(Node::new(expression.map(Box::new), position)) Self::Break(Node::new(expression.map(Box::new), position))
} }
@ -304,6 +309,7 @@ impl Expression {
} }
} }
} }
Expression::Dereference(expression) => expression.inner.type_evaluation(context)?,
Expression::FieldAccess(field_access_expression) => { Expression::FieldAccess(field_access_expression) => {
let FieldAccessExpression { container, field } = let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref(); field_access_expression.inner.as_ref();
@ -571,6 +577,7 @@ impl Expression {
Expression::Block(block) => block.position, Expression::Block(block) => block.position,
Expression::Break(expression_node) => expression_node.position, Expression::Break(expression_node) => expression_node.position,
Expression::Call(call) => call.position, Expression::Call(call) => call.position,
Expression::Dereference(expression_node) => expression_node.position,
Expression::FieldAccess(field_access) => field_access.position, Expression::FieldAccess(field_access) => field_access.position,
Expression::Grouped(grouped) => grouped.position, Expression::Grouped(grouped) => grouped.position,
Expression::Identifier(identifier) => identifier.position, Expression::Identifier(identifier) => identifier.position,
@ -600,6 +607,7 @@ impl Display for Expression {
} }
} }
Expression::Call(call) => write!(f, "{}", call.inner), Expression::Call(call) => write!(f, "{}", call.inner),
Expression::Dereference(expression_node) => write!(f, "*{}", expression_node.inner),
Expression::FieldAccess(field_access) => write!(f, "{}", field_access.inner), Expression::FieldAccess(field_access) => write!(f, "{}", field_access.inner),
Expression::Grouped(grouped) => write!(f, "({})", grouped.inner), Expression::Grouped(grouped) => write!(f, "({})", grouped.inner),
Expression::Identifier(identifier) => write!(f, "{}", identifier.inner), Expression::Identifier(identifier) => write!(f, "{}", identifier.inner),

View File

@ -369,8 +369,16 @@ impl<'src> Parser<'src> {
Ok(Expression::negation(operand, position)) Ok(Expression::negation(operand, position))
} }
Token::Star => {
self.next_token()?;
let operand = self.parse_expression(0)?;
let position = (operator_start, self.current_position.1);
Ok(Expression::dereference(operand, position))
}
_ => Err(ParseError::ExpectedTokenMultiple { _ => Err(ParseError::ExpectedTokenMultiple {
expected: vec![TokenKind::Bang, TokenKind::Minus], expected: vec![TokenKind::Bang, TokenKind::Minus, TokenKind::Star],
actual: self.current_token.to_owned(), actual: self.current_token.to_owned(),
position: self.current_position, position: self.current_position,
}), }),
@ -1157,6 +1165,21 @@ mod tests {
use super::*; use super::*;
#[test]
fn dereference() {
let source = "*a";
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::dereference(
Expression::identifier(Identifier::new("a"), (1, 2)),
(0, 2)
),)
]))
);
}
#[test] #[test]
fn character_literal() { fn character_literal() {
let source = "'a'"; let source = "'a'";

View File

@ -270,7 +270,7 @@ impl<'src> Token<'src> {
} }
pub fn is_prefix(&self) -> bool { pub fn is_prefix(&self) -> bool {
matches!(self, Token::Bang | Token::Minus) matches!(self, Token::Bang | Token::Minus | Token::Star)
} }
pub fn is_postfix(&self) -> bool { pub fn is_postfix(&self) -> bool {

View File

@ -130,6 +130,14 @@ impl Value {
} }
} }
pub fn into_raw(self) -> Self {
match self {
Value::Raw(_) => self,
Value::Reference(data) => Value::Raw(data.as_ref().clone()),
Value::Mutable(data) => Value::Raw(data.read().unwrap().clone()),
}
}
pub fn into_reference(self) -> Self { pub fn into_reference(self) -> Self {
match self { match self {
Value::Raw(data) => Value::Reference(Arc::new(data)), Value::Raw(data) => Value::Reference(Arc::new(data)),
@ -158,6 +166,13 @@ impl Value {
} }
} }
pub fn is_raw(&self) -> bool {
match self {
Value::Raw(_) => true,
_ => false,
}
}
pub fn as_mutable(&self) -> Option<&Arc<RwLock<ValueData>>> { pub fn as_mutable(&self) -> Option<&Arc<RwLock<ValueData>>> {
match self { match self {
Value::Mutable(data) => Some(data), Value::Mutable(data) => Some(data),
@ -1398,7 +1413,7 @@ impl Function {
} }
} }
let mut vm = Vm::new(new_context); let vm = Vm::new(new_context);
vm.run(body) vm.run(body)
.map_err(|error| FunctionCallError::Runtime(Box::new(error))) .map_err(|error| FunctionCallError::Runtime(Box::new(error)))

View File

@ -7,7 +7,6 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
rc::Weak,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -243,18 +242,12 @@ impl Vm {
let position = value.position(); let position = value.position();
let value = self let value = self
.run_expression(value, collect_garbage)? .run_expression(value, collect_garbage)?
.expect_value(position)?; .expect_value(position)?
.into_raw()
let reference = match value { .into_reference();
Value::Raw(_) => value.into_reference(),
Value::Reference(_) => value,
Value::Mutable(_) => {
return Err(RuntimeError::CannotAssignToMutable { position });
}
};
self.context self.context
.set_variable_value(identifier.inner, reference) .set_variable_value(identifier.inner, value)
.map_err(|error| RuntimeError::ContextError { error, position })?; .map_err(|error| RuntimeError::ContextError { error, position })?;
Ok(()) Ok(())
@ -264,6 +257,7 @@ impl Vm {
let mutable_value = self let mutable_value = self
.run_expression(value, collect_garbage)? .run_expression(value, collect_garbage)?
.expect_value(position)? .expect_value(position)?
.into_raw()
.into_mutable(); .into_mutable();
self.context self.context
@ -309,6 +303,22 @@ impl Vm {
Ok(evaluation) Ok(evaluation)
} }
Expression::Call(call) => self.run_call(*call.inner, collect_garbage), Expression::Call(call) => self.run_call(*call.inner, collect_garbage),
Expression::Dereference(Node { inner, .. }) => {
let run_expression = self.run_expression(*inner, collect_garbage)?;
let evaluation = match run_expression {
Evaluation::Constructor(_) => {
return Err(RuntimeError::ExpectedValue { position })
}
Evaluation::Return(value_option) => {
Evaluation::Return(value_option.map(|value| value.into_raw()))
}
Evaluation::Break(value_option) => {
Evaluation::Break(value_option.map(|value| value.into_raw()))
}
};
Ok(evaluation)
}
Expression::FieldAccess(field_access) => { Expression::FieldAccess(field_access) => {
self.run_field_access(*field_access.inner, collect_garbage) self.run_field_access(*field_access.inner, collect_garbage)
} }
@ -978,7 +988,8 @@ impl Vm {
let position = repeat_operand.position(); let position = repeat_operand.position();
let value = self let value = self
.run_expression(repeat_operand, collect_garbage)? .run_expression(repeat_operand, collect_garbage)?
.expect_value(position)?; .expect_value(position)?
.into_raw();
Ok(Evaluation::Return(Some(Value::list(vec![ Ok(Evaluation::Return(Some(Value::list(vec![
value; value;
@ -1417,13 +1428,20 @@ mod tests {
use super::*; use super::*;
#[test]
fn dereference_variable() {
let source = "let x = 42; let y = x; *y";
assert!(run(source).unwrap().unwrap().is_raw());
}
#[test] #[test]
fn mutate_copied_variable() { fn mutate_copied_variable() {
let source = "let mut x = 42; let y = [x; 3]; x += 1; y"; let source = "let mut x = 42; let y = [x; 3]; x += 1; y";
assert_eq!( assert_eq!(
run(source), run(source),
Ok(Some(Value::list([43.into(), 43.into(), 43.into()]))) Ok(Some(Value::list([42.into(), 42.into(), 42.into()])))
); );
} }
@ -1443,9 +1461,9 @@ mod tests {
#[test] #[test]
fn mutate_assigned_variable() { fn mutate_assigned_variable() {
let source = "let mut x = 42; let mut y = x; x += 1; y"; let source = "let mut x = 42; let y = x; x += 1; y";
assert_eq!(run(source), Ok(Some(Value::integer(43)))); assert_eq!(run(source), Ok(Some(Value::integer(42))));
} }
#[test] #[test]