Compare commits
6 Commits
path-to-no
...
achalmers/
Author | SHA1 | Date | |
---|---|---|---|
09dc17f994 | |||
4fa9eb4a0e | |||
c2d3808f7c | |||
e77c83a7b8 | |||
189099bce5 | |||
628310952f |
1
src/wasm-lib/Cargo.lock
generated
1
src/wasm-lib/Cargo.lock
generated
@ -1864,7 +1864,6 @@ dependencies = [
|
|||||||
"dashmap",
|
"dashmap",
|
||||||
"databake",
|
"databake",
|
||||||
"derive-docs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"derive-docs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"either",
|
|
||||||
"expectorate",
|
"expectorate",
|
||||||
"futures",
|
"futures",
|
||||||
"insta",
|
"insta",
|
||||||
|
@ -17,7 +17,12 @@ pub enum EpBinding {
|
|||||||
/// A KCL value which gets stored in a particular address in KCEP memory.
|
/// A KCL value which gets stored in a particular address in KCEP memory.
|
||||||
Single(Address),
|
Single(Address),
|
||||||
/// A sequence of KCL values, indexed by their position in the sequence.
|
/// A sequence of KCL values, indexed by their position in the sequence.
|
||||||
Sequence(Vec<EpBinding>),
|
Sequence {
|
||||||
|
/// Address where the length of the array is stored.
|
||||||
|
length_at: Address,
|
||||||
|
/// Where is each element in the array bound?
|
||||||
|
elements: Vec<EpBinding>,
|
||||||
|
},
|
||||||
/// A sequence of KCL values, indexed by their identifier.
|
/// A sequence of KCL values, indexed by their identifier.
|
||||||
Map(HashMap<String, EpBinding>),
|
Map(HashMap<String, EpBinding>),
|
||||||
/// Not associated with a KCEP address.
|
/// Not associated with a KCEP address.
|
||||||
@ -38,9 +43,11 @@ impl EpBinding {
|
|||||||
LiteralIdentifier::Literal(litval) => match litval.value {
|
LiteralIdentifier::Literal(litval) => match litval.value {
|
||||||
// Arrays can be indexed by integers.
|
// Arrays can be indexed by integers.
|
||||||
LiteralValue::IInteger(i) => match self {
|
LiteralValue::IInteger(i) => match self {
|
||||||
EpBinding::Sequence(seq) => {
|
EpBinding::Sequence { length_at: _, elements } => {
|
||||||
let i = usize::try_from(i).map_err(|_| CompileError::InvalidIndex(i.to_string()))?;
|
let i = usize::try_from(i).map_err(|_| CompileError::InvalidIndex(i.to_string()))?;
|
||||||
seq.get(i).ok_or(CompileError::IndexOutOfBounds { i, len: seq.len() })
|
elements
|
||||||
|
.get(i)
|
||||||
|
.ok_or(CompileError::IndexOutOfBounds { i, len: elements.len() })
|
||||||
}
|
}
|
||||||
EpBinding::Map(_) => Err(CompileError::CannotIndex),
|
EpBinding::Map(_) => Err(CompileError::CannotIndex),
|
||||||
EpBinding::Single(_) => Err(CompileError::CannotIndex),
|
EpBinding::Single(_) => Err(CompileError::CannotIndex),
|
||||||
@ -50,7 +57,7 @@ impl EpBinding {
|
|||||||
LiteralValue::String(property) => match self {
|
LiteralValue::String(property) => match self {
|
||||||
EpBinding::Single(_) => Err(CompileError::NoProperties),
|
EpBinding::Single(_) => Err(CompileError::NoProperties),
|
||||||
EpBinding::Function(_) => Err(CompileError::NoProperties),
|
EpBinding::Function(_) => Err(CompileError::NoProperties),
|
||||||
EpBinding::Sequence(_) => Err(CompileError::ArrayDoesNotHaveProperties),
|
EpBinding::Sequence { .. } => Err(CompileError::ArrayDoesNotHaveProperties),
|
||||||
EpBinding::Map(map) => map.get(&property).ok_or(CompileError::UndefinedProperty { property }),
|
EpBinding::Map(map) => map.get(&property).ok_or(CompileError::UndefinedProperty { property }),
|
||||||
},
|
},
|
||||||
// It's never valid to index by a fractional number.
|
// It's never valid to index by a fractional number.
|
||||||
|
@ -231,7 +231,7 @@ impl Planner {
|
|||||||
binding: arg,
|
binding: arg,
|
||||||
} = match KclValueGroup::from(argument) {
|
} = match KclValueGroup::from(argument) {
|
||||||
KclValueGroup::Single(value) => self.plan_to_compute_single(ctx, value)?,
|
KclValueGroup::Single(value) => self.plan_to_compute_single(ctx, value)?,
|
||||||
KclValueGroup::ArrayExpression(_) => todo!(),
|
KclValueGroup::ArrayExpression(expr) => self.plan_to_bind_array(ctx, *expr)?,
|
||||||
KclValueGroup::ObjectExpression(_) => todo!(),
|
KclValueGroup::ObjectExpression(_) => todo!(),
|
||||||
};
|
};
|
||||||
acc_instrs.extend(new_instructions);
|
acc_instrs.extend(new_instructions);
|
||||||
@ -411,9 +411,9 @@ impl Planner {
|
|||||||
.declarations
|
.declarations
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.try_fold(Vec::new(), |mut acc, declaration| {
|
.try_fold(Vec::new(), |mut acc, declaration| {
|
||||||
let (instrs, binding) = self.plan_to_bind_one(&mut ctx, declaration.init)?;
|
let EvalPlan { instructions, binding } = self.plan_to_bind_one(&mut ctx, declaration.init)?;
|
||||||
self.binding_scope.bind(declaration.id.name, binding);
|
self.binding_scope.bind(declaration.id.name, binding);
|
||||||
acc.extend(instrs);
|
acc.extend(instructions);
|
||||||
Ok(acc)
|
Ok(acc)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -422,69 +422,14 @@ impl Planner {
|
|||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut Context,
|
ctx: &mut Context,
|
||||||
value_being_bound: ast::types::Value,
|
value_being_bound: ast::types::Value,
|
||||||
) -> Result<(Vec<Instruction>, EpBinding), CompileError> {
|
) -> Result<EvalPlan, CompileError> {
|
||||||
match KclValueGroup::from(value_being_bound) {
|
match KclValueGroup::from(value_being_bound) {
|
||||||
KclValueGroup::Single(init_value) => {
|
KclValueGroup::Single(init_value) => {
|
||||||
// Simple! Just evaluate it, note where the final value will be stored in KCEP memory,
|
// Simple! Just evaluate it, note where the final value will be stored in KCEP memory,
|
||||||
// and bind it to the KCL identifier.
|
// and bind it to the KCL identifier.
|
||||||
let EvalPlan { instructions, binding } = self.plan_to_compute_single(ctx, init_value)?;
|
self.plan_to_compute_single(ctx, init_value)
|
||||||
Ok((instructions, binding))
|
|
||||||
}
|
|
||||||
KclValueGroup::ArrayExpression(expr) => {
|
|
||||||
// First, emit a plan to compute each element of the array.
|
|
||||||
// Collect all the bindings from each element too.
|
|
||||||
let (instructions, bindings) = expr.elements.into_iter().try_fold(
|
|
||||||
(Vec::new(), Vec::new()),
|
|
||||||
|(mut acc_instrs, mut acc_bindings), element| {
|
|
||||||
match KclValueGroup::from(element) {
|
|
||||||
KclValueGroup::Single(value) => {
|
|
||||||
// If this element of the array is a single value, then binding it is
|
|
||||||
// straightforward -- you got a single binding, no need to change anything.
|
|
||||||
let EvalPlan { instructions, binding } = self.plan_to_compute_single(ctx, value)?;
|
|
||||||
acc_instrs.extend(instructions);
|
|
||||||
acc_bindings.push(binding);
|
|
||||||
}
|
|
||||||
KclValueGroup::ArrayExpression(expr) => {
|
|
||||||
// If this element of the array is _itself_ an array, then we need to
|
|
||||||
// emit a plan to calculate each element of this child array.
|
|
||||||
// Then we collect the child array's bindings, and bind them to one
|
|
||||||
// element of the parent array.
|
|
||||||
let binding = expr
|
|
||||||
.elements
|
|
||||||
.into_iter()
|
|
||||||
.try_fold(Vec::new(), |mut seq, child_element| {
|
|
||||||
let (instructions, binding) = self.plan_to_bind_one(ctx, child_element)?;
|
|
||||||
acc_instrs.extend(instructions);
|
|
||||||
seq.push(binding);
|
|
||||||
Ok(seq)
|
|
||||||
})
|
|
||||||
.map(EpBinding::Sequence)?;
|
|
||||||
acc_bindings.push(binding);
|
|
||||||
}
|
|
||||||
KclValueGroup::ObjectExpression(expr) => {
|
|
||||||
// If this element of the array is an object, then we need to
|
|
||||||
// emit a plan to calculate each value of each property of the object.
|
|
||||||
// Then we collect the bindings for each child value, and bind them to one
|
|
||||||
// element of the parent array.
|
|
||||||
let map = HashMap::with_capacity(expr.properties.len());
|
|
||||||
let binding = expr
|
|
||||||
.properties
|
|
||||||
.into_iter()
|
|
||||||
.try_fold(map, |mut map, property| {
|
|
||||||
let (instructions, binding) = self.plan_to_bind_one(ctx, property.value)?;
|
|
||||||
map.insert(property.key.name, binding);
|
|
||||||
acc_instrs.extend(instructions);
|
|
||||||
Ok(map)
|
|
||||||
})
|
|
||||||
.map(EpBinding::Map)?;
|
|
||||||
acc_bindings.push(binding);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok((acc_instrs, acc_bindings))
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
Ok((instructions, EpBinding::Sequence(bindings)))
|
|
||||||
}
|
}
|
||||||
|
KclValueGroup::ArrayExpression(expr) => self.plan_to_bind_array(ctx, *expr),
|
||||||
KclValueGroup::ObjectExpression(expr) => {
|
KclValueGroup::ObjectExpression(expr) => {
|
||||||
// Convert the object to a sequence of key-value pairs.
|
// Convert the object to a sequence of key-value pairs.
|
||||||
let mut kvs = expr.properties.into_iter().map(|prop| (prop.key, prop.value));
|
let mut kvs = expr.properties.into_iter().map(|prop| (prop.key, prop.value));
|
||||||
@ -502,16 +447,22 @@ impl Planner {
|
|||||||
// each element of that array. Collect their bindings, and bind them all
|
// each element of that array. Collect their bindings, and bind them all
|
||||||
// under one property of the parent object.
|
// under one property of the parent object.
|
||||||
let n = expr.elements.len();
|
let n = expr.elements.len();
|
||||||
|
let length_at = self.next_addr.offset_by(1);
|
||||||
|
acc_instrs.push(Instruction::SetPrimitive {
|
||||||
|
address: length_at,
|
||||||
|
value: n.into(),
|
||||||
|
});
|
||||||
let binding = expr
|
let binding = expr
|
||||||
.elements
|
.elements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.try_fold(Vec::with_capacity(n), |mut seq, child_element| {
|
.try_fold(Vec::with_capacity(n), |mut seq, child_element| {
|
||||||
let (instructions, binding) = self.plan_to_bind_one(ctx, child_element)?;
|
let EvalPlan { instructions, binding } =
|
||||||
|
self.plan_to_bind_one(ctx, child_element)?;
|
||||||
seq.push(binding);
|
seq.push(binding);
|
||||||
acc_instrs.extend(instructions);
|
acc_instrs.extend(instructions);
|
||||||
Ok(seq)
|
Ok(seq)
|
||||||
})
|
})
|
||||||
.map(EpBinding::Sequence)?;
|
.map(|elements| EpBinding::Sequence { length_at, elements })?;
|
||||||
acc_bindings.insert(key.name, binding);
|
acc_bindings.insert(key.name, binding);
|
||||||
}
|
}
|
||||||
KclValueGroup::ObjectExpression(expr) => {
|
KclValueGroup::ObjectExpression(expr) => {
|
||||||
@ -524,7 +475,8 @@ impl Planner {
|
|||||||
.properties
|
.properties
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.try_fold(HashMap::with_capacity(n), |mut map, property| {
|
.try_fold(HashMap::with_capacity(n), |mut map, property| {
|
||||||
let (instructions, binding) = self.plan_to_bind_one(ctx, property.value)?;
|
let EvalPlan { instructions, binding } =
|
||||||
|
self.plan_to_bind_one(ctx, property.value)?;
|
||||||
map.insert(property.key.name, binding);
|
map.insert(property.key.name, binding);
|
||||||
acc_instrs.extend(instructions);
|
acc_instrs.extend(instructions);
|
||||||
Ok(map)
|
Ok(map)
|
||||||
@ -536,10 +488,90 @@ impl Planner {
|
|||||||
Ok((acc_instrs, acc_bindings))
|
Ok((acc_instrs, acc_bindings))
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
Ok((instructions, EpBinding::Map(each_property_binding)))
|
Ok(EvalPlan {
|
||||||
|
instructions,
|
||||||
|
binding: EpBinding::Map(each_property_binding),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn plan_to_bind_array(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut Context,
|
||||||
|
expr: ast::types::ArrayExpression,
|
||||||
|
) -> Result<EvalPlan, CompileError> {
|
||||||
|
let length_at = self.next_addr.offset_by(1);
|
||||||
|
let mut instructions = vec![Instruction::SetPrimitive {
|
||||||
|
address: length_at,
|
||||||
|
value: expr.elements.len().into(),
|
||||||
|
}];
|
||||||
|
// First, emit a plan to compute each element of the array.
|
||||||
|
// Collect all the bindings from each element too.
|
||||||
|
let (instrs, bindings) = expr.elements.into_iter().try_fold(
|
||||||
|
(Vec::new(), Vec::new()),
|
||||||
|
|(mut acc_instrs, mut acc_bindings), element| {
|
||||||
|
match KclValueGroup::from(element) {
|
||||||
|
KclValueGroup::Single(value) => {
|
||||||
|
// If this element of the array is a single value, then binding it is
|
||||||
|
// straightforward -- you got a single binding, no need to change anything.
|
||||||
|
let EvalPlan { instructions, binding } = self.plan_to_compute_single(ctx, value)?;
|
||||||
|
acc_instrs.extend(instructions);
|
||||||
|
acc_bindings.push(binding);
|
||||||
|
}
|
||||||
|
KclValueGroup::ArrayExpression(expr) => {
|
||||||
|
// If this element of the array is _itself_ an array, then we need to
|
||||||
|
// emit a plan to calculate each element of this child array.
|
||||||
|
// Then we collect the child array's bindings, and bind them to one
|
||||||
|
// element of the parent array.
|
||||||
|
let length_at = self.next_addr.offset_by(1);
|
||||||
|
acc_instrs.push(Instruction::SetPrimitive {
|
||||||
|
address: length_at,
|
||||||
|
value: expr.elements.len().into(),
|
||||||
|
});
|
||||||
|
let binding = expr
|
||||||
|
.elements
|
||||||
|
.into_iter()
|
||||||
|
.try_fold(Vec::new(), |mut seq, child_element| {
|
||||||
|
let EvalPlan { instructions, binding } = self.plan_to_bind_one(ctx, child_element)?;
|
||||||
|
acc_instrs.extend(instructions);
|
||||||
|
seq.push(binding);
|
||||||
|
Ok(seq)
|
||||||
|
})
|
||||||
|
.map(|elements| EpBinding::Sequence { length_at, elements })?;
|
||||||
|
acc_bindings.push(binding);
|
||||||
|
}
|
||||||
|
KclValueGroup::ObjectExpression(expr) => {
|
||||||
|
// If this element of the array is an object, then we need to
|
||||||
|
// emit a plan to calculate each value of each property of the object.
|
||||||
|
// Then we collect the bindings for each child value, and bind them to one
|
||||||
|
// element of the parent array.
|
||||||
|
let map = HashMap::with_capacity(expr.properties.len());
|
||||||
|
let binding = expr
|
||||||
|
.properties
|
||||||
|
.into_iter()
|
||||||
|
.try_fold(map, |mut map, property| {
|
||||||
|
let EvalPlan { instructions, binding } = self.plan_to_bind_one(ctx, property.value)?;
|
||||||
|
map.insert(property.key.name, binding);
|
||||||
|
acc_instrs.extend(instructions);
|
||||||
|
Ok(map)
|
||||||
|
})
|
||||||
|
.map(EpBinding::Map)?;
|
||||||
|
acc_bindings.push(binding);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok((acc_instrs, acc_bindings))
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
instructions.extend(instrs);
|
||||||
|
Ok(EvalPlan {
|
||||||
|
instructions,
|
||||||
|
binding: EpBinding::Sequence {
|
||||||
|
length_at,
|
||||||
|
elements: bindings,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Every KCL literal value is equivalent to an Execution Plan value, and therefore can be
|
/// Every KCL literal value is equivalent to an Execution Plan value, and therefore can be
|
||||||
|
@ -48,16 +48,22 @@ fn bind_array() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
plan,
|
plan,
|
||||||
vec![
|
vec![
|
||||||
|
// Arrays start with the length.
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO,
|
address: Address::ZERO,
|
||||||
|
value: 3usize.into(),
|
||||||
|
},
|
||||||
|
// Then the elements follow.
|
||||||
|
Instruction::SetPrimitive {
|
||||||
|
address: Address::ZERO + 1,
|
||||||
value: 44i64.into(),
|
value: 44i64.into(),
|
||||||
},
|
},
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO.offset(1),
|
address: Address::ZERO + 2,
|
||||||
value: 55i64.into(),
|
value: 55i64.into(),
|
||||||
},
|
},
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO.offset(2),
|
address: Address::ZERO + 3,
|
||||||
value: "sixty-six".to_owned().into(),
|
value: "sixty-six".to_owned().into(),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -73,14 +79,22 @@ fn bind_nested_array() {
|
|||||||
vec![
|
vec![
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO,
|
address: Address::ZERO,
|
||||||
|
value: 2usize.into(),
|
||||||
|
},
|
||||||
|
Instruction::SetPrimitive {
|
||||||
|
address: Address::ZERO + 1,
|
||||||
value: 44i64.into(),
|
value: 44i64.into(),
|
||||||
},
|
},
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO.offset(1),
|
address: Address::ZERO + 2,
|
||||||
|
value: 2usize.into(),
|
||||||
|
},
|
||||||
|
Instruction::SetPrimitive {
|
||||||
|
address: Address::ZERO + 3,
|
||||||
value: 55i64.into(),
|
value: 55i64.into(),
|
||||||
},
|
},
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO.offset(2),
|
address: Address::ZERO + 4,
|
||||||
value: "sixty-six".to_owned().into(),
|
value: "sixty-six".to_owned().into(),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -96,14 +110,18 @@ fn bind_arrays_with_objects_elements() {
|
|||||||
vec![
|
vec![
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO,
|
address: Address::ZERO,
|
||||||
|
value: 2usize.into()
|
||||||
|
},
|
||||||
|
Instruction::SetPrimitive {
|
||||||
|
address: Address::ZERO + 1,
|
||||||
value: 44i64.into(),
|
value: 44i64.into(),
|
||||||
},
|
},
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO.offset(1),
|
address: Address::ZERO + 2,
|
||||||
value: 55i64.into(),
|
value: 55i64.into(),
|
||||||
},
|
},
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO.offset(2),
|
address: Address::ZERO + 3,
|
||||||
value: "sixty-six".to_owned().into(),
|
value: "sixty-six".to_owned().into(),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -187,6 +205,45 @@ fn use_native_function_add() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn arrays_as_parameters() {
|
||||||
|
let program = "fn identity = (x) => { return x }
|
||||||
|
let array = identity([1,2,3])";
|
||||||
|
let (plan, scope) = must_plan(program);
|
||||||
|
let expected_plan = vec![
|
||||||
|
// Array length
|
||||||
|
Instruction::SetPrimitive {
|
||||||
|
address: Address::ZERO,
|
||||||
|
value: 3usize.into(),
|
||||||
|
},
|
||||||
|
// Array contents
|
||||||
|
Instruction::SetPrimitive {
|
||||||
|
address: Address::ZERO + 1,
|
||||||
|
value: 1i64.into(),
|
||||||
|
},
|
||||||
|
Instruction::SetPrimitive {
|
||||||
|
address: Address::ZERO + 2,
|
||||||
|
value: 2i64.into(),
|
||||||
|
},
|
||||||
|
Instruction::SetPrimitive {
|
||||||
|
address: Address::ZERO + 3,
|
||||||
|
value: 3i64.into(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
assert_eq!(plan, expected_plan);
|
||||||
|
assert_eq!(
|
||||||
|
scope.get("array").unwrap(),
|
||||||
|
&EpBinding::Sequence {
|
||||||
|
length_at: Address::ZERO,
|
||||||
|
elements: vec![
|
||||||
|
EpBinding::Single(Address::ZERO + 1),
|
||||||
|
EpBinding::Single(Address::ZERO + 2),
|
||||||
|
EpBinding::Single(Address::ZERO + 3),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn use_native_function_id() {
|
fn use_native_function_id() {
|
||||||
let program = "let x = id(2)";
|
let program = "let x = id(2)";
|
||||||
@ -265,7 +322,7 @@ fn member_expressions_array() {
|
|||||||
let (_plan, scope) = must_plan(program);
|
let (_plan, scope) = must_plan(program);
|
||||||
match scope.get("first").unwrap() {
|
match scope.get("first").unwrap() {
|
||||||
EpBinding::Single(addr) => {
|
EpBinding::Single(addr) => {
|
||||||
assert_eq!(*addr, Address::ZERO);
|
assert_eq!(*addr, Address::ZERO + 2);
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
panic!("expected 'number' bound to 0x0 but it was bound to {other:?}");
|
panic!("expected 'number' bound to 0x0 but it was bound to {other:?}");
|
||||||
@ -273,7 +330,7 @@ fn member_expressions_array() {
|
|||||||
}
|
}
|
||||||
match scope.get("last").unwrap() {
|
match scope.get("last").unwrap() {
|
||||||
EpBinding::Single(addr) => {
|
EpBinding::Single(addr) => {
|
||||||
assert_eq!(*addr, Address::ZERO + 3);
|
assert_eq!(*addr, Address::ZERO + 6);
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
panic!("expected 'number' bound to 0x3 but it was bound to {other:?}");
|
panic!("expected 'number' bound to 0x3 but it was bound to {other:?}");
|
||||||
@ -682,14 +739,11 @@ fn store_object() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
bindings.get("x0").unwrap(),
|
bindings.get("x0").unwrap(),
|
||||||
&EpBinding::Map(HashMap::from([
|
&EpBinding::Map(HashMap::from([
|
||||||
("a".to_owned(), EpBinding::Single(Address::ZERO),),
|
("a".to_owned(), EpBinding::Single(Address::ZERO)),
|
||||||
("b".to_owned(), EpBinding::Single(Address::ZERO.offset(1))),
|
("b".to_owned(), EpBinding::Single(Address::ZERO + 1)),
|
||||||
(
|
(
|
||||||
"c".to_owned(),
|
"c".to_owned(),
|
||||||
EpBinding::Map(HashMap::from([(
|
EpBinding::Map(HashMap::from([("d".to_owned(), EpBinding::Single(Address::ZERO + 2))]))
|
||||||
"d".to_owned(),
|
|
||||||
EpBinding::Single(Address::ZERO.offset(2))
|
|
||||||
)]))
|
|
||||||
),
|
),
|
||||||
]))
|
]))
|
||||||
)
|
)
|
||||||
@ -697,7 +751,7 @@ fn store_object() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn store_object_with_array_property() {
|
fn store_object_with_array_property() {
|
||||||
let program = "const x0 = {a: 1, b: [2, 3]}";
|
let program = "const x0 = {a: 1, b: [22, 33]}";
|
||||||
let (actual, bindings) = must_plan(program);
|
let (actual, bindings) = must_plan(program);
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
@ -705,12 +759,16 @@ fn store_object_with_array_property() {
|
|||||||
value: 1i64.into(),
|
value: 1i64.into(),
|
||||||
},
|
},
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO.offset(1),
|
address: Address::ZERO + 1,
|
||||||
value: 2i64.into(),
|
value: 2usize.into(),
|
||||||
},
|
},
|
||||||
Instruction::SetPrimitive {
|
Instruction::SetPrimitive {
|
||||||
address: Address::ZERO.offset(2),
|
address: Address::ZERO + 2,
|
||||||
value: 3i64.into(),
|
value: 22i64.into(),
|
||||||
|
},
|
||||||
|
Instruction::SetPrimitive {
|
||||||
|
address: Address::ZERO + 3,
|
||||||
|
value: 33i64.into(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
@ -721,10 +779,13 @@ fn store_object_with_array_property() {
|
|||||||
("a".to_owned(), EpBinding::Single(Address::ZERO),),
|
("a".to_owned(), EpBinding::Single(Address::ZERO),),
|
||||||
(
|
(
|
||||||
"b".to_owned(),
|
"b".to_owned(),
|
||||||
EpBinding::Sequence(vec![
|
EpBinding::Sequence {
|
||||||
EpBinding::Single(Address::ZERO.offset(1)),
|
length_at: Address::ZERO.offset(1),
|
||||||
EpBinding::Single(Address::ZERO.offset(2)),
|
elements: vec![
|
||||||
])
|
EpBinding::Single(Address::ZERO.offset(2)),
|
||||||
|
EpBinding::Single(Address::ZERO.offset(3)),
|
||||||
|
]
|
||||||
|
}
|
||||||
),
|
),
|
||||||
]))
|
]))
|
||||||
)
|
)
|
||||||
|
@ -32,7 +32,6 @@ thiserror = "1.0.50"
|
|||||||
ts-rs = { version = "7", features = ["uuid-impl"] }
|
ts-rs = { version = "7", features = ["uuid-impl"] }
|
||||||
uuid = { version = "1.6.1", features = ["v4", "js", "serde"] }
|
uuid = { version = "1.6.1", features = ["v4", "js", "serde"] }
|
||||||
winnow = "0.5.18"
|
winnow = "0.5.18"
|
||||||
either = "1.6.1"
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
js-sys = { version = "0.3.65" }
|
js-sys = { version = "0.3.65" }
|
||||||
|
@ -19,7 +19,6 @@ use crate::{
|
|||||||
parser::PIPE_OPERATOR,
|
parser::PIPE_OPERATOR,
|
||||||
std::{kcl_stdlib::KclStdLibFn, FunctionKind},
|
std::{kcl_stdlib::KclStdLibFn, FunctionKind},
|
||||||
};
|
};
|
||||||
use crate::executor::PathToNode;
|
|
||||||
|
|
||||||
mod literal_value;
|
mod literal_value;
|
||||||
mod none;
|
mod none;
|
||||||
@ -1434,7 +1433,6 @@ impl From<Literal> for MemoryItem {
|
|||||||
value: JValue::from(literal.value.clone()),
|
value: JValue::from(literal.value.clone()),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: literal.into(),
|
source_range: literal.into(),
|
||||||
path_to_node: vec![],
|
|
||||||
}],
|
}],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1446,7 +1444,6 @@ impl From<&Box<Literal>> for MemoryItem {
|
|||||||
value: JValue::from(literal.value.clone()),
|
value: JValue::from(literal.value.clone()),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: literal.into(),
|
source_range: literal.into(),
|
||||||
path_to_node: vec![],
|
|
||||||
}],
|
}],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1644,7 +1641,7 @@ impl ArrayExpression {
|
|||||||
Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await?,
|
Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await?,
|
||||||
Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, ctx).await?,
|
Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, ctx).await?,
|
||||||
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, ctx).await?,
|
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, ctx).await?,
|
||||||
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, ctx, vec![]).await?,
|
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, ctx).await?,
|
||||||
Value::PipeSubstitution(pipe_substitution) => {
|
Value::PipeSubstitution(pipe_substitution) => {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution),
|
message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution),
|
||||||
@ -1668,7 +1665,6 @@ impl ArrayExpression {
|
|||||||
value: results.into(),
|
value: results.into(),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.into(),
|
source_range: self.into(),
|
||||||
path_to_node: vec![],
|
|
||||||
}],
|
}],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -1798,7 +1794,7 @@ impl ObjectExpression {
|
|||||||
Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await?,
|
Value::UnaryExpression(unary_expression) => unary_expression.get_result(memory, pipe_info, ctx).await?,
|
||||||
Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, ctx).await?,
|
Value::ObjectExpression(object_expression) => object_expression.execute(memory, pipe_info, ctx).await?,
|
||||||
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, ctx).await?,
|
Value::ArrayExpression(array_expression) => array_expression.execute(memory, pipe_info, ctx).await?,
|
||||||
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, ctx, vec![]).await?,
|
Value::PipeExpression(pipe_expression) => pipe_expression.get_result(memory, pipe_info, ctx).await?,
|
||||||
Value::PipeSubstitution(pipe_substitution) => {
|
Value::PipeSubstitution(pipe_substitution) => {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution),
|
message: format!("PipeSubstitution not implemented here: {:?}", pipe_substitution),
|
||||||
@ -1826,7 +1822,6 @@ impl ObjectExpression {
|
|||||||
value: object.into(),
|
value: object.into(),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.into(),
|
source_range: self.into(),
|
||||||
path_to_node: vec![],
|
|
||||||
}],
|
}],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -2036,7 +2031,6 @@ impl MemberExpression {
|
|||||||
value: value.clone(),
|
value: value.clone(),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.into(),
|
source_range: self.into(),
|
||||||
path_to_node: vec![],
|
|
||||||
}],
|
}],
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
@ -2093,7 +2087,6 @@ impl MemberExpression {
|
|||||||
value: value.clone(),
|
value: value.clone(),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.into(),
|
source_range: self.into(),
|
||||||
path_to_node: vec![],
|
|
||||||
}],
|
}],
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
@ -2258,7 +2251,6 @@ impl BinaryExpression {
|
|||||||
value,
|
value,
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.into(),
|
source_range: self.into(),
|
||||||
path_to_node: vec![],
|
|
||||||
}],
|
}],
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -2280,7 +2272,6 @@ impl BinaryExpression {
|
|||||||
value,
|
value,
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.into(),
|
source_range: self.into(),
|
||||||
path_to_node: vec![],
|
|
||||||
}],
|
}],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -2444,7 +2435,6 @@ impl UnaryExpression {
|
|||||||
value: (-(num)).into(),
|
value: (-(num)).into(),
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.into(),
|
source_range: self.into(),
|
||||||
path_to_node: vec![],
|
|
||||||
}],
|
}],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -2574,12 +2564,11 @@ impl PipeExpression {
|
|||||||
memory: &mut ProgramMemory,
|
memory: &mut ProgramMemory,
|
||||||
pipe_info: &mut PipeInfo,
|
pipe_info: &mut PipeInfo,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
path_to_node: PathToNode,
|
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
// Reset the previous results.
|
// Reset the previous results.
|
||||||
pipe_info.previous_results = vec![];
|
pipe_info.previous_results = vec![];
|
||||||
pipe_info.index = 0;
|
pipe_info.index = 0;
|
||||||
execute_pipe_body(memory, &self.body, pipe_info, self.into(), ctx, path_to_node).await
|
execute_pipe_body(memory, &self.body, pipe_info, self.into(), ctx).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rename all identifiers that have the old name to the new given name.
|
/// Rename all identifiers that have the old name to the new given name.
|
||||||
@ -2597,8 +2586,6 @@ async fn execute_pipe_body(
|
|||||||
pipe_info: &mut PipeInfo,
|
pipe_info: &mut PipeInfo,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
ctx: &ExecutorContext,
|
ctx: &ExecutorContext,
|
||||||
path_to_node: PathToNode,
|
|
||||||
|
|
||||||
) -> Result<MemoryItem, KclError> {
|
) -> Result<MemoryItem, KclError> {
|
||||||
if pipe_info.index == body.len() {
|
if pipe_info.index == body.len() {
|
||||||
pipe_info.is_in_pipe = false;
|
pipe_info.is_in_pipe = false;
|
||||||
|
@ -11,7 +11,6 @@ use schemars::JsonSchema;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value as JValue;
|
use serde_json::Value as JValue;
|
||||||
use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
|
use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
|
||||||
// use either::Either;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::types::{BodyItem, FunctionExpression, KclNone, Value},
|
ast::types::{BodyItem, FunctionExpression, KclNone, Value},
|
||||||
@ -633,18 +632,6 @@ impl From<Point3d> for kittycad::types::Point3D {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// number or string
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
||||||
#[ts(export)]
|
|
||||||
pub enum NumberOrString {
|
|
||||||
Num(i32), // assuming 'number' is equivalent to a 32-bit integer
|
|
||||||
Str(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PathToNode
|
|
||||||
pub type PathToNode = Vec<(NumberOrString, String)>;
|
|
||||||
|
|
||||||
|
|
||||||
/// Metadata.
|
/// Metadata.
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
@ -652,16 +639,11 @@ pub type PathToNode = Vec<(NumberOrString, String)>;
|
|||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
/// The source range.
|
/// The source range.
|
||||||
pub source_range: SourceRange,
|
pub source_range: SourceRange,
|
||||||
/// The path to node for this memory Item
|
|
||||||
pub path_to_node: PathToNode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SourceRange> for Metadata {
|
impl From<SourceRange> for Metadata {
|
||||||
fn from(source_range: SourceRange) -> Self {
|
fn from(source_range: SourceRange) -> Self {
|
||||||
Self {
|
Self { source_range }
|
||||||
source_range,
|
|
||||||
path_to_node: Vec::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -847,17 +829,12 @@ pub async fn execute(
|
|||||||
) -> Result<ProgramMemory, KclError> {
|
) -> Result<ProgramMemory, KclError> {
|
||||||
let mut pipe_info = PipeInfo::default();
|
let mut pipe_info = PipeInfo::default();
|
||||||
|
|
||||||
// let path_to_Node: PathToNode = vec![("body".to_string(), "".to_string())];
|
|
||||||
let path_to_node: PathToNode = vec![(NumberOrString::Str("body".to_string()), "".to_string())];
|
|
||||||
|
|
||||||
// Iterate over the body of the program.
|
// Iterate over the body of the program.
|
||||||
for (index, statement) in program.body.iter().enumerate() {
|
for statement in &program.body {
|
||||||
let mut with_body_path_to_node = path_to_node.clone();
|
|
||||||
with_body_path_to_node.push((NumberOrString::Num(index as i32), "index".to_string()));
|
|
||||||
match statement {
|
match statement {
|
||||||
BodyItem::ExpressionStatement(expression_statement) => {
|
BodyItem::ExpressionStatement(expression_statement) => {
|
||||||
if let Value::PipeExpression(pipe_expr) = &expression_statement.expression {
|
if let Value::PipeExpression(pipe_expr) = &expression_statement.expression {
|
||||||
pipe_expr.get_result(memory, &mut pipe_info, ctx, with_body_path_to_node).await?;
|
pipe_expr.get_result(memory, &mut pipe_info, ctx).await?;
|
||||||
} else if let Value::CallExpression(call_expr) = &expression_statement.expression {
|
} else if let Value::CallExpression(call_expr) = &expression_statement.expression {
|
||||||
let fn_name = call_expr.callee.name.to_string();
|
let fn_name = call_expr.callee.name.to_string();
|
||||||
let mut args: Vec<MemoryItem> = Vec::new();
|
let mut args: Vec<MemoryItem> = Vec::new();
|
||||||
@ -928,15 +905,10 @@ pub async fn execute(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BodyItem::VariableDeclaration(variable_declaration) => {
|
BodyItem::VariableDeclaration(variable_declaration) => {
|
||||||
|
for declaration in &variable_declaration.declarations {
|
||||||
for (index, declaration) in variable_declaration.declarations.iter().enumerate() {
|
|
||||||
let var_name = declaration.id.name.to_string();
|
let var_name = declaration.id.name.to_string();
|
||||||
let source_range: SourceRange = declaration.init.clone().into();
|
let source_range: SourceRange = declaration.init.clone().into();
|
||||||
let mut with_dec_path_to_node = with_body_path_to_node.clone();
|
let metadata = Metadata { source_range };
|
||||||
with_dec_path_to_node.push((NumberOrString::Str("declarations".to_string()), "VariableDeclaration".to_string()));
|
|
||||||
with_dec_path_to_node.push((NumberOrString::Num(index as i32), "index".to_string()));
|
|
||||||
with_dec_path_to_node.push((NumberOrString::Str("init".to_string()), "".to_string()));
|
|
||||||
let metadata = Metadata { source_range, path_to_node: with_dec_path_to_node.clone() };
|
|
||||||
|
|
||||||
match &declaration.init {
|
match &declaration.init {
|
||||||
Value::None(none) => {
|
Value::None(none) => {
|
||||||
@ -991,7 +963,7 @@ pub async fn execute(
|
|||||||
memory.add(&var_name, result, source_range)?;
|
memory.add(&var_name, result, source_range)?;
|
||||||
}
|
}
|
||||||
Value::PipeExpression(pipe_expression) => {
|
Value::PipeExpression(pipe_expression) => {
|
||||||
let result = pipe_expression.get_result(memory, &mut pipe_info, ctx, with_dec_path_to_node).await?;
|
let result = pipe_expression.get_result(memory, &mut pipe_info, ctx).await?;
|
||||||
memory.add(&var_name, result, source_range)?;
|
memory.add(&var_name, result, source_range)?;
|
||||||
}
|
}
|
||||||
Value::PipeSubstitution(pipe_substitution) => {
|
Value::PipeSubstitution(pipe_substitution) => {
|
||||||
@ -1055,7 +1027,7 @@ pub async fn execute(
|
|||||||
memory.return_ = Some(ProgramReturn::Value(result));
|
memory.return_ = Some(ProgramReturn::Value(result));
|
||||||
}
|
}
|
||||||
Value::PipeExpression(pipe_expr) => {
|
Value::PipeExpression(pipe_expr) => {
|
||||||
let result = pipe_expr.get_result(memory, &mut pipe_info, ctx, with_body_path_to_node).await?;
|
let result = pipe_expr.get_result(memory, &mut pipe_info, ctx).await?;
|
||||||
memory.return_ = Some(ProgramReturn::Value(result));
|
memory.return_ = Some(ProgramReturn::Value(result));
|
||||||
}
|
}
|
||||||
Value::PipeSubstitution(_) => {}
|
Value::PipeSubstitution(_) => {}
|
||||||
|
@ -190,7 +190,6 @@ impl Args {
|
|||||||
value: j,
|
value: j,
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: self.source_range,
|
source_range: self.source_range,
|
||||||
path_to_node: Vec::new()
|
|
||||||
}],
|
}],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user