Add defereference expressions
This commit is contained in:
parent
5f733ba1dd
commit
b02e5244f2
@ -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();
|
||||
|
@ -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),
|
||||
|
@ -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'";
|
||||
|
@ -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 {
|
||||
|
@ -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)))
|
||||
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user