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);
|
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();
|
||||||
|
@ -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),
|
||||||
|
@ -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'";
|
||||||
|
@ -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 {
|
||||||
|
@ -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)))
|
||||||
|
@ -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]
|
||||||
|
Loading…
Reference in New Issue
Block a user