Merge remote-tracking branch 'origin' into paultag/import
This commit is contained in:
@ -8,11 +8,11 @@ use crate::{
|
||||
execution::{
|
||||
annotations,
|
||||
cad_op::{OpArg, OpKclValue, Operation},
|
||||
kcl_value::{FunctionSource, NumericType, PrimitiveType, RuntimeType},
|
||||
kcl_value::{FunctionSource, NumericType, RuntimeType},
|
||||
memory,
|
||||
state::ModuleState,
|
||||
BodyType, EnvironmentRef, ExecState, ExecutorContext, KclValue, Metadata, Plane, PlaneType, Point3d,
|
||||
TagEngineInfo, TagIdentifier,
|
||||
BodyType, EnvironmentRef, ExecState, ExecutorContext, KclValue, Metadata, PlaneType, TagEngineInfo,
|
||||
TagIdentifier,
|
||||
},
|
||||
modules::{ModuleId, ModulePath, ModuleRepr},
|
||||
parsing::ast::types::{
|
||||
@ -23,7 +23,7 @@ use crate::{
|
||||
},
|
||||
source_range::SourceRange,
|
||||
std::{
|
||||
args::{Arg, FromKclValue, KwArgs},
|
||||
args::{Arg, KwArgs},
|
||||
FunctionKind,
|
||||
},
|
||||
CompilationError,
|
||||
@ -55,10 +55,9 @@ impl ExecutorContext {
|
||||
for annotation in annotations {
|
||||
if annotation.name() == Some(annotations::SETTINGS) {
|
||||
if matches!(body_type, BodyType::Root) {
|
||||
let old_units = exec_state.length_unit();
|
||||
exec_state.mod_local.settings.update_from_annotation(annotation)?;
|
||||
let new_units = exec_state.length_unit();
|
||||
if !self.engine.execution_kind().await.is_isolated() && old_units != new_units {
|
||||
if !self.engine.execution_kind().await.is_isolated() {
|
||||
self.engine
|
||||
.set_units(new_units.into(), annotation.as_source_range())
|
||||
.await?;
|
||||
@ -94,6 +93,7 @@ impl ExecutorContext {
|
||||
exec_state: &mut ExecState,
|
||||
exec_kind: ExecutionKind,
|
||||
preserve_mem: bool,
|
||||
module_id: ModuleId,
|
||||
path: &ModulePath,
|
||||
) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
|
||||
crate::log::log(format!("enter module {path} {}", exec_state.stack()));
|
||||
@ -101,7 +101,12 @@ impl ExecutorContext {
|
||||
let old_units = exec_state.length_unit();
|
||||
let original_execution = self.engine.replace_execution_kind(exec_kind).await;
|
||||
|
||||
let mut local_state = ModuleState::new(&self.settings, path.std_path(), exec_state.stack().memory.clone());
|
||||
let mut local_state = ModuleState::new(
|
||||
&self.settings,
|
||||
path.std_path(),
|
||||
exec_state.stack().memory.clone(),
|
||||
Some(module_id),
|
||||
);
|
||||
if !preserve_mem {
|
||||
std::mem::swap(&mut exec_state.mod_local, &mut local_state);
|
||||
}
|
||||
@ -504,7 +509,7 @@ impl ExecutorContext {
|
||||
ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
|
||||
ModuleRepr::Kcl(_, Some((env_ref, items))) => Ok((*env_ref, items.clone())),
|
||||
ModuleRepr::Kcl(program, cache) => self
|
||||
.exec_module_from_ast(program, &path, exec_state, exec_kind, source_range)
|
||||
.exec_module_from_ast(program, module_id, &path, exec_state, exec_kind, source_range)
|
||||
.await
|
||||
.map(|(_, er, items)| {
|
||||
*cache = Some((er, items.clone()));
|
||||
@ -535,7 +540,7 @@ impl ExecutorContext {
|
||||
let result = match &repr {
|
||||
ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
|
||||
ModuleRepr::Kcl(program, _) => self
|
||||
.exec_module_from_ast(program, &path, exec_state, exec_kind, source_range)
|
||||
.exec_module_from_ast(program, module_id, &path, exec_state, exec_kind, source_range)
|
||||
.await
|
||||
.map(|(val, _, _)| val),
|
||||
ModuleRepr::Foreign(geom) => super::import::send_to_engine(geom.clone(), self)
|
||||
@ -551,13 +556,16 @@ impl ExecutorContext {
|
||||
async fn exec_module_from_ast(
|
||||
&self,
|
||||
program: &Node<Program>,
|
||||
module_id: ModuleId,
|
||||
path: &ModulePath,
|
||||
exec_state: &mut ExecState,
|
||||
exec_kind: ExecutionKind,
|
||||
source_range: SourceRange,
|
||||
) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
|
||||
exec_state.global.mod_loader.enter_module(path);
|
||||
let result = self.exec_module_body(program, exec_state, exec_kind, false, path).await;
|
||||
let result = self
|
||||
.exec_module_body(program, exec_state, exec_kind, false, module_id, path)
|
||||
.await;
|
||||
exec_state.global.mod_loader.leave_module(path);
|
||||
|
||||
result.map_err(|err| {
|
||||
@ -690,11 +698,11 @@ impl ExecutorContext {
|
||||
let result = self
|
||||
.execute_expr(&expr.expr, exec_state, metadata, &[], statement_kind)
|
||||
.await?;
|
||||
coerce(result, &expr.ty, exec_state).map_err(|value| {
|
||||
coerce(&result, &expr.ty, exec_state).ok_or_else(|| {
|
||||
KclError::Semantic(KclErrorDetails {
|
||||
message: format!(
|
||||
"could not coerce {} value to type {}",
|
||||
value.human_friendly_type(),
|
||||
result.human_friendly_type(),
|
||||
expr.ty
|
||||
),
|
||||
source_ranges: vec![expr.into()],
|
||||
@ -706,72 +714,14 @@ impl ExecutorContext {
|
||||
}
|
||||
}
|
||||
|
||||
fn coerce(value: KclValue, ty: &Node<Type>, exec_state: &mut ExecState) -> Result<KclValue, KclValue> {
|
||||
let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, (&value).into())
|
||||
fn coerce(value: &KclValue, ty: &Node<Type>, exec_state: &mut ExecState) -> Option<KclValue> {
|
||||
let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into())
|
||||
.map_err(|e| {
|
||||
exec_state.err(e);
|
||||
value.clone()
|
||||
})?
|
||||
.ok_or_else(|| value.clone())?;
|
||||
if value.has_type(&ty) {
|
||||
return Ok(value);
|
||||
}
|
||||
})
|
||||
.ok()??;
|
||||
|
||||
// TODO coerce numeric types
|
||||
|
||||
if let KclValue::Object { value, meta } = value {
|
||||
return match ty {
|
||||
RuntimeType::Primitive(PrimitiveType::Plane) => {
|
||||
let origin = value
|
||||
.get("origin")
|
||||
.and_then(Point3d::from_kcl_val)
|
||||
.ok_or_else(|| KclValue::Object {
|
||||
value: value.clone(),
|
||||
meta: meta.clone(),
|
||||
})?;
|
||||
let x_axis = value
|
||||
.get("xAxis")
|
||||
.and_then(Point3d::from_kcl_val)
|
||||
.ok_or_else(|| KclValue::Object {
|
||||
value: value.clone(),
|
||||
meta: meta.clone(),
|
||||
})?;
|
||||
let y_axis = value
|
||||
.get("yAxis")
|
||||
.and_then(Point3d::from_kcl_val)
|
||||
.ok_or_else(|| KclValue::Object {
|
||||
value: value.clone(),
|
||||
meta: meta.clone(),
|
||||
})?;
|
||||
let z_axis = value
|
||||
.get("zAxis")
|
||||
.and_then(Point3d::from_kcl_val)
|
||||
.ok_or_else(|| KclValue::Object {
|
||||
value: value.clone(),
|
||||
meta: meta.clone(),
|
||||
})?;
|
||||
|
||||
let id = exec_state.global.id_generator.next_uuid();
|
||||
let plane = Plane {
|
||||
id,
|
||||
artifact_id: id.into(),
|
||||
origin,
|
||||
x_axis,
|
||||
y_axis,
|
||||
z_axis,
|
||||
value: PlaneType::Uninit,
|
||||
// TODO use length unit from origin
|
||||
units: exec_state.length_unit(),
|
||||
meta,
|
||||
};
|
||||
|
||||
Ok(KclValue::Plane { value: Box::new(plane) })
|
||||
}
|
||||
_ => Err(KclValue::Object { value, meta }),
|
||||
};
|
||||
}
|
||||
|
||||
Err(value)
|
||||
value.coerce(&ty, exec_state)
|
||||
}
|
||||
|
||||
impl BinaryPart {
|
||||
@ -797,33 +747,7 @@ impl BinaryPart {
|
||||
}
|
||||
|
||||
impl Node<MemberExpression> {
|
||||
pub fn get_result_array(&self, exec_state: &mut ExecState, index: usize) -> Result<KclValue, KclError> {
|
||||
let array = match &self.object {
|
||||
MemberObject::MemberExpression(member_expr) => member_expr.get_result(exec_state)?,
|
||||
MemberObject::Identifier(identifier) => {
|
||||
let value = exec_state.stack().get(&identifier.name, identifier.into())?;
|
||||
value.clone()
|
||||
}
|
||||
};
|
||||
|
||||
let KclValue::MixedArray { value: array, meta: _ } = array else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: format!("MemberExpression array is not an array: {:?}", array),
|
||||
source_ranges: vec![self.clone().into()],
|
||||
}));
|
||||
};
|
||||
|
||||
if let Some(value) = array.get(index) {
|
||||
Ok(value.to_owned())
|
||||
} else {
|
||||
Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: format!("index {} not found in array", index),
|
||||
source_ranges: vec![self.clone().into()],
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_result(&self, exec_state: &mut ExecState) -> Result<KclValue, KclError> {
|
||||
fn get_result(&self, exec_state: &mut ExecState) -> Result<KclValue, KclError> {
|
||||
let property = Property::try_from(self.computed, self.property.clone(), exec_state, self.into())?;
|
||||
let object = match &self.object {
|
||||
// TODO: Don't use recursion here, use a loop.
|
||||
@ -1424,11 +1348,22 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
|
||||
// TODO: This could probably be done in a better way, but as of now this was my only idea
|
||||
// and it works.
|
||||
match result {
|
||||
KclValue::Sketch { value: ref mut sketch } => {
|
||||
for (_, tag) in sketch.tags.iter() {
|
||||
exec_state
|
||||
.mut_stack()
|
||||
.insert_or_update(tag.value.clone(), KclValue::TagIdentifier(Box::new(tag.clone())));
|
||||
KclValue::Sketch { value } => {
|
||||
for (name, tag) in value.tags.iter() {
|
||||
if exec_state.stack().cur_frame_contains(name) {
|
||||
exec_state.mut_stack().update(name, |v, _| {
|
||||
v.as_mut_tag().unwrap().merge_info(tag);
|
||||
});
|
||||
} else {
|
||||
exec_state
|
||||
.mut_stack()
|
||||
.add(
|
||||
name.to_owned(),
|
||||
KclValue::TagIdentifier(Box::new(tag.clone())),
|
||||
SourceRange::default(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
KclValue::Solid { ref mut value } => {
|
||||
@ -1437,7 +1372,7 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
|
||||
// Get the past tag and update it.
|
||||
let tag_id = if let Some(t) = value.sketch.tags.get(&tag.name) {
|
||||
let mut t = t.clone();
|
||||
let Some(ref info) = t.info else {
|
||||
let Some(info) = t.get_cur_info() else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: format!("Tag {} does not have path info", tag.name),
|
||||
source_ranges: vec![tag.into()],
|
||||
@ -1447,59 +1382,70 @@ fn update_memory_for_tags_of_geometry(result: &mut KclValue, exec_state: &mut Ex
|
||||
let mut info = info.clone();
|
||||
info.surface = Some(v.clone());
|
||||
info.sketch = value.id;
|
||||
t.info = Some(info);
|
||||
t.info.push((exec_state.stack().current_epoch(), info));
|
||||
t
|
||||
} else {
|
||||
// It's probably a fillet or a chamfer.
|
||||
// Initialize it.
|
||||
TagIdentifier {
|
||||
value: tag.name.clone(),
|
||||
info: Some(TagEngineInfo {
|
||||
id: v.get_id(),
|
||||
surface: Some(v.clone()),
|
||||
path: None,
|
||||
sketch: value.id,
|
||||
}),
|
||||
info: vec![(
|
||||
exec_state.stack().current_epoch(),
|
||||
TagEngineInfo {
|
||||
id: v.get_id(),
|
||||
surface: Some(v.clone()),
|
||||
path: None,
|
||||
sketch: value.id,
|
||||
},
|
||||
)],
|
||||
meta: vec![Metadata {
|
||||
source_range: tag.clone().into(),
|
||||
}],
|
||||
}
|
||||
};
|
||||
|
||||
exec_state
|
||||
.mut_stack()
|
||||
.insert_or_update(tag.name.clone(), KclValue::TagIdentifier(Box::new(tag_id.clone())));
|
||||
|
||||
// update the sketch tags.
|
||||
value.sketch.tags.insert(tag.name.clone(), tag_id);
|
||||
value.sketch.merge_tags(Some(&tag_id).into_iter());
|
||||
|
||||
if exec_state.stack().cur_frame_contains(&tag.name) {
|
||||
exec_state.mut_stack().update(&tag.name, |v, _| {
|
||||
v.as_mut_tag().unwrap().merge_info(&tag_id);
|
||||
});
|
||||
} else {
|
||||
exec_state
|
||||
.mut_stack()
|
||||
.add(
|
||||
tag.name.clone(),
|
||||
KclValue::TagIdentifier(Box::new(tag_id)),
|
||||
SourceRange::default(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the stale sketch in memory and update it.
|
||||
if !value.sketch.tags.is_empty() {
|
||||
let updates: Vec<_> = exec_state
|
||||
let sketches_to_update: Vec<_> = exec_state
|
||||
.stack()
|
||||
.find_all_in_current_env(|v| match v {
|
||||
.find_keys_in_current_env(|v| match v {
|
||||
KclValue::Sketch { value: sk } => sk.artifact_id == value.sketch.artifact_id,
|
||||
_ => false,
|
||||
})
|
||||
.map(|(k, v)| {
|
||||
let mut sketch = v.as_sketch().unwrap().clone();
|
||||
for (tag_name, tag_id) in value.sketch.tags.iter() {
|
||||
sketch.tags.insert(tag_name.clone(), tag_id.clone());
|
||||
}
|
||||
(
|
||||
k.clone(),
|
||||
KclValue::Sketch {
|
||||
value: Box::new(sketch),
|
||||
},
|
||||
)
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
updates
|
||||
.into_iter()
|
||||
.for_each(|(k, v)| exec_state.mut_stack().insert_or_update(k, v))
|
||||
for k in sketches_to_update {
|
||||
exec_state.mut_stack().update(&k, |v, _| {
|
||||
let sketch = v.as_mut_sketch().unwrap();
|
||||
sketch.merge_tags(value.sketch.tags.values());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
KclValue::MixedArray { value, .. } | KclValue::HomArray { value, .. } => {
|
||||
for v in value {
|
||||
update_memory_for_tags_of_geometry(v, exec_state)?;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -1511,7 +1457,7 @@ impl Node<TagDeclarator> {
|
||||
pub async fn execute(&self, exec_state: &mut ExecState) -> Result<KclValue, KclError> {
|
||||
let memory_item = KclValue::TagIdentifier(Box::new(TagIdentifier {
|
||||
value: self.name.clone(),
|
||||
info: None,
|
||||
info: Vec::new(),
|
||||
meta: vec![Metadata {
|
||||
source_range: self.into(),
|
||||
}],
|
||||
@ -2026,8 +1972,8 @@ mod test {
|
||||
use std::sync::Arc;
|
||||
use tokio::{sync::RwLock, task::JoinSet};
|
||||
|
||||
#[test]
|
||||
fn test_assign_args_to_params() {
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_assign_args_to_params() {
|
||||
// Set up a little framework for this test.
|
||||
fn mem(number: usize) -> KclValue {
|
||||
KclValue::Number {
|
||||
@ -2138,7 +2084,16 @@ mod test {
|
||||
digest: None,
|
||||
});
|
||||
let args = args.into_iter().map(Arg::synthetic).collect();
|
||||
let mut exec_state = ExecState::new(&Default::default());
|
||||
let exec_ctxt = ExecutorContext {
|
||||
engine: Arc::new(Box::new(
|
||||
crate::engine::conn_mock::EngineConnection::new().await.unwrap(),
|
||||
)),
|
||||
fs: Arc::new(crate::fs::FileManager::new()),
|
||||
stdlib: Arc::new(RwLock::new(crate::std::StdLib::new())),
|
||||
settings: Default::default(),
|
||||
context_type: ContextType::Mock,
|
||||
};
|
||||
let mut exec_state = ExecState::new(&exec_ctxt);
|
||||
exec_state.mod_local.stack = Stack::new_for_tests();
|
||||
let actual = assign_args_to_params(func_expr, args, &mut exec_state).map(|_| exec_state.mod_local.stack);
|
||||
assert_eq!(
|
||||
@ -2278,7 +2233,7 @@ import 'a.kcl'
|
||||
settings: Default::default(),
|
||||
context_type: ContextType::Mock,
|
||||
};
|
||||
let mut exec_state = ExecState::new(&exec_ctxt.settings);
|
||||
let mut exec_state = ExecState::new(&exec_ctxt);
|
||||
|
||||
eprintln!("{:?}", exec_ctxt);
|
||||
|
||||
|
Reference in New Issue
Block a user