diff --git a/src/protocol/eval.rs b/src/protocol/eval.rs index e340a246338a62ca1eb9f20d6cd10f3fe3d6bd93..ac3b73001c34fa0c2860934a9ae9f754d21b7ade 100644 --- a/src/protocol/eval.rs +++ b/src/protocol/eval.rs @@ -93,7 +93,7 @@ impl Value { match index { Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => { let index = i64::from(index); - if index < 0 || index > MESSAGE_MAX_LENGTH { + if index < 0 || index >= MESSAGE_MAX_LENGTH { // It is inconsistent to update out of bounds return None; } @@ -145,6 +145,82 @@ impl Value { _ => unreachable!(), } } + fn get(&self, index: &Value) -> Option { + // The index must be of integer type, and non-negative + let the_index: usize; + match index { + Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => { + let index = i64::from(index); + if index < 0 || index >= MESSAGE_MAX_LENGTH { + // It is inconsistent to update out of bounds + return None; + } + the_index = index.try_into().unwrap(); + } + _ => unreachable!(), + } + // The subject must be either a message or an array + match self { + Value::Message(MessageValue(None)) => { + // It is inconsistent to read from the null message + None + } + Value::Message(MessageValue(Some(buffer))) => { + if let Some(slot) = buffer.get(the_index) { + Some(Value::Short(ShortValue((*slot).try_into().unwrap()))) + } else { + // It is inconsistent to update out of bounds + None + } + } + Value::InputArray(_) => todo!(), + Value::OutputArray(_) => todo!(), + Value::MessageArray(_) => todo!(), + Value::BooleanArray(_) => todo!(), + Value::ByteArray(_) => todo!(), + Value::ShortArray(_) => todo!(), + Value::IntArray(_) => todo!(), + Value::LongArray(_) => todo!(), + _ => unreachable!(), + } + } + fn length(&self) -> Option { + // The subject must be either a message or an array + match self { + Value::Message(MessageValue(None)) => { + // It is inconsistent to get length from the null message + None + } + Value::Message(MessageValue(Some(buffer))) => { + Some(Value::Int(IntValue((buffer.len()).try_into().unwrap()))) + } + Value::InputArray(InputArrayValue(vec)) => { + Some(Value::Int(IntValue((vec.len()).try_into().unwrap()))) + } + Value::OutputArray(OutputArrayValue(vec)) => { + Some(Value::Int(IntValue((vec.len()).try_into().unwrap()))) + } + Value::MessageArray(MessageArrayValue(vec)) => { + Some(Value::Int(IntValue((vec.len()).try_into().unwrap()))) + } + Value::BooleanArray(BooleanArrayValue(vec)) => { + Some(Value::Int(IntValue((vec.len()).try_into().unwrap()))) + } + Value::ByteArray(ByteArrayValue(vec)) => { + Some(Value::Int(IntValue((vec.len()).try_into().unwrap()))) + } + Value::ShortArray(ShortArrayValue(vec)) => { + Some(Value::Int(IntValue((vec.len()).try_into().unwrap()))) + } + Value::IntArray(IntArrayValue(vec)) => { + Some(Value::Int(IntValue((vec.len()).try_into().unwrap()))) + } + Value::LongArray(LongArrayValue(vec)) => { + Some(Value::Int(IntValue((vec.len()).try_into().unwrap()))) + } + _ => unreachable!(), + } + } fn plus(&self, other: &Value) -> Value { // TODO: do a match on the value directly assert!(!self.exact_type().array); @@ -1371,13 +1447,45 @@ impl Store { _ => unimplemented!("{:?}", h[lexpr]), } } - fn get(&mut self, h: &Heap, rexpr: ExpressionId) -> EvalResult { + fn get(&mut self, h: &Heap, ctx: &mut EvalContext, rexpr: ExpressionId) -> EvalResult { match &h[rexpr] { Expression::Variable(var) => { let var = var.declaration.unwrap(); let value = self.map.get(&var).expect(&format!("Uninitialized variable {:?}", h[h[var].identifier()])); Ok(value.clone()) } + Expression::Indexing(indexing) => { + // Evaluate index expression, which must be some integral type + let index = self.eval(h, ctx, indexing.index)?; + // Reference to subject + let subject; + match &h[indexing.subject] { + Expression::Variable(var) => { + let var = var.declaration.unwrap(); + subject = self.map.get(&var).unwrap(); + } + _ => unreachable!(), + } + match subject.get(&index) { + Some(value) => Ok(value), + None => Err(EvalContinuation::Inconsistent), + } + } + Expression::Select(selecting) => { + // Reference to subject + let subject; + match &h[selecting.subject] { + Expression::Variable(var) => { + let var = var.declaration.unwrap(); + subject = self.map.get(&var).unwrap(); + } + _ => unreachable!(), + } + match subject.length() { + Some(value) => Ok(value), + None => Err(EvalContinuation::Inconsistent), + } + } _ => unimplemented!("{:?}", h[rexpr]), } } @@ -1387,15 +1495,15 @@ impl Store { let value = self.eval(h, ctx, expr.right)?; match expr.operation { AssignmentOperator::Set => { - self.update(h, ctx, expr.left, value.clone()); + self.update(h, ctx, expr.left, value.clone())?; } AssignmentOperator::Added => { - let old = self.get(h, expr.left)?; - self.update(h, ctx, expr.left, old.plus(&value)); + let old = self.get(h, ctx, expr.left)?; + self.update(h, ctx, expr.left, old.plus(&value))?; } AssignmentOperator::Subtracted => { - let old = self.get(h, expr.left)?; - self.update(h, ctx, expr.left, old.minus(&value)); + let old = self.get(h, ctx, expr.left)?; + self.update(h, ctx, expr.left, old.minus(&value))?; } _ => unimplemented!("{:?}", expr), } @@ -1427,27 +1535,33 @@ impl Store { let mut value = self.eval(h, ctx, expr.expression)?; match expr.operation { UnaryOperation::PostIncrement => { - self.update(h, ctx, expr.expression, value.plus(&ONE)); + self.update(h, ctx, expr.expression, value.plus(&ONE))?; } UnaryOperation::PreIncrement => { value = value.plus(&ONE); - self.update(h, ctx, expr.expression, value.clone()); + self.update(h, ctx, expr.expression, value.clone())?; } UnaryOperation::PostDecrement => { - self.update(h, ctx, expr.expression, value.minus(&ONE)); + self.update(h, ctx, expr.expression, value.minus(&ONE))?; } UnaryOperation::PreDecrement => { value = value.minus(&ONE); - self.update(h, ctx, expr.expression, value.clone()); + self.update(h, ctx, expr.expression, value.clone())?; } _ => unimplemented!(), } Ok(value) } - Expression::Indexing(expr) => self.get(h, expr.this.upcast()), + Expression::Indexing(expr) => self.get(h, ctx, expr.this.upcast()), Expression::Slicing(expr) => unimplemented!(), - Expression::Select(expr) => self.get(h, expr.this.upcast()), - Expression::Array(expr) => unimplemented!(), + Expression::Select(expr) => self.get(h, ctx, expr.this.upcast()), + Expression::Array(expr) => { + let mut elements = Vec::new(); + for &elem in expr.elements.iter() { + elements.push(self.eval(h, ctx, elem)?); + } + todo!() + }, Expression::Constant(expr) => Ok(Value::from_constant(&expr.value)), Expression::Call(expr) => match expr.method { Method::Create => { @@ -1473,7 +1587,7 @@ impl Store { } Method::Symbolic(symbol) => unimplemented!(), }, - Expression::Variable(expr) => self.get(h, expr.this.upcast()), + Expression::Variable(expr) => self.get(h, ctx, expr.this.upcast()), } } } diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 25731b736c26558cbd8c6e3c780fa77eb0999aab..295e8d3a8ecc052605dd2e49ef359797e2eac60f 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -10,7 +10,6 @@ use crate::protocol::ast::*; use crate::protocol::eval::*; use crate::protocol::inputsource::*; use crate::protocol::parser::*; -use std::hint::unreachable_unchecked; pub struct ProtocolDescriptionImpl { heap: Heap, @@ -125,16 +124,15 @@ impl ComponentState for ComponentStateImpl { // Look up definition (TODO for now, assume it is a definition) let h = &pd.heap; let def = h[decl].as_defined().definition; - println!("Create component: {}", String::from_utf8_lossy(h[h[def].identifier()].ident())); let init_state = ComponentStateImpl { prompt: Prompt::new(h, def, &args) }; context.new_component(&args, init_state); // Continue stepping continue; } // Outside synchronous blocks, no fires/get/put happens - EvalContinuation::BlockFires(val) => unreachable!(), - EvalContinuation::BlockGet(val) => unreachable!(), - EvalContinuation::Put(port, msg) => unreachable!(), + EvalContinuation::BlockFires(_) => unreachable!(), + EvalContinuation::BlockGet(_) => unreachable!(), + EvalContinuation::Put(_, _) => unreachable!(), }, } } diff --git a/src/protocol/parser.rs b/src/protocol/parser.rs index c1fc2d7946e1821a4871a8094483d2f01fd11c40..da7f78c16934df9f13e2bce24528a3e1459a8502 100644 --- a/src/protocol/parser.rs +++ b/src/protocol/parser.rs @@ -1626,14 +1626,11 @@ impl Visitor for IndexableExpressions { h: &mut Heap, expr: IndexingExpressionId, ) -> VisitorResult { - if self.indexable { - self.error(h[expr].position) - } else { - self.indexable = true; - self.visit_expression(h, h[expr].subject)?; - self.indexable = false; - self.visit_expression(h, h[expr].index) - } + let old = self.indexable; + self.indexable = false; + self.visit_expression(h, h[expr].subject)?; + self.indexable = old; + self.visit_expression(h, h[expr].index) } fn visit_slicing_expression( &mut self, diff --git a/testdata/eval/positive/7.pdl b/testdata/eval/positive/7.pdl new file mode 100644 index 0000000000000000000000000000000000000000..8c6d75754b0b75237b8893b9e1ef7bdf02280cdb --- /dev/null +++ b/testdata/eval/positive/7.pdl @@ -0,0 +1,13 @@ +#version 100 + +composite main() {} + +int test() { + msg x = create(5); + x[0] = 1; + x[1] = 2; + x[2] = 3; + x[3] = 4; + x[4] = 5; + return x[x[x[x[x[0]]]]]; +} \ No newline at end of file diff --git a/testdata/eval/positive/7.txt b/testdata/eval/positive/7.txt new file mode 100644 index 0000000000000000000000000000000000000000..7813681f5b41c028345ca62a2be376bae70b7f61 --- /dev/null +++ b/testdata/eval/positive/7.txt @@ -0,0 +1 @@ +5 \ No newline at end of file diff --git a/testdata/eval/positive/8.pdl b/testdata/eval/positive/8.pdl new file mode 100644 index 0000000000000000000000000000000000000000..efb4940a9dc9ef453e9b113866b3216af2ae0d6a --- /dev/null +++ b/testdata/eval/positive/8.pdl @@ -0,0 +1,12 @@ +#version 100 + +composite main() {} + +int test() { + msg x = create(4); + x[0] = 1; + x[1] = 2; + x[2] = 3; + x[3] = 4; + return x.length; +} \ No newline at end of file diff --git a/testdata/eval/positive/8.txt b/testdata/eval/positive/8.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf0d87ab1b2b0ec1a11a3973d2845b42413d9767 --- /dev/null +++ b/testdata/eval/positive/8.txt @@ -0,0 +1 @@ +4 \ No newline at end of file diff --git a/testdata/eval/positive/9.pdl b/testdata/eval/positive/9.pdl new file mode 100644 index 0000000000000000000000000000000000000000..901050c0282ac503ed5d21307883be10f1e8c1a6 --- /dev/null +++ b/testdata/eval/positive/9.pdl @@ -0,0 +1,12 @@ +#version 100 + +composite main() {} + +int test() { + msg[] x = {create(4)}; + x[0][0] = 0; + x[x[0][0]][1] = 1; + x[x[0][0]][x[0][1]+x[0][1]] = 2; + x[x[0][0]][3] = 3; + return x.length + x[0].length + x[x[0][0]][x[0][3]]; +} \ No newline at end of file diff --git a/testdata/eval/positive/9.txt b/testdata/eval/positive/9.txt new file mode 100644 index 0000000000000000000000000000000000000000..301160a93062df23030a69f4b5e4d9bf71866ee9 --- /dev/null +++ b/testdata/eval/positive/9.txt @@ -0,0 +1 @@ +8 \ No newline at end of file