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);
}
}
Expression::Dereference(expression) => {
self.analyze_expression(&expression.inner, statement_position);
}
Expression::FieldAccess(field_access_expression) => {
let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref();

View File

@ -18,6 +18,7 @@ pub enum Expression {
Block(Node<Box<BlockExpression>>),
Break(Node<Option<Box<Expression>>>),
Call(Node<Box<CallExpression>>),
Dereference(Node<Box<Expression>>),
FieldAccess(Node<Box<FieldAccessExpression>>),
Grouped(Node<Box<Expression>>),
Identifier(Node<Identifier>),
@ -34,6 +35,10 @@ pub enum 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 {
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) => {
let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref();
@ -571,6 +577,7 @@ impl Expression {
Expression::Block(block) => block.position,
Expression::Break(expression_node) => expression_node.position,
Expression::Call(call) => call.position,
Expression::Dereference(expression_node) => expression_node.position,
Expression::FieldAccess(field_access) => field_access.position,
Expression::Grouped(grouped) => grouped.position,
Expression::Identifier(identifier) => identifier.position,
@ -600,6 +607,7 @@ impl Display for Expression {
}
}
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::Grouped(grouped) => write!(f, "({})", grouped.inner),
Expression::Identifier(identifier) => write!(f, "{}", identifier.inner),

View File

@ -369,8 +369,16 @@ impl<'src> Parser<'src> {
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 {
expected: vec![TokenKind::Bang, TokenKind::Minus],
expected: vec![TokenKind::Bang, TokenKind::Minus, TokenKind::Star],
actual: self.current_token.to_owned(),
position: self.current_position,
}),
@ -1157,6 +1165,21 @@ mod tests {
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]
fn character_literal() {
let source = "'a'";

View File

@ -270,7 +270,7 @@ impl<'src> Token<'src> {
}
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 {

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 {
match self {
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>>> {
match self {
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)
.map_err(|error| FunctionCallError::Runtime(Box::new(error)))

View File

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