2023-08-24 15:34:51 -07:00
|
|
|
//! The executor for the AST.
|
|
|
|
|
2025-02-11 13:52:46 +13:00
|
|
|
use std::{path::PathBuf, sync::Arc};
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
use anyhow::Result;
|
2025-02-28 16:06:26 -05:00
|
|
|
pub use artifact::{
|
|
|
|
Artifact, ArtifactCommand, ArtifactGraph, ArtifactId, CodeRef, StartSketchOnFace, StartSketchOnPlane,
|
|
|
|
};
|
2025-02-05 17:53:49 +13:00
|
|
|
use cache::OldAstState;
|
2025-02-26 19:29:59 -08:00
|
|
|
pub use cache::{bust_cache, clear_mem_cache};
|
|
|
|
pub use cad_op::Operation;
|
|
|
|
pub use geometry::*;
|
|
|
|
pub(crate) use import::{
|
|
|
|
import_foreign, send_to_engine as send_import_to_engine, PreImportedGeometry, ZOO_COORD_SYSTEM,
|
|
|
|
};
|
2024-11-07 11:23:41 -05:00
|
|
|
use indexmap::IndexMap;
|
2025-03-08 03:53:34 +13:00
|
|
|
pub use kcl_value::{KclObjectFields, KclValue, PrimitiveType, UnitAngle, UnitLen};
|
2024-09-19 14:06:29 -07:00
|
|
|
use kcmc::{
|
|
|
|
each_cmd as mcmd,
|
|
|
|
ok_response::{output::TakeSnapshot, OkModelingCmdResponse},
|
|
|
|
websocket::{ModelingSessionData, OkWebSocketResponseData},
|
|
|
|
ImageFormat, ModelingCmd,
|
|
|
|
};
|
2025-02-05 17:53:49 +13:00
|
|
|
use kittycad_modeling_cmds as kcmc;
|
2025-02-26 19:29:59 -08:00
|
|
|
pub use memory::EnvironmentRef;
|
2023-08-25 13:41:04 -07:00
|
|
|
use schemars::JsonSchema;
|
2023-08-24 15:34:51 -07:00
|
|
|
use serde::{Deserialize, Serialize};
|
2025-02-26 19:29:59 -08:00
|
|
|
pub use state::{ExecState, IdGenerator, MetaSettings};
|
2023-08-25 13:41:04 -07:00
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
use crate::{
|
|
|
|
engine::EngineManager,
|
2025-02-11 13:52:46 +13:00
|
|
|
errors::KclError,
|
2025-02-05 17:53:49 +13:00
|
|
|
execution::{
|
|
|
|
artifact::build_artifact_graph,
|
|
|
|
cache::{CacheInformation, CacheResult},
|
|
|
|
},
|
2025-02-11 13:52:46 +13:00
|
|
|
fs::FileManager,
|
2025-02-25 11:51:54 -06:00
|
|
|
modules::{ModuleId, ModulePath},
|
2025-02-27 22:24:48 -08:00
|
|
|
parsing::ast::types::{Expr, ImportPath, NodeRef},
|
2025-02-05 17:53:49 +13:00
|
|
|
settings::types::UnitLength,
|
2025-02-11 13:52:46 +13:00
|
|
|
source_range::SourceRange,
|
2025-02-20 19:33:21 +13:00
|
|
|
std::StdLib,
|
2025-02-25 16:10:06 +13:00
|
|
|
CompilationError, ExecError, ExecutionKind, KclErrorWithOutputs,
|
2025-02-05 17:53:49 +13:00
|
|
|
};
|
2024-09-18 17:04:04 -05:00
|
|
|
|
2025-01-31 13:11:15 -08:00
|
|
|
pub(crate) mod annotations;
|
2025-01-08 20:02:30 -05:00
|
|
|
mod artifact;
|
2024-12-10 18:50:22 -08:00
|
|
|
pub(crate) mod cache;
|
2024-12-16 13:10:31 -05:00
|
|
|
mod cad_op;
|
2024-12-10 18:50:22 -08:00
|
|
|
mod exec_ast;
|
2025-02-05 17:53:49 +13:00
|
|
|
mod geometry;
|
2025-01-29 08:28:32 +13:00
|
|
|
mod import;
|
2025-01-31 13:11:15 -08:00
|
|
|
pub(crate) mod kcl_value;
|
2025-02-05 17:53:49 +13:00
|
|
|
mod memory;
|
|
|
|
mod state;
|
2024-09-16 15:10:33 -04:00
|
|
|
|
2025-01-06 16:55:59 -05:00
|
|
|
/// Outcome of executing a program. This is used in TS.
|
2025-03-08 04:04:57 +13:00
|
|
|
#[derive(Debug, Clone, Serialize, ts_rs::TS)]
|
2025-01-06 16:55:59 -05:00
|
|
|
#[ts(export)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct ExecOutcome {
|
2025-02-12 10:22:56 +13:00
|
|
|
/// Variables in the top-level of the root module. Note that functions will have an invalid env ref.
|
|
|
|
pub variables: IndexMap<String, KclValue>,
|
2025-01-06 16:55:59 -05:00
|
|
|
/// Operations that have been performed in execution order, for display in
|
|
|
|
/// the Feature Tree.
|
|
|
|
pub operations: Vec<Operation>,
|
2025-01-08 20:02:30 -05:00
|
|
|
/// Output map of UUIDs to artifacts.
|
|
|
|
pub artifacts: IndexMap<ArtifactId, Artifact>,
|
|
|
|
/// Output commands to allow building the artifact graph by the caller.
|
|
|
|
pub artifact_commands: Vec<ArtifactCommand>,
|
2025-01-17 14:34:36 -05:00
|
|
|
/// Output artifact graph.
|
|
|
|
pub artifact_graph: ArtifactGraph,
|
2025-02-21 09:30:44 +13:00
|
|
|
/// Non-fatal errors and warnings.
|
|
|
|
pub errors: Vec<CompilationError>,
|
2025-02-25 11:51:54 -06:00
|
|
|
/// File Names in module Id array index order
|
|
|
|
pub filenames: IndexMap<ModuleId, ModulePath>,
|
2025-01-06 16:55:59 -05:00
|
|
|
}
|
|
|
|
|
2024-04-15 17:18:32 -07:00
|
|
|
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
|
|
#[ts(export)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct DefaultPlanes {
|
|
|
|
pub xy: uuid::Uuid,
|
|
|
|
pub xz: uuid::Uuid,
|
|
|
|
pub yz: uuid::Uuid,
|
|
|
|
pub neg_xy: uuid::Uuid,
|
|
|
|
pub neg_xz: uuid::Uuid,
|
|
|
|
pub neg_yz: uuid::Uuid,
|
|
|
|
}
|
|
|
|
|
2024-07-27 22:56:46 -07:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ts_rs::TS, JsonSchema)]
|
2024-06-24 14:45:07 -07:00
|
|
|
#[ts(export)]
|
|
|
|
#[serde(tag = "type", rename_all = "camelCase")]
|
|
|
|
pub struct TagIdentifier {
|
|
|
|
pub value: String,
|
2024-07-27 22:56:46 -07:00
|
|
|
pub info: Option<TagEngineInfo>,
|
2024-06-24 14:45:07 -07:00
|
|
|
#[serde(rename = "__meta")]
|
|
|
|
pub meta: Vec<Metadata>,
|
|
|
|
}
|
|
|
|
|
2024-07-27 22:56:46 -07:00
|
|
|
impl Eq for TagIdentifier {}
|
|
|
|
|
2024-06-24 14:45:07 -07:00
|
|
|
impl std::fmt::Display for TagIdentifier {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "{}", self.value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::str::FromStr for TagIdentifier {
|
|
|
|
type Err = KclError;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
Ok(Self {
|
|
|
|
value: s.to_string(),
|
2024-07-27 22:56:46 -07:00
|
|
|
info: None,
|
2024-06-24 14:45:07 -07:00
|
|
|
meta: Default::default(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Ord for TagIdentifier {
|
|
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
|
|
self.value.cmp(&other.value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for TagIdentifier {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::hash::Hash for TagIdentifier {
|
|
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
|
|
self.value.hash(state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
/// Engine information for a tag.
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
|
|
#[ts(export)]
|
|
|
|
#[serde(tag = "type", rename_all = "camelCase")]
|
|
|
|
pub struct TagEngineInfo {
|
|
|
|
/// The id of the tagged object.
|
|
|
|
pub id: uuid::Uuid,
|
|
|
|
/// The sketch the tag is on.
|
|
|
|
pub sketch: uuid::Uuid,
|
|
|
|
/// The path the tag is on.
|
|
|
|
pub path: Option<Path>,
|
|
|
|
/// The surface information for the tag.
|
|
|
|
pub surface: Option<ExtrudeSurface>,
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
|
|
|
|
2025-02-21 09:30:44 +13:00
|
|
|
#[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq)]
|
2023-08-24 15:34:51 -07:00
|
|
|
pub enum BodyType {
|
2025-02-25 16:10:06 +13:00
|
|
|
Root,
|
2023-08-24 15:34:51 -07:00
|
|
|
Block,
|
|
|
|
}
|
|
|
|
|
2023-08-25 13:41:04 -07:00
|
|
|
/// Metadata.
|
2024-11-14 17:27:19 -06:00
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq, Copy)]
|
2023-08-24 15:34:51 -07:00
|
|
|
#[ts(export)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct Metadata {
|
2023-08-25 13:41:04 -07:00
|
|
|
/// The source range.
|
2023-08-24 15:34:51 -07:00
|
|
|
pub source_range: SourceRange,
|
|
|
|
}
|
|
|
|
|
2024-11-14 17:27:19 -06:00
|
|
|
impl From<Metadata> for Vec<SourceRange> {
|
|
|
|
fn from(meta: Metadata) -> Self {
|
|
|
|
vec![meta.source_range]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
impl From<SourceRange> for Metadata {
|
|
|
|
fn from(source_range: SourceRange) -> Self {
|
|
|
|
Self { source_range }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-30 16:52:17 -04:00
|
|
|
impl<T> From<NodeRef<'_, T>> for Metadata {
|
|
|
|
fn from(node: NodeRef<'_, T>) -> Self {
|
2024-10-17 00:48:33 -04:00
|
|
|
Self {
|
2024-11-07 11:23:41 -05:00
|
|
|
source_range: SourceRange::new(node.start, node.end, node.module_id),
|
2024-08-14 01:57:03 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-16 15:10:33 -04:00
|
|
|
impl From<&Expr> for Metadata {
|
|
|
|
fn from(expr: &Expr) -> Self {
|
|
|
|
Self {
|
|
|
|
source_range: SourceRange::from(expr),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-01 12:45:01 -07:00
|
|
|
/// The type of ExecutorContext being used
|
|
|
|
#[derive(PartialEq, Debug, Default, Clone)]
|
|
|
|
pub enum ContextType {
|
|
|
|
/// Live engine connection
|
|
|
|
#[default]
|
|
|
|
Live,
|
|
|
|
|
|
|
|
/// Completely mocked connection
|
|
|
|
/// Mock mode is only for the modeling app when they just want to mock engine calls and not
|
|
|
|
/// actually make them.
|
|
|
|
Mock,
|
|
|
|
|
|
|
|
/// Handled by some other interpreter/conversion system
|
|
|
|
MockCustomForwarded,
|
|
|
|
}
|
|
|
|
|
2023-10-05 14:27:48 -07:00
|
|
|
/// The executor context.
|
2024-06-06 16:01:41 -05:00
|
|
|
/// Cloning will return another handle to the same engine connection/session,
|
|
|
|
/// as this uses `Arc` under the hood.
|
2023-10-05 14:27:48 -07:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct ExecutorContext {
|
2024-03-13 12:56:46 -07:00
|
|
|
pub engine: Arc<Box<dyn EngineManager>>,
|
2024-04-15 17:18:32 -07:00
|
|
|
pub fs: Arc<FileManager>,
|
2023-11-08 20:23:59 -06:00
|
|
|
pub stdlib: Arc<StdLib>,
|
2024-04-25 00:13:09 -07:00
|
|
|
pub settings: ExecutorSettings,
|
2024-10-01 12:45:01 -07:00
|
|
|
pub context_type: ContextType,
|
2023-10-05 14:27:48 -07:00
|
|
|
}
|
|
|
|
|
2024-04-25 00:13:09 -07:00
|
|
|
/// The executor settings.
|
2024-12-05 19:51:06 -08:00
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
|
|
#[ts(export)]
|
2024-04-25 00:13:09 -07:00
|
|
|
pub struct ExecutorSettings {
|
2025-01-17 07:55:01 +13:00
|
|
|
/// The project-default unit to use in modeling dimensions.
|
2024-06-18 14:38:25 -05:00
|
|
|
pub units: UnitLength,
|
2024-04-25 00:13:09 -07:00
|
|
|
/// Highlight edges of 3D objects?
|
|
|
|
pub highlight_edges: bool,
|
2024-04-25 02:31:18 -07:00
|
|
|
/// Whether or not Screen Space Ambient Occlusion (SSAO) is enabled.
|
|
|
|
pub enable_ssao: bool,
|
2024-08-23 17:40:30 -05:00
|
|
|
/// Show grid?
|
2024-07-05 12:39:58 -07:00
|
|
|
pub show_grid: bool,
|
2024-08-23 17:40:30 -05:00
|
|
|
/// Should engine store this for replay?
|
|
|
|
/// If so, under what name?
|
|
|
|
pub replay: Option<String>,
|
2024-12-07 07:16:04 +13:00
|
|
|
/// The directory of the current project. This is used for resolving import
|
|
|
|
/// paths. If None is given, the current working directory is used.
|
|
|
|
pub project_directory: Option<PathBuf>,
|
2025-01-28 15:43:39 -08:00
|
|
|
/// This is the path to the current file being executed.
|
|
|
|
/// We use this for preventing cyclic imports.
|
|
|
|
pub current_file: Option<PathBuf>,
|
2024-04-25 00:13:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for ExecutorSettings {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
units: Default::default(),
|
|
|
|
highlight_edges: true,
|
2024-04-25 02:31:18 -07:00
|
|
|
enable_ssao: false,
|
2024-07-05 12:39:58 -07:00
|
|
|
show_grid: false,
|
2024-08-23 17:40:30 -05:00
|
|
|
replay: None,
|
2024-12-07 07:16:04 +13:00
|
|
|
project_directory: None,
|
2025-01-28 15:43:39 -08:00
|
|
|
current_file: None,
|
2024-04-25 02:31:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<crate::settings::types::Configuration> for ExecutorSettings {
|
|
|
|
fn from(config: crate::settings::types::Configuration) -> Self {
|
|
|
|
Self {
|
|
|
|
units: config.settings.modeling.base_unit,
|
|
|
|
highlight_edges: config.settings.modeling.highlight_edges.into(),
|
|
|
|
enable_ssao: config.settings.modeling.enable_ssao.into(),
|
2024-07-05 12:39:58 -07:00
|
|
|
show_grid: config.settings.modeling.show_scale_grid,
|
2024-08-23 17:40:30 -05:00
|
|
|
replay: None,
|
2024-12-07 07:16:04 +13:00
|
|
|
project_directory: None,
|
2025-01-28 15:43:39 -08:00
|
|
|
current_file: None,
|
2024-04-25 02:31:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<crate::settings::types::project::ProjectConfiguration> for ExecutorSettings {
|
|
|
|
fn from(config: crate::settings::types::project::ProjectConfiguration) -> Self {
|
|
|
|
Self {
|
|
|
|
units: config.settings.modeling.base_unit,
|
|
|
|
highlight_edges: config.settings.modeling.highlight_edges.into(),
|
|
|
|
enable_ssao: config.settings.modeling.enable_ssao.into(),
|
2025-02-28 16:15:57 -08:00
|
|
|
show_grid: Default::default(),
|
2024-08-23 17:40:30 -05:00
|
|
|
replay: None,
|
2024-12-07 07:16:04 +13:00
|
|
|
project_directory: None,
|
2025-01-28 15:43:39 -08:00
|
|
|
current_file: None,
|
2024-04-25 02:31:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<crate::settings::types::ModelingSettings> for ExecutorSettings {
|
|
|
|
fn from(modeling: crate::settings::types::ModelingSettings) -> Self {
|
|
|
|
Self {
|
|
|
|
units: modeling.base_unit,
|
|
|
|
highlight_edges: modeling.highlight_edges.into(),
|
|
|
|
enable_ssao: modeling.enable_ssao.into(),
|
2024-07-05 12:39:58 -07:00
|
|
|
show_grid: modeling.show_scale_grid,
|
2024-08-23 17:40:30 -05:00
|
|
|
replay: None,
|
2024-12-07 07:16:04 +13:00
|
|
|
project_directory: None,
|
2025-01-28 15:43:39 -08:00
|
|
|
current_file: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-28 19:02:06 -08:00
|
|
|
impl From<crate::settings::types::project::ProjectModelingSettings> for ExecutorSettings {
|
|
|
|
fn from(modeling: crate::settings::types::project::ProjectModelingSettings) -> Self {
|
|
|
|
Self {
|
|
|
|
units: modeling.base_unit,
|
|
|
|
highlight_edges: modeling.highlight_edges.into(),
|
|
|
|
enable_ssao: modeling.enable_ssao.into(),
|
|
|
|
show_grid: Default::default(),
|
|
|
|
replay: None,
|
|
|
|
project_directory: None,
|
|
|
|
current_file: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-28 15:43:39 -08:00
|
|
|
impl ExecutorSettings {
|
|
|
|
/// Add the current file path to the executor settings.
|
|
|
|
pub fn with_current_file(&mut self, current_file: PathBuf) {
|
|
|
|
// We want the parent directory of the file.
|
|
|
|
if current_file.extension() == Some(std::ffi::OsStr::new("kcl")) {
|
|
|
|
self.current_file = Some(current_file.clone());
|
|
|
|
// Get the parent directory.
|
|
|
|
if let Some(parent) = current_file.parent() {
|
|
|
|
self.project_directory = Some(parent.to_path_buf());
|
|
|
|
} else {
|
|
|
|
self.project_directory = Some(std::path::PathBuf::from(""));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.project_directory = Some(current_file.clone());
|
2024-04-25 00:13:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-12 12:18:37 -08:00
|
|
|
impl ExecutorContext {
|
|
|
|
/// Create a new default executor context.
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2024-08-23 17:40:30 -05:00
|
|
|
pub async fn new(client: &kittycad::Client, settings: ExecutorSettings) -> Result<Self> {
|
|
|
|
let (ws, _headers) = client
|
2024-04-25 02:31:18 -07:00
|
|
|
.modeling()
|
|
|
|
.commands_ws(
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
if settings.enable_ssao {
|
|
|
|
Some(kittycad::types::PostEffectType::Ssao)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
2024-08-23 17:40:30 -05:00
|
|
|
settings.replay.clone(),
|
2024-07-05 12:39:58 -07:00
|
|
|
if settings.show_grid { Some(true) } else { None },
|
2024-04-25 02:31:18 -07:00
|
|
|
None,
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
Some(false),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
let engine: Arc<Box<dyn EngineManager>> =
|
|
|
|
Arc::new(Box::new(crate::engine::conn::EngineConnection::new(ws).await?));
|
|
|
|
|
2024-08-23 17:40:30 -05:00
|
|
|
Ok(Self {
|
2024-04-25 02:31:18 -07:00
|
|
|
engine,
|
2024-04-15 17:18:32 -07:00
|
|
|
fs: Arc::new(FileManager::new()),
|
2024-02-12 12:18:37 -08:00
|
|
|
stdlib: Arc::new(StdLib::new()),
|
2024-04-25 00:13:09 -07:00
|
|
|
settings,
|
2024-10-01 12:45:01 -07:00
|
|
|
context_type: ContextType::Live,
|
2024-08-23 17:40:30 -05:00
|
|
|
})
|
2024-02-12 12:18:37 -08:00
|
|
|
}
|
|
|
|
|
2024-11-20 15:19:25 +13:00
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
|
|
pub async fn new(
|
|
|
|
engine_manager: crate::engine::conn_wasm::EngineCommandManager,
|
|
|
|
fs_manager: crate::fs::wasm::FileSystemManager,
|
2024-12-10 18:50:22 -08:00
|
|
|
settings: ExecutorSettings,
|
2024-11-20 15:19:25 +13:00
|
|
|
) -> Result<Self, String> {
|
|
|
|
Ok(ExecutorContext {
|
|
|
|
engine: Arc::new(Box::new(
|
|
|
|
crate::engine::conn_wasm::EngineConnection::new(engine_manager)
|
|
|
|
.await
|
|
|
|
.map_err(|e| format!("{:?}", e))?,
|
|
|
|
)),
|
|
|
|
fs: Arc::new(FileManager::new(fs_manager)),
|
|
|
|
stdlib: Arc::new(StdLib::new()),
|
2024-12-10 18:50:22 -08:00
|
|
|
settings,
|
2024-11-20 15:19:25 +13:00
|
|
|
context_type: ContextType::Live,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
|
|
pub async fn new_mock() -> Self {
|
|
|
|
ExecutorContext {
|
|
|
|
engine: Arc::new(Box::new(
|
|
|
|
crate::engine::conn_mock::EngineConnection::new().await.unwrap(),
|
|
|
|
)),
|
|
|
|
fs: Arc::new(FileManager::new()),
|
|
|
|
stdlib: Arc::new(StdLib::new()),
|
|
|
|
settings: Default::default(),
|
|
|
|
context_type: ContextType::Mock,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-20 15:19:25 +13:00
|
|
|
#[cfg(target_arch = "wasm32")]
|
2024-12-10 18:50:22 -08:00
|
|
|
pub async fn new_mock(
|
|
|
|
fs_manager: crate::fs::wasm::FileSystemManager,
|
|
|
|
settings: ExecutorSettings,
|
|
|
|
) -> Result<Self, String> {
|
2024-11-20 15:19:25 +13:00
|
|
|
Ok(ExecutorContext {
|
|
|
|
engine: Arc::new(Box::new(
|
|
|
|
crate::engine::conn_mock::EngineConnection::new()
|
|
|
|
.await
|
|
|
|
.map_err(|e| format!("{:?}", e))?,
|
|
|
|
)),
|
|
|
|
fs: Arc::new(FileManager::new(fs_manager)),
|
|
|
|
stdlib: Arc::new(StdLib::new()),
|
2024-12-10 18:50:22 -08:00
|
|
|
settings,
|
2024-11-20 15:19:25 +13:00
|
|
|
context_type: ContextType::Mock,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
|
|
pub fn new_forwarded_mock(engine: Arc<Box<dyn EngineManager>>) -> Self {
|
|
|
|
ExecutorContext {
|
|
|
|
engine,
|
|
|
|
fs: Arc::new(FileManager::new()),
|
|
|
|
stdlib: Arc::new(StdLib::new()),
|
|
|
|
settings: Default::default(),
|
|
|
|
context_type: ContextType::MockCustomForwarded,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-25 20:06:32 -07:00
|
|
|
/// Create a new default executor context.
|
|
|
|
/// With a kittycad client.
|
|
|
|
/// This allows for passing in `ZOO_API_TOKEN` and `ZOO_HOST` as environment
|
|
|
|
/// variables.
|
|
|
|
/// But also allows for passing in a token and engine address directly.
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
|
|
pub async fn new_with_client(
|
|
|
|
settings: ExecutorSettings,
|
|
|
|
token: Option<String>,
|
|
|
|
engine_addr: Option<String>,
|
|
|
|
) -> Result<Self> {
|
|
|
|
// Create the client.
|
2025-02-05 17:53:49 +13:00
|
|
|
let client = crate::engine::new_zoo_client(token, engine_addr)?;
|
2024-10-25 20:06:32 -07:00
|
|
|
|
|
|
|
let ctx = Self::new(&client, settings).await?;
|
|
|
|
Ok(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a new default executor context.
|
|
|
|
/// With the default kittycad client.
|
|
|
|
/// This allows for passing in `ZOO_API_TOKEN` and `ZOO_HOST` as environment
|
|
|
|
/// variables.
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2024-11-20 15:19:25 +13:00
|
|
|
pub async fn new_with_default_client(units: UnitLength) -> Result<Self> {
|
2024-10-25 20:06:32 -07:00
|
|
|
// Create the client.
|
2024-11-20 15:19:25 +13:00
|
|
|
let ctx = Self::new_with_client(
|
|
|
|
ExecutorSettings {
|
|
|
|
units,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
.await?;
|
2024-10-25 20:06:32 -07:00
|
|
|
Ok(ctx)
|
|
|
|
}
|
|
|
|
|
2024-06-18 14:38:25 -05:00
|
|
|
/// For executing unit tests.
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
2024-07-29 13:43:27 -05:00
|
|
|
pub async fn new_for_unit_test(units: UnitLength, engine_addr: Option<String>) -> Result<Self> {
|
2024-10-25 20:06:32 -07:00
|
|
|
let ctx = ExecutorContext::new_with_client(
|
2024-06-18 14:38:25 -05:00
|
|
|
ExecutorSettings {
|
|
|
|
units,
|
|
|
|
highlight_edges: true,
|
|
|
|
enable_ssao: false,
|
2024-07-05 12:39:58 -07:00
|
|
|
show_grid: false,
|
2024-08-23 17:40:30 -05:00
|
|
|
replay: None,
|
2024-12-07 07:16:04 +13:00
|
|
|
project_directory: None,
|
2025-01-28 15:43:39 -08:00
|
|
|
current_file: None,
|
2024-06-18 14:38:25 -05:00
|
|
|
},
|
2024-10-25 20:06:32 -07:00
|
|
|
None,
|
|
|
|
engine_addr,
|
2024-06-18 14:38:25 -05:00
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
Ok(ctx)
|
|
|
|
}
|
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
pub fn is_mock(&self) -> bool {
|
|
|
|
self.context_type == ContextType::Mock || self.context_type == ContextType::MockCustomForwarded
|
|
|
|
}
|
|
|
|
|
2025-02-12 22:37:34 -05:00
|
|
|
/// Returns true if we should not send engine commands for any reason.
|
2025-02-18 13:50:13 -08:00
|
|
|
pub async fn no_engine_commands(&self) -> bool {
|
|
|
|
self.is_mock() || self.engine.execution_kind().await.is_isolated()
|
2025-02-12 22:37:34 -05:00
|
|
|
}
|
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
pub async fn send_clear_scene(
|
2024-10-09 19:38:40 -04:00
|
|
|
&self,
|
2024-11-20 15:19:25 +13:00
|
|
|
exec_state: &mut ExecState,
|
2024-12-07 07:16:04 +13:00
|
|
|
source_range: crate::execution::SourceRange,
|
2024-12-05 19:51:06 -08:00
|
|
|
) -> Result<(), KclError> {
|
2024-11-20 15:19:25 +13:00
|
|
|
self.engine
|
2024-12-17 09:38:32 +13:00
|
|
|
.clear_scene(&mut exec_state.global.id_generator, source_range)
|
2025-02-05 17:53:49 +13:00
|
|
|
.await
|
2024-06-18 14:38:25 -05:00
|
|
|
}
|
2024-12-10 18:50:22 -08:00
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
async fn prepare_mem(&self, exec_state: &mut ExecState) -> Result<(), KclErrorWithOutputs> {
|
|
|
|
self.eval_prelude(exec_state, SourceRange::synthetic())
|
|
|
|
.await
|
|
|
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
2025-03-05 12:03:32 +13:00
|
|
|
exec_state.mut_stack().push_new_root_env(true);
|
2025-02-25 16:10:06 +13:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
pub async fn run_mock(
|
|
|
|
&self,
|
|
|
|
program: crate::Program,
|
2025-02-12 10:22:56 +13:00
|
|
|
use_prev_memory: bool,
|
2025-02-05 17:53:49 +13:00
|
|
|
) -> Result<ExecOutcome, KclErrorWithOutputs> {
|
|
|
|
assert!(self.is_mock());
|
2024-12-10 18:50:22 -08:00
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
let mut exec_state = ExecState::new(&self.settings);
|
2025-02-25 16:10:06 +13:00
|
|
|
if use_prev_memory {
|
|
|
|
match cache::read_old_memory().await {
|
2025-03-05 12:03:32 +13:00
|
|
|
Some(mem) => *exec_state.mut_stack() = mem,
|
2025-02-25 16:10:06 +13:00
|
|
|
None => self.prepare_mem(&mut exec_state).await?,
|
|
|
|
}
|
2025-02-12 10:22:56 +13:00
|
|
|
} else {
|
2025-02-25 16:10:06 +13:00
|
|
|
self.prepare_mem(&mut exec_state).await?
|
2025-02-12 10:22:56 +13:00
|
|
|
};
|
|
|
|
|
2025-03-08 04:04:57 +13:00
|
|
|
// Push a scope so that old variables can be overwritten (since we might be re-executing some
|
|
|
|
// part of the scene).
|
|
|
|
exec_state.mut_stack().push_new_env_for_scope();
|
2025-02-12 10:22:56 +13:00
|
|
|
|
2025-02-27 22:24:48 -08:00
|
|
|
let result = self.inner_run(&program, &mut exec_state, true).await?;
|
2025-02-12 10:22:56 +13:00
|
|
|
|
|
|
|
// Restore any temporary variables, then save any newly created variables back to
|
|
|
|
// memory in case another run wants to use them. Note this is just saved to the preserved
|
|
|
|
// memory, not to the exec_state which is not cached for mock execution.
|
2025-03-05 12:03:32 +13:00
|
|
|
|
|
|
|
let mut mem = exec_state.stack().clone();
|
|
|
|
let outcome = exec_state.to_mock_wasm_outcome(result.0);
|
2025-02-12 10:22:56 +13:00
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
mem.squash_env(result.0);
|
2025-02-12 10:22:56 +13:00
|
|
|
cache::write_old_memory(mem).await;
|
|
|
|
|
|
|
|
Ok(outcome)
|
2025-02-05 17:53:49 +13:00
|
|
|
}
|
2024-12-10 18:50:22 -08:00
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
pub async fn run_with_caching(&self, program: crate::Program) -> Result<ExecOutcome, KclErrorWithOutputs> {
|
|
|
|
assert!(!self.is_mock());
|
Implement some basic cache program generation (#4840)
Implement some basic cache program generation
A bit ago, @jessfraz added the ability to control reexecution from the
executor. When we did this, it used the digest to determine if there
was a code change rather than a non-code change (whitespace, comment,
etc).
This allows the creation of a new program to be run without clearing the
scene. This, in conjunction with being able to delete Engine objects by
ID will allow us to do some clever stuff when incrementally executing
a program.
I'm still working on something a bit more advanced, but a good first
step to derisk some of the caching behavior here fully is to implement a
basic "changed program" stub.
This process the ast programs (old and new) if it doesn't exactly match.
This would have been a complete refresh before this commit.
1) Check all overlapping top-level statements of the body of the new and
old AST and ensure they all match.
- If this is true, this means that one of the two AST programs has more
elements then the other, and they all otherwise match (addition or
deletion of the end of the program). We continue to #2 in this
case.
- If this is false, we have a meaingful difference in a section of
overlapping code. This will result in a cache miss and rebuild
the scene. We short-cut here and the scene is rebuilt.
2) Check the lengths of the two bodies.
- If they're the same, we shouldn't have even been called. We will
short-cut with a noop cache return (no clear, no program).
- if the old ast is longer, we've removed instructions from the
program. We can't delete things now, so this will result in a cache
miss and rebuild the scene. We short-cut here and the scene is
rebuilt.
- If the new ast is longer, we have an insertion of code at the end.
3) construct a new program using only the new elements from the new
ast, and return a `CacheResult` that *does not clear the scene*.
This means nothing will be rebuilt, and only a new object will polp
onto the scene. This is the first case where we diverge with
existing behavior.
Signed-off-by: Paul R. Tagliamonte <paul@zoo.dev>
2024-12-19 16:18:35 -05:00
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
let (program, mut exec_state, preserve_mem) = if let Some(OldAstState {
|
2025-02-05 17:53:49 +13:00
|
|
|
ast: old_ast,
|
2025-02-25 16:10:06 +13:00
|
|
|
exec_state: mut old_state,
|
2025-02-05 17:53:49 +13:00
|
|
|
settings: old_settings,
|
2025-02-25 16:10:06 +13:00
|
|
|
result_env,
|
2025-02-12 10:22:56 +13:00
|
|
|
}) = cache::read_old_ast().await
|
2025-02-05 17:53:49 +13:00
|
|
|
{
|
|
|
|
let old = CacheInformation {
|
|
|
|
ast: &old_ast,
|
|
|
|
settings: &old_settings,
|
|
|
|
};
|
|
|
|
let new = CacheInformation {
|
|
|
|
ast: &program.ast,
|
|
|
|
settings: &self.settings,
|
|
|
|
};
|
2024-12-10 18:50:22 -08:00
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
// Get the program that actually changed from the old and new information.
|
|
|
|
let (clear_scene, program) = match cache::get_changed_program(old, new).await {
|
|
|
|
CacheResult::ReExecute {
|
|
|
|
clear_scene,
|
|
|
|
reapply_settings,
|
|
|
|
program: changed_program,
|
|
|
|
} => {
|
|
|
|
if reapply_settings
|
|
|
|
&& self
|
|
|
|
.engine
|
|
|
|
.reapply_settings(&self.settings, Default::default())
|
|
|
|
.await
|
|
|
|
.is_err()
|
|
|
|
{
|
2025-02-27 14:34:01 -08:00
|
|
|
(true, program)
|
2025-02-05 17:53:49 +13:00
|
|
|
} else {
|
2025-02-27 14:34:01 -08:00
|
|
|
(
|
|
|
|
clear_scene,
|
|
|
|
crate::Program {
|
|
|
|
ast: changed_program,
|
|
|
|
original_file_contents: program.original_file_contents,
|
|
|
|
},
|
|
|
|
)
|
2025-02-05 17:53:49 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
CacheResult::NoAction(true) => {
|
|
|
|
if self
|
|
|
|
.engine
|
|
|
|
.reapply_settings(&self.settings, Default::default())
|
|
|
|
.await
|
|
|
|
.is_ok()
|
|
|
|
{
|
2025-02-20 22:08:49 -08:00
|
|
|
// We need to update the old ast state with the new settings!!
|
|
|
|
cache::write_old_ast(OldAstState {
|
|
|
|
ast: old_ast,
|
|
|
|
exec_state: old_state.clone(),
|
|
|
|
settings: self.settings.clone(),
|
2025-02-25 16:10:06 +13:00
|
|
|
result_env,
|
2025-02-20 22:08:49 -08:00
|
|
|
})
|
|
|
|
.await;
|
|
|
|
|
2025-03-05 12:03:32 +13:00
|
|
|
let outcome = old_state.to_wasm_outcome(result_env);
|
|
|
|
return Ok(outcome);
|
2025-02-05 17:53:49 +13:00
|
|
|
}
|
2025-02-27 14:34:01 -08:00
|
|
|
(true, program)
|
2025-02-05 17:53:49 +13:00
|
|
|
}
|
2025-03-05 12:03:32 +13:00
|
|
|
CacheResult::NoAction(false) => {
|
|
|
|
let outcome = old_state.to_wasm_outcome(result_env);
|
|
|
|
return Ok(outcome);
|
|
|
|
}
|
2025-02-05 17:53:49 +13:00
|
|
|
};
|
2024-12-10 18:50:22 -08:00
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
let (exec_state, preserve_mem) = if clear_scene {
|
2025-02-05 17:53:49 +13:00
|
|
|
// Pop the execution state, since we are starting fresh.
|
|
|
|
let mut exec_state = old_state;
|
|
|
|
exec_state.reset(&self.settings);
|
|
|
|
|
2025-02-28 15:00:10 -08:00
|
|
|
exec_state.add_root_module_contents(&program);
|
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
// We don't do this in mock mode since there is no engine connection
|
|
|
|
// anyways and from the TS side we override memory and don't want to clear it.
|
|
|
|
self.send_clear_scene(&mut exec_state, Default::default())
|
|
|
|
.await
|
|
|
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
Implement some basic cache program generation (#4840)
Implement some basic cache program generation
A bit ago, @jessfraz added the ability to control reexecution from the
executor. When we did this, it used the digest to determine if there
was a code change rather than a non-code change (whitespace, comment,
etc).
This allows the creation of a new program to be run without clearing the
scene. This, in conjunction with being able to delete Engine objects by
ID will allow us to do some clever stuff when incrementally executing
a program.
I'm still working on something a bit more advanced, but a good first
step to derisk some of the caching behavior here fully is to implement a
basic "changed program" stub.
This process the ast programs (old and new) if it doesn't exactly match.
This would have been a complete refresh before this commit.
1) Check all overlapping top-level statements of the body of the new and
old AST and ensure they all match.
- If this is true, this means that one of the two AST programs has more
elements then the other, and they all otherwise match (addition or
deletion of the end of the program). We continue to #2 in this
case.
- If this is false, we have a meaingful difference in a section of
overlapping code. This will result in a cache miss and rebuild
the scene. We short-cut here and the scene is rebuilt.
2) Check the lengths of the two bodies.
- If they're the same, we shouldn't have even been called. We will
short-cut with a noop cache return (no clear, no program).
- if the old ast is longer, we've removed instructions from the
program. We can't delete things now, so this will result in a cache
miss and rebuild the scene. We short-cut here and the scene is
rebuilt.
- If the new ast is longer, we have an insertion of code at the end.
3) construct a new program using only the new elements from the new
ast, and return a `CacheResult` that *does not clear the scene*.
This means nothing will be rebuilt, and only a new object will polp
onto the scene. This is the first case where we diverge with
existing behavior.
Signed-off-by: Paul R. Tagliamonte <paul@zoo.dev>
2024-12-19 16:18:35 -05:00
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
(exec_state, false)
|
2025-02-05 17:53:49 +13:00
|
|
|
} else {
|
2025-03-05 12:03:32 +13:00
|
|
|
old_state.mut_stack().restore_env(result_env);
|
2025-02-28 15:00:10 -08:00
|
|
|
old_state.add_root_module_contents(&program);
|
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
(old_state, true)
|
Implement some basic cache program generation (#4840)
Implement some basic cache program generation
A bit ago, @jessfraz added the ability to control reexecution from the
executor. When we did this, it used the digest to determine if there
was a code change rather than a non-code change (whitespace, comment,
etc).
This allows the creation of a new program to be run without clearing the
scene. This, in conjunction with being able to delete Engine objects by
ID will allow us to do some clever stuff when incrementally executing
a program.
I'm still working on something a bit more advanced, but a good first
step to derisk some of the caching behavior here fully is to implement a
basic "changed program" stub.
This process the ast programs (old and new) if it doesn't exactly match.
This would have been a complete refresh before this commit.
1) Check all overlapping top-level statements of the body of the new and
old AST and ensure they all match.
- If this is true, this means that one of the two AST programs has more
elements then the other, and they all otherwise match (addition or
deletion of the end of the program). We continue to #2 in this
case.
- If this is false, we have a meaingful difference in a section of
overlapping code. This will result in a cache miss and rebuild
the scene. We short-cut here and the scene is rebuilt.
2) Check the lengths of the two bodies.
- If they're the same, we shouldn't have even been called. We will
short-cut with a noop cache return (no clear, no program).
- if the old ast is longer, we've removed instructions from the
program. We can't delete things now, so this will result in a cache
miss and rebuild the scene. We short-cut here and the scene is
rebuilt.
- If the new ast is longer, we have an insertion of code at the end.
3) construct a new program using only the new elements from the new
ast, and return a `CacheResult` that *does not clear the scene*.
This means nothing will be rebuilt, and only a new object will polp
onto the scene. This is the first case where we diverge with
existing behavior.
Signed-off-by: Paul R. Tagliamonte <paul@zoo.dev>
2024-12-19 16:18:35 -05:00
|
|
|
};
|
2024-12-10 18:50:22 -08:00
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
(program, exec_state, preserve_mem)
|
2025-02-05 17:53:49 +13:00
|
|
|
} else {
|
|
|
|
let mut exec_state = ExecState::new(&self.settings);
|
2025-02-28 15:00:10 -08:00
|
|
|
exec_state.add_root_module_contents(&program);
|
2025-02-05 17:53:49 +13:00
|
|
|
self.send_clear_scene(&mut exec_state, Default::default())
|
|
|
|
.await
|
|
|
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
2025-02-27 14:34:01 -08:00
|
|
|
(program, exec_state, false)
|
2025-02-05 17:53:49 +13:00
|
|
|
};
|
|
|
|
|
2025-02-27 22:24:48 -08:00
|
|
|
let result = self.inner_run(&program, &mut exec_state, preserve_mem).await;
|
2025-02-05 17:53:49 +13:00
|
|
|
|
|
|
|
if result.is_err() {
|
|
|
|
cache::bust_cache().await;
|
Implement some basic cache program generation (#4840)
Implement some basic cache program generation
A bit ago, @jessfraz added the ability to control reexecution from the
executor. When we did this, it used the digest to determine if there
was a code change rather than a non-code change (whitespace, comment,
etc).
This allows the creation of a new program to be run without clearing the
scene. This, in conjunction with being able to delete Engine objects by
ID will allow us to do some clever stuff when incrementally executing
a program.
I'm still working on something a bit more advanced, but a good first
step to derisk some of the caching behavior here fully is to implement a
basic "changed program" stub.
This process the ast programs (old and new) if it doesn't exactly match.
This would have been a complete refresh before this commit.
1) Check all overlapping top-level statements of the body of the new and
old AST and ensure they all match.
- If this is true, this means that one of the two AST programs has more
elements then the other, and they all otherwise match (addition or
deletion of the end of the program). We continue to #2 in this
case.
- If this is false, we have a meaingful difference in a section of
overlapping code. This will result in a cache miss and rebuild
the scene. We short-cut here and the scene is rebuilt.
2) Check the lengths of the two bodies.
- If they're the same, we shouldn't have even been called. We will
short-cut with a noop cache return (no clear, no program).
- if the old ast is longer, we've removed instructions from the
program. We can't delete things now, so this will result in a cache
miss and rebuild the scene. We short-cut here and the scene is
rebuilt.
- If the new ast is longer, we have an insertion of code at the end.
3) construct a new program using only the new elements from the new
ast, and return a `CacheResult` that *does not clear the scene*.
This means nothing will be rebuilt, and only a new object will polp
onto the scene. This is the first case where we diverge with
existing behavior.
Signed-off-by: Paul R. Tagliamonte <paul@zoo.dev>
2024-12-19 16:18:35 -05:00
|
|
|
}
|
2025-02-05 17:53:49 +13:00
|
|
|
|
|
|
|
// Throw the error.
|
2025-02-25 16:10:06 +13:00
|
|
|
let result = result?;
|
2025-02-05 17:53:49 +13:00
|
|
|
|
|
|
|
// Save this as the last successful execution to the cache.
|
2025-02-12 10:22:56 +13:00
|
|
|
cache::write_old_ast(OldAstState {
|
2025-02-27 14:34:01 -08:00
|
|
|
ast: program.ast,
|
2025-02-05 17:53:49 +13:00
|
|
|
exec_state: exec_state.clone(),
|
|
|
|
settings: self.settings.clone(),
|
2025-02-25 16:10:06 +13:00
|
|
|
result_env: result.0,
|
2025-02-05 17:53:49 +13:00
|
|
|
})
|
|
|
|
.await;
|
|
|
|
|
2025-03-05 12:03:32 +13:00
|
|
|
let outcome = exec_state.to_wasm_outcome(result.0);
|
|
|
|
Ok(outcome)
|
2024-12-10 18:50:22 -08:00
|
|
|
}
|
2024-06-18 14:38:25 -05:00
|
|
|
|
2024-04-12 21:32:57 -07:00
|
|
|
/// Perform the execution of a program.
|
2025-01-08 20:02:30 -05:00
|
|
|
///
|
|
|
|
/// You can optionally pass in some initialization memory for partial
|
|
|
|
/// execution.
|
2025-02-21 09:30:44 +13:00
|
|
|
///
|
|
|
|
/// To access non-fatal errors and warnings, extract them from the `ExecState`.
|
2025-02-05 17:53:49 +13:00
|
|
|
pub async fn run(
|
|
|
|
&self,
|
|
|
|
program: &crate::Program,
|
|
|
|
exec_state: &mut ExecState,
|
2025-02-25 16:10:06 +13:00
|
|
|
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclError> {
|
2025-02-05 17:53:49 +13:00
|
|
|
self.run_with_ui_outputs(program, exec_state)
|
|
|
|
.await
|
|
|
|
.map_err(|e| e.into())
|
2024-08-23 17:40:30 -05:00
|
|
|
}
|
2024-11-20 15:19:25 +13:00
|
|
|
|
2024-08-23 17:40:30 -05:00
|
|
|
/// Perform the execution of a program.
|
2025-01-08 20:02:30 -05:00
|
|
|
///
|
|
|
|
/// You can optionally pass in some initialization memory for partial
|
|
|
|
/// execution.
|
|
|
|
///
|
|
|
|
/// The error includes additional outputs used for the feature tree and
|
|
|
|
/// artifact graph.
|
|
|
|
pub async fn run_with_ui_outputs(
|
|
|
|
&self,
|
2025-02-05 17:53:49 +13:00
|
|
|
program: &crate::Program,
|
2024-11-20 15:19:25 +13:00
|
|
|
exec_state: &mut ExecState,
|
2025-02-25 16:10:06 +13:00
|
|
|
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
2025-02-28 15:00:10 -08:00
|
|
|
exec_state.add_root_module_contents(program);
|
2025-02-05 17:53:49 +13:00
|
|
|
self.send_clear_scene(exec_state, Default::default())
|
|
|
|
.await
|
|
|
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
2025-02-27 22:24:48 -08:00
|
|
|
self.inner_run(program, exec_state, false).await
|
2025-01-08 20:02:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Perform the execution of a program. Accept all possible parameters and
|
2025-02-05 17:53:49 +13:00
|
|
|
/// output everything.
|
|
|
|
async fn inner_run(
|
|
|
|
&self,
|
2025-02-27 22:24:48 -08:00
|
|
|
program: &crate::Program,
|
2025-02-05 17:53:49 +13:00
|
|
|
exec_state: &mut ExecState,
|
2025-02-25 16:10:06 +13:00
|
|
|
preserve_mem: bool,
|
|
|
|
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
2025-02-05 17:53:49 +13:00
|
|
|
let _stats = crate::log::LogPerfStats::new("Interpretation");
|
2024-12-05 19:51:06 -08:00
|
|
|
|
2024-12-10 18:50:22 -08:00
|
|
|
// Re-apply the settings, in case the cache was busted.
|
2025-01-08 20:02:30 -05:00
|
|
|
self.engine
|
|
|
|
.reapply_settings(&self.settings, Default::default())
|
|
|
|
.await
|
|
|
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
2024-10-09 19:38:40 -04:00
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
let env_ref = self
|
2025-02-27 22:24:48 -08:00
|
|
|
.execute_and_build_graph(&program.ast, exec_state, preserve_mem)
|
2025-02-20 19:33:21 +13:00
|
|
|
.await
|
|
|
|
.map_err(|e| {
|
2025-02-25 11:51:54 -06:00
|
|
|
let module_id_to_module_path: IndexMap<ModuleId, ModulePath> = exec_state
|
|
|
|
.global
|
|
|
|
.path_to_source_id
|
|
|
|
.iter()
|
|
|
|
.map(|(k, v)| ((*v), k.clone()))
|
|
|
|
.collect();
|
|
|
|
|
2025-02-20 19:33:21 +13:00
|
|
|
KclErrorWithOutputs::new(
|
|
|
|
e,
|
2025-02-27 15:46:41 +13:00
|
|
|
exec_state.global.operations.clone(),
|
2025-02-20 19:33:21 +13:00
|
|
|
exec_state.global.artifact_commands.clone(),
|
|
|
|
exec_state.global.artifact_graph.clone(),
|
2025-02-25 11:51:54 -06:00
|
|
|
module_id_to_module_path,
|
2025-02-26 19:29:59 -08:00
|
|
|
exec_state.global.id_to_source.clone(),
|
2025-02-20 19:33:21 +13:00
|
|
|
)
|
|
|
|
})?;
|
2025-01-17 14:34:36 -05:00
|
|
|
|
2025-03-05 12:03:32 +13:00
|
|
|
crate::log::log(format!(
|
|
|
|
"Post interpretation KCL memory stats: {:#?}",
|
|
|
|
exec_state.stack().memory.stats
|
|
|
|
));
|
|
|
|
|
2025-02-12 10:22:56 +13:00
|
|
|
if !self.is_mock() {
|
2025-03-05 12:03:32 +13:00
|
|
|
let mut mem = exec_state.stack().deep_clone();
|
2025-02-25 16:10:06 +13:00
|
|
|
mem.restore_env(env_ref);
|
|
|
|
cache::write_old_memory(mem).await;
|
2025-02-12 10:22:56 +13:00
|
|
|
}
|
2025-02-18 13:50:13 -08:00
|
|
|
let session_data = self.engine.get_session_data().await;
|
2025-02-25 16:10:06 +13:00
|
|
|
Ok((env_ref, session_data))
|
2025-01-17 14:34:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Execute an AST's program and build auxiliary outputs like the artifact
|
|
|
|
/// graph.
|
2025-02-05 19:51:54 -05:00
|
|
|
async fn execute_and_build_graph(
|
2025-01-17 14:34:36 -05:00
|
|
|
&self,
|
2025-02-05 19:51:54 -05:00
|
|
|
program: NodeRef<'_, crate::parsing::ast::types::Program>,
|
2025-01-17 14:34:36 -05:00
|
|
|
exec_state: &mut ExecState,
|
2025-02-25 16:10:06 +13:00
|
|
|
preserve_mem: bool,
|
|
|
|
) -> Result<EnvironmentRef, KclError> {
|
2025-01-17 14:34:36 -05:00
|
|
|
// Don't early return! We need to build other outputs regardless of
|
|
|
|
// whether execution failed.
|
2025-02-25 16:10:06 +13:00
|
|
|
|
|
|
|
self.eval_prelude(exec_state, SourceRange::from(program).start_as_range())
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
let exec_result = self
|
2025-02-27 15:46:41 +13:00
|
|
|
.exec_module_body(
|
|
|
|
program,
|
|
|
|
exec_state,
|
|
|
|
ExecutionKind::Normal,
|
|
|
|
preserve_mem,
|
|
|
|
&ModulePath::Main,
|
|
|
|
)
|
2025-02-25 16:10:06 +13:00
|
|
|
.await;
|
|
|
|
|
2025-01-17 14:34:36 -05:00
|
|
|
// Move the artifact commands and responses to simplify cache management
|
|
|
|
// and error creation.
|
2025-01-10 22:33:05 -05:00
|
|
|
exec_state
|
|
|
|
.global
|
|
|
|
.artifact_commands
|
2025-02-18 13:50:13 -08:00
|
|
|
.extend(self.engine.take_artifact_commands().await);
|
|
|
|
exec_state
|
|
|
|
.global
|
|
|
|
.artifact_responses
|
|
|
|
.extend(self.engine.take_responses().await);
|
2025-01-17 14:34:36 -05:00
|
|
|
// Build the artifact graph.
|
|
|
|
match build_artifact_graph(
|
|
|
|
&exec_state.global.artifact_commands,
|
|
|
|
&exec_state.global.artifact_responses,
|
|
|
|
program,
|
|
|
|
&exec_state.global.artifacts,
|
|
|
|
) {
|
|
|
|
Ok(artifact_graph) => {
|
|
|
|
exec_state.global.artifact_graph = artifact_graph;
|
2025-02-27 15:46:41 +13:00
|
|
|
exec_result.map(|(_, env_ref, _)| env_ref)
|
2025-01-17 14:34:36 -05:00
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
// Prefer the exec error.
|
|
|
|
exec_result.and(Err(err))
|
|
|
|
}
|
|
|
|
}
|
2024-04-12 21:32:57 -07:00
|
|
|
}
|
2024-02-20 17:55:06 -08:00
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
/// 'Import' std::prelude as the outermost scope.
|
2025-03-05 12:03:32 +13:00
|
|
|
///
|
|
|
|
/// SAFETY: the current thread must have sole access to the memory referenced in exec_state.
|
2025-02-25 16:10:06 +13:00
|
|
|
async fn eval_prelude(&self, exec_state: &mut ExecState, source_range: SourceRange) -> Result<(), KclError> {
|
2025-03-05 12:03:32 +13:00
|
|
|
if exec_state.stack().memory.requires_std() {
|
2025-02-25 16:10:06 +13:00
|
|
|
let id = self
|
|
|
|
.open_module(
|
|
|
|
&ImportPath::Std {
|
|
|
|
path: vec!["std".to_owned(), "prelude".to_owned()],
|
|
|
|
},
|
|
|
|
&[],
|
|
|
|
exec_state,
|
|
|
|
source_range,
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
let (module_memory, _) = self
|
|
|
|
.exec_module_for_items(id, exec_state, ExecutionKind::Isolated, source_range)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
2025-03-05 12:03:32 +13:00
|
|
|
exec_state.mut_stack().memory.set_std(module_memory);
|
2025-02-25 16:10:06 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-04-12 21:32:57 -07:00
|
|
|
/// Update the units for the executor.
|
2025-02-05 17:53:49 +13:00
|
|
|
pub(crate) fn update_units(&mut self, units: UnitLength) {
|
2024-04-25 00:13:09 -07:00
|
|
|
self.settings.units = units;
|
2024-04-12 21:32:57 -07:00
|
|
|
}
|
2024-06-06 16:01:41 -05:00
|
|
|
|
2024-12-10 18:50:22 -08:00
|
|
|
/// Get a snapshot of the current scene.
|
|
|
|
pub async fn prepare_snapshot(&self) -> std::result::Result<TakeSnapshot, ExecError> {
|
2024-06-06 16:01:41 -05:00
|
|
|
// Zoom to fit.
|
|
|
|
self.engine
|
|
|
|
.send_modeling_cmd(
|
|
|
|
uuid::Uuid::new_v4(),
|
2024-12-07 07:16:04 +13:00
|
|
|
crate::execution::SourceRange::default(),
|
2025-01-08 20:02:30 -05:00
|
|
|
&ModelingCmd::from(mcmd::ZoomToFit {
|
2024-06-06 16:01:41 -05:00
|
|
|
object_ids: Default::default(),
|
2024-09-18 17:04:04 -05:00
|
|
|
animated: false,
|
2024-06-06 16:01:41 -05:00
|
|
|
padding: 0.1,
|
2024-09-18 17:04:04 -05:00
|
|
|
}),
|
2024-06-06 16:01:41 -05:00
|
|
|
)
|
2025-01-08 20:02:30 -05:00
|
|
|
.await
|
|
|
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
2024-06-06 16:01:41 -05:00
|
|
|
|
|
|
|
// Send a snapshot request to the engine.
|
|
|
|
let resp = self
|
|
|
|
.engine
|
|
|
|
.send_modeling_cmd(
|
|
|
|
uuid::Uuid::new_v4(),
|
2024-12-07 07:16:04 +13:00
|
|
|
crate::execution::SourceRange::default(),
|
2025-01-08 20:02:30 -05:00
|
|
|
&ModelingCmd::from(mcmd::TakeSnapshot {
|
2024-09-18 17:04:04 -05:00
|
|
|
format: ImageFormat::Png,
|
|
|
|
}),
|
2024-06-06 16:01:41 -05:00
|
|
|
)
|
2025-01-08 20:02:30 -05:00
|
|
|
.await
|
|
|
|
.map_err(KclErrorWithOutputs::no_outputs)?;
|
2024-06-06 16:01:41 -05:00
|
|
|
|
2024-09-18 17:04:04 -05:00
|
|
|
let OkWebSocketResponseData::Modeling {
|
|
|
|
modeling_response: OkModelingCmdResponse::TakeSnapshot(contents),
|
2024-06-06 16:01:41 -05:00
|
|
|
} = resp
|
|
|
|
else {
|
2024-11-25 14:06:23 -06:00
|
|
|
return Err(ExecError::BadPng(format!(
|
|
|
|
"Instead of a TakeSnapshot response, the engine returned {resp:?}"
|
|
|
|
)));
|
2024-06-06 16:01:41 -05:00
|
|
|
};
|
2024-11-20 15:19:25 +13:00
|
|
|
Ok(contents)
|
2024-06-06 16:01:41 -05:00
|
|
|
}
|
2024-12-10 18:50:22 -08:00
|
|
|
|
2025-01-10 20:05:27 -05:00
|
|
|
pub async fn close(&self) {
|
|
|
|
self.engine.close().await;
|
|
|
|
}
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
#[cfg(test)]
|
2025-02-28 17:40:01 -08:00
|
|
|
pub(crate) async fn parse_execute(
|
|
|
|
code: &str,
|
|
|
|
) -> Result<(crate::Program, EnvironmentRef, ExecutorContext, ExecState), KclError> {
|
2025-02-05 17:53:49 +13:00
|
|
|
let program = crate::Program::parse_no_errs(code)?;
|
|
|
|
|
|
|
|
let ctx = ExecutorContext {
|
2025-02-28 17:40:01 -08:00
|
|
|
engine: Arc::new(Box::new(
|
|
|
|
crate::engine::conn_mock::EngineConnection::new().await.map_err(|err| {
|
|
|
|
KclError::Internal(crate::errors::KclErrorDetails {
|
|
|
|
message: format!("Failed to create mock engine connection: {}", err),
|
|
|
|
source_ranges: vec![SourceRange::default()],
|
|
|
|
})
|
|
|
|
})?,
|
|
|
|
)),
|
2025-02-05 17:53:49 +13:00
|
|
|
fs: Arc::new(crate::fs::FileManager::new()),
|
|
|
|
stdlib: Arc::new(crate::std::StdLib::new()),
|
|
|
|
settings: Default::default(),
|
|
|
|
context_type: ContextType::Mock,
|
2024-09-16 15:10:33 -04:00
|
|
|
};
|
2025-02-05 17:53:49 +13:00
|
|
|
let mut exec_state = ExecState::new(&ctx.settings);
|
2025-02-25 16:10:06 +13:00
|
|
|
let result = ctx.run(&program, &mut exec_state).await?;
|
2024-09-16 15:10:33 -04:00
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
Ok((program, result.0, ctx, exec_state))
|
2024-05-23 14:50:22 -05:00
|
|
|
}
|
|
|
|
|
2023-08-24 15:34:51 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use pretty_assertions::assert_eq;
|
|
|
|
|
2023-08-29 14:12:48 -07:00
|
|
|
use super::*;
|
2025-03-05 12:03:32 +13:00
|
|
|
use crate::{errors::KclErrorDetails, execution::memory::Stack, ModuleId};
|
2023-08-24 15:34:51 -07:00
|
|
|
|
2024-08-14 02:38:37 -04:00
|
|
|
/// Convenience function to get a JSON value from memory and unwrap.
|
2024-12-17 09:38:32 +13:00
|
|
|
#[track_caller]
|
2025-03-05 12:03:32 +13:00
|
|
|
fn mem_get_json(memory: &Stack, env: EnvironmentRef, name: &str) -> KclValue {
|
|
|
|
memory
|
|
|
|
.memory
|
|
|
|
.get_from_unchecked(name, env, SourceRange::default())
|
|
|
|
.unwrap()
|
|
|
|
.to_owned()
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|
2025-02-21 09:30:44 +13:00
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_warn() {
|
|
|
|
let text = "@blah";
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, _, _, exec_state) = parse_execute(text).await.unwrap();
|
2025-02-21 09:30:44 +13:00
|
|
|
let errs = exec_state.errors();
|
|
|
|
assert_eq!(errs.len(), 1);
|
|
|
|
assert_eq!(errs[0].severity, crate::errors::Severity::Warning);
|
2025-02-22 20:16:29 +13:00
|
|
|
assert!(
|
|
|
|
errs[0].message.contains("Unknown annotation"),
|
|
|
|
"unexpected warning message: {}",
|
|
|
|
errs[0].message
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_warn_on_deprecated() {
|
|
|
|
let text = "p = pi()";
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, _, _, exec_state) = parse_execute(text).await.unwrap();
|
2025-02-22 20:16:29 +13:00
|
|
|
let errs = exec_state.errors();
|
|
|
|
assert_eq!(errs.len(), 1);
|
|
|
|
assert_eq!(errs[0].severity, crate::errors::Severity::Warning);
|
|
|
|
assert!(
|
|
|
|
errs[0].message.contains("`pi` is deprecated"),
|
|
|
|
"unexpected warning message: {}",
|
|
|
|
errs[0].message
|
|
|
|
);
|
2025-02-21 09:30:44 +13:00
|
|
|
}
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_fn_definitions() {
|
2023-09-13 11:42:09 -07:00
|
|
|
let ast = r#"fn def = (x) => {
|
2023-08-24 15:34:51 -07:00
|
|
|
return x
|
|
|
|
}
|
2023-09-13 11:42:09 -07:00
|
|
|
fn ghi = (x) => {
|
2023-08-24 15:34:51 -07:00
|
|
|
return x
|
|
|
|
}
|
2023-09-13 11:42:09 -07:00
|
|
|
fn jkl = (x) => {
|
2023-08-24 15:34:51 -07:00
|
|
|
return x
|
|
|
|
}
|
2023-09-13 11:42:09 -07:00
|
|
|
fn hmm = (x) => {
|
2023-08-24 15:34:51 -07:00
|
|
|
return x
|
|
|
|
}
|
|
|
|
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
yo = 5 + 6
|
2023-08-24 15:34:51 -07:00
|
|
|
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
abc = 3
|
|
|
|
identifierGuy = 5
|
2025-02-27 15:58:58 +13:00
|
|
|
part001 = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([-1.2, 4.83], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [2.8, 0])
|
2023-08-24 15:34:51 -07:00
|
|
|
|> angledLine([100 + 100, 3.01], %)
|
|
|
|
|> angledLine([abc, 3.02], %)
|
|
|
|
|> angledLine([def(yo), 3.03], %)
|
|
|
|
|> angledLine([ghi(2), 3.04], %)
|
|
|
|
|> angledLine([jkl(yo) + 2, 3.05], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> close()
|
|
|
|
yo2 = hmm([identifierGuy + 5])"#;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_with_pipe_substitutions_unary() {
|
|
|
|
let ast = r#"const myVar = 3
|
2025-02-27 15:58:58 +13:00
|
|
|
const part001 = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0, 0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [3, 4], tag = $seg01)
|
|
|
|
|> line(end = [
|
2024-07-27 22:56:46 -07:00
|
|
|
min(segLen(seg01), myVar),
|
|
|
|
-legLen(segLen(seg01), myVar)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
])
|
2024-03-01 17:16:18 -08:00
|
|
|
"#;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_with_pipe_substitutions() {
|
|
|
|
let ast = r#"const myVar = 3
|
2025-02-27 15:58:58 +13:00
|
|
|
const part001 = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0, 0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [3, 4], tag = $seg01)
|
|
|
|
|> line(end = [
|
2024-07-27 22:56:46 -07:00
|
|
|
min(segLen(seg01), myVar),
|
|
|
|
legLen(segLen(seg01), myVar)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
])
|
2024-03-01 17:16:18 -08:00
|
|
|
"#;
|
2023-09-05 16:02:27 -07:00
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_with_inline_comment() {
|
|
|
|
let ast = r#"const baseThick = 1
|
|
|
|
const armAngle = 60
|
|
|
|
|
|
|
|
const baseThickHalf = baseThick / 2
|
|
|
|
const halfArmAngle = armAngle / 2
|
|
|
|
|
|
|
|
const arrExpShouldNotBeIncluded = [1, 2, 3]
|
|
|
|
const objExpShouldNotBeIncluded = { a: 1, b: 2, c: 3 }
|
|
|
|
|
2025-02-27 15:58:58 +13:00
|
|
|
const part001 = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0, 0], %)
|
2023-09-05 16:02:27 -07:00
|
|
|
|> yLineTo(1, %)
|
|
|
|
|> xLine(3.84, %) // selection-range-7ish-before-this
|
|
|
|
|
|
|
|
const variableBelowShouldNotBeIncluded = 3
|
2024-03-01 17:16:18 -08:00
|
|
|
"#;
|
2023-08-24 15:34:51 -07:00
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
2023-09-11 15:15:37 -07:00
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_with_function_literal_in_pipe() {
|
|
|
|
let ast = r#"const w = 20
|
|
|
|
const l = 8
|
|
|
|
const h = 10
|
|
|
|
|
|
|
|
fn thing = () => {
|
|
|
|
return -8
|
|
|
|
}
|
|
|
|
|
2025-02-27 15:58:58 +13:00
|
|
|
const firstExtrude = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0,0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, l])
|
|
|
|
|> line(end = [w, 0])
|
|
|
|
|> line(end = [0, thing()])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = h)"#;
|
2023-09-11 15:15:37 -07:00
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_with_function_unary_in_pipe() {
|
|
|
|
let ast = r#"const w = 20
|
|
|
|
const l = 8
|
|
|
|
const h = 10
|
|
|
|
|
|
|
|
fn thing = (x) => {
|
|
|
|
return -x
|
|
|
|
}
|
|
|
|
|
2025-02-27 15:58:58 +13:00
|
|
|
const firstExtrude = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0,0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, l])
|
|
|
|
|> line(end = [w, 0])
|
|
|
|
|> line(end = [0, thing(8)])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = h)"#;
|
2023-09-11 15:15:37 -07:00
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_with_function_array_in_pipe() {
|
|
|
|
let ast = r#"const w = 20
|
|
|
|
const l = 8
|
|
|
|
const h = 10
|
|
|
|
|
|
|
|
fn thing = (x) => {
|
|
|
|
return [0, -x]
|
|
|
|
}
|
|
|
|
|
2025-02-27 15:58:58 +13:00
|
|
|
const firstExtrude = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0,0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, l])
|
|
|
|
|> line(end = [w, 0])
|
|
|
|
|> line(end = thing(8))
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = h)"#;
|
2023-09-11 15:15:37 -07:00
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_with_function_call_in_pipe() {
|
|
|
|
let ast = r#"const w = 20
|
|
|
|
const l = 8
|
|
|
|
const h = 10
|
|
|
|
|
|
|
|
fn other_thing = (y) => {
|
|
|
|
return -y
|
|
|
|
}
|
|
|
|
|
|
|
|
fn thing = (x) => {
|
|
|
|
return other_thing(x)
|
|
|
|
}
|
|
|
|
|
2025-02-27 15:58:58 +13:00
|
|
|
const firstExtrude = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0,0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, l])
|
|
|
|
|> line(end = [w, 0])
|
|
|
|
|> line(end = [0, thing(8)])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = h)"#;
|
2023-09-11 15:15:37 -07:00
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_with_function_sketch() {
|
2023-09-13 11:42:09 -07:00
|
|
|
let ast = r#"fn box = (h, l, w) => {
|
2025-02-27 15:58:58 +13:00
|
|
|
const myBox = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0,0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, l])
|
|
|
|
|> line(end = [w, 0])
|
|
|
|
|> line(end = [0, -l])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = h)
|
2023-09-11 15:15:37 -07:00
|
|
|
|
|
|
|
return myBox
|
|
|
|
}
|
|
|
|
|
2024-03-01 17:16:18 -08:00
|
|
|
const fnBox = box(3, 6, 10)"#;
|
2023-09-11 15:15:37 -07:00
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
2023-09-13 07:23:14 -07:00
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_get_member_of_object_with_function_period() {
|
2023-09-13 11:42:09 -07:00
|
|
|
let ast = r#"fn box = (obj) => {
|
2025-02-27 15:58:58 +13:00
|
|
|
let myBox = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt(obj.start, %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, obj.l])
|
|
|
|
|> line(end = [obj.w, 0])
|
|
|
|
|> line(end = [0, -obj.l])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = obj.h)
|
2023-09-13 07:23:14 -07:00
|
|
|
|
|
|
|
return myBox
|
|
|
|
}
|
|
|
|
|
|
|
|
const thisBox = box({start: [0,0], l: 6, w: 10, h: 3})
|
|
|
|
"#;
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_get_member_of_object_with_function_brace() {
|
2023-09-13 11:42:09 -07:00
|
|
|
let ast = r#"fn box = (obj) => {
|
2025-02-27 15:58:58 +13:00
|
|
|
let myBox = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt(obj["start"], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, obj["l"]])
|
|
|
|
|> line(end = [obj["w"], 0])
|
|
|
|
|> line(end = [0, -obj["l"]])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = obj["h"])
|
2023-09-13 07:23:14 -07:00
|
|
|
|
|
|
|
return myBox
|
|
|
|
}
|
|
|
|
|
|
|
|
const thisBox = box({start: [0,0], l: 6, w: 10, h: 3})
|
|
|
|
"#;
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_get_member_of_object_with_function_mix_period_brace() {
|
2023-09-13 11:42:09 -07:00
|
|
|
let ast = r#"fn box = (obj) => {
|
2025-02-27 15:58:58 +13:00
|
|
|
let myBox = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt(obj["start"], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, obj["l"]])
|
|
|
|
|> line(end = [obj["w"], 0])
|
|
|
|
|> line(end = [10 - obj["w"], -obj.l])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = obj["h"])
|
2023-09-13 07:23:14 -07:00
|
|
|
|
|
|
|
return myBox
|
|
|
|
}
|
|
|
|
|
|
|
|
const thisBox = box({start: [0,0], l: 6, w: 10, h: 3})
|
|
|
|
"#;
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
2024-08-13 16:25:09 -04:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
#[ignore] // https://github.com/KittyCAD/modeling-app/issues/3338
|
|
|
|
async fn test_object_member_starting_pipeline() {
|
|
|
|
let ast = r#"
|
|
|
|
fn test2 = () => {
|
|
|
|
return {
|
2025-02-27 15:58:58 +13:00
|
|
|
thing: startSketchOn(XY)
|
2024-08-13 16:25:09 -04:00
|
|
|
|> startProfileAt([0, 0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, 1])
|
|
|
|
|> line(end = [1, 0])
|
|
|
|
|> line(end = [0, -1])
|
|
|
|
|> close()
|
2024-08-13 16:25:09 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const x2 = test2()
|
|
|
|
|
|
|
|
x2.thing
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> extrude(length = 10)
|
2024-08-13 16:25:09 -04:00
|
|
|
"#;
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
2023-09-13 07:23:14 -07:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
#[ignore] // ignore til we get loops
|
|
|
|
async fn test_execute_with_function_sketch_loop_objects() {
|
2023-09-13 11:42:09 -07:00
|
|
|
let ast = r#"fn box = (obj) => {
|
2025-02-27 15:58:58 +13:00
|
|
|
let myBox = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt(obj.start, %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, obj.l])
|
|
|
|
|> line(end = [obj.w, 0])
|
|
|
|
|> line(end = [0, -obj.l])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = obj.h)
|
2023-09-13 07:23:14 -07:00
|
|
|
|
|
|
|
return myBox
|
|
|
|
}
|
|
|
|
|
|
|
|
for var in [{start: [0,0], l: 6, w: 10, h: 3}, {start: [-10,-10], l: 3, w: 5, h: 1.5}] {
|
|
|
|
const thisBox = box(var)
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
#[ignore] // ignore til we get loops
|
|
|
|
async fn test_execute_with_function_sketch_loop_array() {
|
2023-09-13 11:42:09 -07:00
|
|
|
let ast = r#"fn box = (h, l, w, start) => {
|
2025-02-27 15:58:58 +13:00
|
|
|
const myBox = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0,0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, l])
|
|
|
|
|> line(end = [w, 0])
|
|
|
|
|> line(end = [0, -l])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = h)
|
2023-09-13 07:23:14 -07:00
|
|
|
|
|
|
|
return myBox
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for var in [[3, 6, 10, [0,0]], [1.5, 3, 5, [-10,-10]]] {
|
|
|
|
const thisBox = box(var[0], var[1], var[2], var[3])
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_get_member_of_array_with_function() {
|
2024-11-18 19:54:25 -05:00
|
|
|
let ast = r#"fn box = (arr) => {
|
2025-02-27 15:58:58 +13:00
|
|
|
let myBox =startSketchOn(XY)
|
2024-11-18 19:54:25 -05:00
|
|
|
|> startProfileAt(arr[0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, arr[1]])
|
|
|
|
|> line(end = [arr[2], 0])
|
|
|
|
|> line(end = [0, -arr[1]])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = arr[3])
|
2023-09-13 07:23:14 -07:00
|
|
|
|
|
|
|
return myBox
|
|
|
|
}
|
|
|
|
|
|
|
|
const thisBox = box([[0,0], 6, 10, 3])
|
|
|
|
|
|
|
|
"#;
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
2024-07-22 19:43:40 -04:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_function_cannot_access_future_definitions() {
|
|
|
|
let ast = r#"
|
|
|
|
fn returnX = () => {
|
|
|
|
// x shouldn't be defined yet.
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
|
|
|
|
const x = 5
|
|
|
|
|
|
|
|
const answer = returnX()"#;
|
|
|
|
|
|
|
|
let result = parse_execute(ast).await;
|
2025-02-28 17:40:01 -08:00
|
|
|
let err = result.unwrap_err();
|
2024-07-22 19:43:40 -04:00
|
|
|
assert_eq!(
|
|
|
|
err,
|
|
|
|
KclError::UndefinedValue(KclErrorDetails {
|
|
|
|
message: "memory item key `x` is not defined".to_owned(),
|
2024-12-03 16:39:51 +13:00
|
|
|
source_ranges: vec![
|
|
|
|
SourceRange::new(64, 65, ModuleId::default()),
|
|
|
|
SourceRange::new(97, 106, ModuleId::default())
|
|
|
|
],
|
2024-07-22 19:43:40 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2025-02-25 16:10:06 +13:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_override_prelude() {
|
|
|
|
let text = "PI = 3.0";
|
|
|
|
let (_, _, _, exec_state) = parse_execute(text).await.unwrap();
|
|
|
|
let errs = exec_state.errors();
|
|
|
|
assert!(errs.is_empty());
|
|
|
|
}
|
|
|
|
|
2024-12-13 12:10:33 -08:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_cannot_shebang_in_fn() {
|
|
|
|
let ast = r#"
|
|
|
|
fn foo () {
|
|
|
|
#!hello
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
foo
|
|
|
|
"#;
|
|
|
|
|
|
|
|
let result = parse_execute(ast).await;
|
2025-02-28 17:40:01 -08:00
|
|
|
let err = result.unwrap_err();
|
2024-12-13 12:10:33 -08:00
|
|
|
assert_eq!(
|
|
|
|
err,
|
|
|
|
KclError::Syntax(KclErrorDetails {
|
|
|
|
message: "Unexpected token: #".to_owned(),
|
|
|
|
source_ranges: vec![SourceRange::new(15, 16, ModuleId::default())],
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-07-22 19:43:40 -04:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_pattern_transform_function_cannot_access_future_definitions() {
|
|
|
|
let ast = r#"
|
|
|
|
fn transform = (replicaId) => {
|
|
|
|
// x shouldn't be defined yet.
|
|
|
|
let scale = x
|
|
|
|
return {
|
|
|
|
translate: [0, 0, replicaId * 10],
|
|
|
|
scale: [scale, 1, 0],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn layer = () => {
|
2025-02-27 15:58:58 +13:00
|
|
|
return startSketchOn(XY)
|
2025-02-28 17:40:01 -08:00
|
|
|
|> circle( center= [0, 0], radius= 1 , tag =$tag1)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> extrude(length = 10)
|
2024-07-22 19:43:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
const x = 5
|
|
|
|
|
|
|
|
// The 10 layers are replicas of each other, with a transform applied to each.
|
2025-02-12 15:47:02 -06:00
|
|
|
let shape = layer() |> patternTransform(instances = 10, transform = transform)
|
2024-07-22 19:43:40 -04:00
|
|
|
"#;
|
|
|
|
|
|
|
|
let result = parse_execute(ast).await;
|
2025-02-28 17:40:01 -08:00
|
|
|
let err = result.unwrap_err();
|
2024-07-22 19:43:40 -04:00
|
|
|
assert_eq!(
|
|
|
|
err,
|
|
|
|
KclError::UndefinedValue(KclErrorDetails {
|
|
|
|
message: "memory item key `x` is not defined".to_owned(),
|
2024-12-03 16:39:51 +13:00
|
|
|
source_ranges: vec![SourceRange::new(80, 81, ModuleId::default())],
|
2024-07-22 19:43:40 -04:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-11-14 17:27:19 -06:00
|
|
|
// ADAM: Move some of these into simulation tests.
|
2024-07-22 19:43:40 -04:00
|
|
|
|
2023-09-13 07:23:14 -07:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_math_execute_with_functions() {
|
|
|
|
let ast = r#"const myVar = 2 + min(100, -1 + legLen(5, 3))"#;
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
2025-03-05 12:03:32 +13:00
|
|
|
assert_eq!(5.0, mem_get_json(exec_state.stack(), env, "myVar").as_f64().unwrap());
|
2023-09-13 07:23:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_math_execute() {
|
|
|
|
let ast = r#"const myVar = 1 + 2 * (3 - 4) / -5 + 6"#;
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
2025-03-05 12:03:32 +13:00
|
|
|
assert_eq!(7.4, mem_get_json(exec_state.stack(), env, "myVar").as_f64().unwrap());
|
2023-09-13 07:23:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_math_execute_start_negative() {
|
|
|
|
let ast = r#"const myVar = -5 + 6"#;
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
2025-03-05 12:03:32 +13:00
|
|
|
assert_eq!(1.0, mem_get_json(exec_state.stack(), env, "myVar").as_f64().unwrap());
|
2023-09-13 07:23:14 -07:00
|
|
|
}
|
2023-09-13 13:10:55 -07:00
|
|
|
|
2023-09-19 16:05:53 -07:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_math_execute_with_pi() {
|
2025-02-20 19:33:21 +13:00
|
|
|
let ast = r#"const myVar = PI * 2"#;
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
2024-12-10 18:50:22 -08:00
|
|
|
assert_eq!(
|
|
|
|
std::f64::consts::TAU,
|
2025-03-05 12:03:32 +13:00
|
|
|
mem_get_json(exec_state.stack(), env, "myVar").as_f64().unwrap()
|
2024-12-10 18:50:22 -08:00
|
|
|
);
|
2023-09-19 16:05:53 -07:00
|
|
|
}
|
|
|
|
|
2023-09-13 13:10:55 -07:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_math_define_decimal_without_leading_zero() {
|
|
|
|
let ast = r#"let thing = .4 + 7"#;
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
2025-03-05 12:03:32 +13:00
|
|
|
assert_eq!(7.4, mem_get_json(exec_state.stack(), env, "thing").as_f64().unwrap());
|
2023-09-13 13:10:55 -07:00
|
|
|
}
|
2023-09-15 13:19:53 -07:00
|
|
|
|
2025-01-17 07:55:01 +13:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_unit_default() {
|
|
|
|
let ast = r#"const inMm = 25.4 * mm()
|
|
|
|
const inInches = 1.0 * inch()"#;
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
2025-03-05 12:03:32 +13:00
|
|
|
assert_eq!(25.4, mem_get_json(exec_state.stack(), env, "inMm").as_f64().unwrap());
|
2025-02-25 16:10:06 +13:00
|
|
|
assert_eq!(
|
|
|
|
25.4,
|
2025-03-05 12:03:32 +13:00
|
|
|
mem_get_json(exec_state.stack(), env, "inInches").as_f64().unwrap()
|
2025-02-25 16:10:06 +13:00
|
|
|
);
|
2025-01-17 07:55:01 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_unit_overriden() {
|
|
|
|
let ast = r#"@settings(defaultLengthUnit = inch)
|
|
|
|
const inMm = 25.4 * mm()
|
|
|
|
const inInches = 1.0 * inch()"#;
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
1.0,
|
2025-03-05 12:03:32 +13:00
|
|
|
mem_get_json(exec_state.stack(), env, "inMm").as_f64().unwrap().round()
|
2025-02-25 16:10:06 +13:00
|
|
|
);
|
2025-03-05 12:03:32 +13:00
|
|
|
assert_eq!(1.0, mem_get_json(exec_state.stack(), env, "inInches").as_f64().unwrap());
|
2025-01-17 07:55:01 +13:00
|
|
|
}
|
|
|
|
|
2025-01-28 17:09:27 -08:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_unit_overriden_in() {
|
|
|
|
let ast = r#"@settings(defaultLengthUnit = in)
|
|
|
|
const inMm = 25.4 * mm()
|
|
|
|
const inInches = 2.0 * inch()"#;
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
1.0,
|
2025-03-05 12:03:32 +13:00
|
|
|
mem_get_json(exec_state.stack(), env, "inMm").as_f64().unwrap().round()
|
2025-02-25 16:10:06 +13:00
|
|
|
);
|
2025-03-05 12:03:32 +13:00
|
|
|
assert_eq!(2.0, mem_get_json(exec_state.stack(), env, "inInches").as_f64().unwrap());
|
2025-01-28 17:09:27 -08:00
|
|
|
}
|
|
|
|
|
2023-09-20 10:51:49 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_zero_param_fn() {
|
|
|
|
let ast = r#"const sigmaAllow = 35000 // psi
|
|
|
|
const leg1 = 5 // inches
|
|
|
|
const leg2 = 8 // inches
|
|
|
|
fn thickness = () => { return 0.56 }
|
|
|
|
|
2025-02-27 15:58:58 +13:00
|
|
|
const bracket = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0,0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, leg1])
|
|
|
|
|> line(end = [leg2, 0])
|
|
|
|
|> line(end = [0, -thickness()])
|
|
|
|
|> line(end = [-leg2 + thickness(), 0])
|
2023-09-20 10:51:49 -05:00
|
|
|
"#;
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
2024-08-14 02:38:37 -04:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_unary_operator_not_succeeds() {
|
|
|
|
let ast = r#"
|
|
|
|
fn returnTrue = () => { return !false }
|
|
|
|
const t = true
|
|
|
|
const f = false
|
|
|
|
let notTrue = !t
|
|
|
|
let notFalse = !f
|
|
|
|
let c = !!true
|
|
|
|
let d = !returnTrue()
|
|
|
|
|
|
|
|
assert(!false, "expected to pass")
|
|
|
|
|
|
|
|
fn check = (x) => {
|
|
|
|
assert(!x, "expected argument to be false")
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
check(false)
|
|
|
|
"#;
|
2025-02-25 16:10:06 +13:00
|
|
|
let (_, env, _, exec_state) = parse_execute(ast).await.unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
false,
|
2025-03-05 12:03:32 +13:00
|
|
|
mem_get_json(exec_state.stack(), env, "notTrue").as_bool().unwrap()
|
2025-02-25 16:10:06 +13:00
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
true,
|
2025-03-05 12:03:32 +13:00
|
|
|
mem_get_json(exec_state.stack(), env, "notFalse").as_bool().unwrap()
|
2025-02-25 16:10:06 +13:00
|
|
|
);
|
2025-03-05 12:03:32 +13:00
|
|
|
assert_eq!(true, mem_get_json(exec_state.stack(), env, "c").as_bool().unwrap());
|
|
|
|
assert_eq!(false, mem_get_json(exec_state.stack(), env, "d").as_bool().unwrap());
|
2024-08-14 02:38:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_unary_operator_not_on_non_bool_fails() {
|
|
|
|
let code1 = r#"
|
|
|
|
// Yup, this is null.
|
|
|
|
let myNull = 0 / 0
|
|
|
|
let notNull = !myNull
|
|
|
|
"#;
|
|
|
|
assert_eq!(
|
2025-02-28 17:40:01 -08:00
|
|
|
parse_execute(code1).await.unwrap_err(),
|
2024-08-14 02:38:37 -04:00
|
|
|
KclError::Semantic(KclErrorDetails {
|
2024-11-14 17:27:19 -06:00
|
|
|
message: "Cannot apply unary operator ! to non-boolean value: number".to_owned(),
|
2024-12-03 16:39:51 +13:00
|
|
|
source_ranges: vec![SourceRange::new(56, 63, ModuleId::default())],
|
2024-08-14 02:38:37 -04:00
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
let code2 = "let notZero = !0";
|
|
|
|
assert_eq!(
|
2025-02-28 17:40:01 -08:00
|
|
|
parse_execute(code2).await.unwrap_err(),
|
2024-08-14 02:38:37 -04:00
|
|
|
KclError::Semantic(KclErrorDetails {
|
2024-11-25 10:50:43 +13:00
|
|
|
message: "Cannot apply unary operator ! to non-boolean value: number".to_owned(),
|
2024-12-03 16:39:51 +13:00
|
|
|
source_ranges: vec![SourceRange::new(14, 16, ModuleId::default())],
|
2024-08-14 02:38:37 -04:00
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
let code3 = r#"
|
|
|
|
let notEmptyString = !""
|
|
|
|
"#;
|
|
|
|
assert_eq!(
|
2025-02-28 17:40:01 -08:00
|
|
|
parse_execute(code3).await.unwrap_err(),
|
2024-08-14 02:38:37 -04:00
|
|
|
KclError::Semantic(KclErrorDetails {
|
2024-11-14 17:27:19 -06:00
|
|
|
message: "Cannot apply unary operator ! to non-boolean value: string (text)".to_owned(),
|
2024-12-03 16:39:51 +13:00
|
|
|
source_ranges: vec![SourceRange::new(22, 25, ModuleId::default())],
|
2024-08-14 02:38:37 -04:00
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
let code4 = r#"
|
|
|
|
let obj = { a: 1 }
|
|
|
|
let notMember = !obj.a
|
|
|
|
"#;
|
|
|
|
assert_eq!(
|
2025-02-28 17:40:01 -08:00
|
|
|
parse_execute(code4).await.unwrap_err(),
|
2024-08-14 02:38:37 -04:00
|
|
|
KclError::Semantic(KclErrorDetails {
|
2024-11-25 10:50:43 +13:00
|
|
|
message: "Cannot apply unary operator ! to non-boolean value: number".to_owned(),
|
2024-12-03 16:39:51 +13:00
|
|
|
source_ranges: vec![SourceRange::new(36, 42, ModuleId::default())],
|
2024-08-14 02:38:37 -04:00
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
let code5 = "
|
|
|
|
let a = []
|
|
|
|
let notArray = !a";
|
|
|
|
assert_eq!(
|
2025-02-28 17:40:01 -08:00
|
|
|
parse_execute(code5).await.unwrap_err(),
|
2024-08-14 02:38:37 -04:00
|
|
|
KclError::Semantic(KclErrorDetails {
|
2024-11-14 17:27:19 -06:00
|
|
|
message: "Cannot apply unary operator ! to non-boolean value: array (list)".to_owned(),
|
2024-12-03 16:39:51 +13:00
|
|
|
source_ranges: vec![SourceRange::new(27, 29, ModuleId::default())],
|
2024-08-14 02:38:37 -04:00
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
let code6 = "
|
|
|
|
let x = {}
|
|
|
|
let notObject = !x";
|
|
|
|
assert_eq!(
|
2025-02-28 17:40:01 -08:00
|
|
|
parse_execute(code6).await.unwrap_err(),
|
2024-08-14 02:38:37 -04:00
|
|
|
KclError::Semantic(KclErrorDetails {
|
2024-11-14 17:27:19 -06:00
|
|
|
message: "Cannot apply unary operator ! to non-boolean value: object".to_owned(),
|
2024-12-03 16:39:51 +13:00
|
|
|
source_ranges: vec![SourceRange::new(28, 30, ModuleId::default())],
|
2024-08-14 02:38:37 -04:00
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
let code7 = "
|
|
|
|
fn x = () => { return 1 }
|
|
|
|
let notFunction = !x";
|
2025-02-28 17:40:01 -08:00
|
|
|
let fn_err = parse_execute(code7).await.unwrap_err();
|
2024-08-14 02:38:37 -04:00
|
|
|
// These are currently printed out as JSON objects, so we don't want to
|
|
|
|
// check the full error.
|
|
|
|
assert!(
|
|
|
|
fn_err
|
|
|
|
.message()
|
|
|
|
.starts_with("Cannot apply unary operator ! to non-boolean value: "),
|
|
|
|
"Actual error: {:?}",
|
|
|
|
fn_err
|
|
|
|
);
|
|
|
|
|
|
|
|
let code8 = "
|
|
|
|
let myTagDeclarator = $myTag
|
|
|
|
let notTagDeclarator = !myTagDeclarator";
|
2025-02-28 17:40:01 -08:00
|
|
|
let tag_declarator_err = parse_execute(code8).await.unwrap_err();
|
2024-08-14 02:38:37 -04:00
|
|
|
// These are currently printed out as JSON objects, so we don't want to
|
|
|
|
// check the full error.
|
|
|
|
assert!(
|
|
|
|
tag_declarator_err
|
|
|
|
.message()
|
2024-11-14 17:27:19 -06:00
|
|
|
.starts_with("Cannot apply unary operator ! to non-boolean value: TagDeclarator"),
|
2024-08-14 02:38:37 -04:00
|
|
|
"Actual error: {:?}",
|
|
|
|
tag_declarator_err
|
|
|
|
);
|
|
|
|
|
|
|
|
let code9 = "
|
2024-12-13 16:39:40 -05:00
|
|
|
let myTagDeclarator = $myTag
|
|
|
|
let notTagIdentifier = !myTag";
|
2025-02-28 17:40:01 -08:00
|
|
|
let tag_identifier_err = parse_execute(code9).await.unwrap_err();
|
2024-08-14 02:38:37 -04:00
|
|
|
// These are currently printed out as JSON objects, so we don't want to
|
|
|
|
// check the full error.
|
|
|
|
assert!(
|
|
|
|
tag_identifier_err
|
|
|
|
.message()
|
2024-11-14 17:27:19 -06:00
|
|
|
.starts_with("Cannot apply unary operator ! to non-boolean value: TagIdentifier"),
|
2024-08-14 02:38:37 -04:00
|
|
|
"Actual error: {:?}",
|
|
|
|
tag_identifier_err
|
|
|
|
);
|
|
|
|
|
|
|
|
let code10 = "let notPipe = !(1 |> 2)";
|
|
|
|
assert_eq!(
|
|
|
|
// TODO: We don't currently parse this, but we should. It should be
|
|
|
|
// a runtime error instead.
|
2025-02-28 17:40:01 -08:00
|
|
|
parse_execute(code10).await.unwrap_err(),
|
2024-08-14 02:38:37 -04:00
|
|
|
KclError::Syntax(KclErrorDetails {
|
2024-08-20 23:49:19 -04:00
|
|
|
message: "Unexpected token: !".to_owned(),
|
2024-12-03 16:39:51 +13:00
|
|
|
source_ranges: vec![SourceRange::new(14, 15, ModuleId::default())],
|
2024-08-14 02:38:37 -04:00
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
let code11 = "
|
|
|
|
fn identity = (x) => { return x }
|
|
|
|
let notPipeSub = 1 |> identity(!%))";
|
|
|
|
assert_eq!(
|
|
|
|
// TODO: We don't currently parse this, but we should. It should be
|
|
|
|
// a runtime error instead.
|
2025-02-28 17:40:01 -08:00
|
|
|
parse_execute(code11).await.unwrap_err(),
|
2024-08-14 02:38:37 -04:00
|
|
|
KclError::Syntax(KclErrorDetails {
|
2024-08-20 23:49:19 -04:00
|
|
|
message: "Unexpected token: |>".to_owned(),
|
2024-12-03 16:39:51 +13:00
|
|
|
source_ranges: vec![SourceRange::new(54, 56, ModuleId::default())],
|
2024-08-14 02:38:37 -04:00
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
// TODO: Add these tests when we support these types.
|
|
|
|
// let notNan = !NaN
|
|
|
|
// let notInfinity = !Infinity
|
|
|
|
}
|
|
|
|
|
2023-09-15 13:19:53 -07:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_math_negative_variable_in_binary_expression() {
|
|
|
|
let ast = r#"const sigmaAllow = 35000 // psi
|
|
|
|
const width = 1 // inch
|
|
|
|
|
|
|
|
const p = 150 // lbs
|
|
|
|
const distance = 6 // inches
|
|
|
|
const FOS = 2
|
|
|
|
|
|
|
|
const leg1 = 5 // inches
|
|
|
|
const leg2 = 8 // inches
|
|
|
|
|
|
|
|
const thickness_squared = distance * p * FOS * 6 / sigmaAllow
|
|
|
|
const thickness = 0.56 // inches. App does not support square root function yet
|
|
|
|
|
2025-02-27 15:58:58 +13:00
|
|
|
const bracket = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0,0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, leg1])
|
|
|
|
|> line(end = [leg2, 0])
|
|
|
|
|> line(end = [0, -thickness])
|
|
|
|
|> line(end = [-leg2 + thickness, 0])
|
2023-09-15 17:40:57 -07:00
|
|
|
"#;
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
2024-08-01 19:40:22 -07:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_execute_function_no_return() {
|
|
|
|
let ast = r#"fn test = (origin) => {
|
|
|
|
origin
|
|
|
|
}
|
|
|
|
|
|
|
|
test([0, 0])
|
|
|
|
"#;
|
|
|
|
let result = parse_execute(ast).await;
|
|
|
|
assert!(result.is_err());
|
2025-02-22 20:16:29 +13:00
|
|
|
assert!(result.unwrap_err().to_string().contains("undefined"),);
|
2024-08-01 19:40:22 -07:00
|
|
|
}
|
|
|
|
|
2023-09-15 17:40:57 -07:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_math_doubly_nested_parens() {
|
|
|
|
let ast = r#"const sigmaAllow = 35000 // psi
|
|
|
|
const width = 4 // inch
|
|
|
|
const p = 150 // Force on shelf - lbs
|
|
|
|
const distance = 6 // inches
|
|
|
|
const FOS = 2
|
|
|
|
const leg1 = 5 // inches
|
|
|
|
const leg2 = 8 // inches
|
|
|
|
const thickness_squared = (distance * p * FOS * 6 / (sigmaAllow - width))
|
|
|
|
const thickness = 0.32 // inches. App does not support square root function yet
|
2025-02-27 15:58:58 +13:00
|
|
|
const bracket = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0,0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, leg1])
|
|
|
|
|> line(end = [leg2, 0])
|
|
|
|
|> line(end = [0, -thickness])
|
|
|
|
|> line(end = [-1 * leg2 + thickness, 0])
|
|
|
|
|> line(end = [0, -1 * leg1 + thickness])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = width)
|
2023-09-15 17:40:57 -07:00
|
|
|
"#;
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_math_nested_parens_one_less() {
|
|
|
|
let ast = r#"const sigmaAllow = 35000 // psi
|
|
|
|
const width = 4 // inch
|
|
|
|
const p = 150 // Force on shelf - lbs
|
|
|
|
const distance = 6 // inches
|
|
|
|
const FOS = 2
|
|
|
|
const leg1 = 5 // inches
|
|
|
|
const leg2 = 8 // inches
|
|
|
|
const thickness_squared = distance * p * FOS * 6 / (sigmaAllow - width)
|
|
|
|
const thickness = 0.32 // inches. App does not support square root function yet
|
2025-02-27 15:58:58 +13:00
|
|
|
const bracket = startSketchOn(XY)
|
2023-10-05 14:27:48 -07:00
|
|
|
|> startProfileAt([0,0], %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(end = [0, leg1])
|
|
|
|
|> line(end = [leg2, 0])
|
|
|
|
|> line(end = [0, -thickness])
|
|
|
|
|> line(end = [-1 * leg2 + thickness, 0])
|
|
|
|
|> line(end = [0, -1 * leg1 + thickness])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = width)
|
2023-09-15 13:19:53 -07:00
|
|
|
"#;
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
Remove just one enum (#1096)
# Problem
This is my proposal for fixing #1107 . I've only done it for one stdlib function, `tangentialArcTo` -- if y'all like it, I'll apply this idea to the rest of the stdlib.
Previously, if users want to put a tag on the arc, the function's parameters change type.
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is object
tangentialArcTo({to: [x, y], tag: "myTag"}, %)
```
# Solution
My proposal in #1006 is that KCL should have optional values. This means we can change the stdlib `tangentialArcTo` function to use them. In this PR, the calls are now like
```
// Tag missing: first param is array
tangentialArcTo([x, y], %)
// Tag present: first param is array still, but we now pass a tag at the end.
tangentialArcTo([x, y], %, "myTag")
```
This adds an "option" type to KCL typesystem, but it's not really revealed to users (no KCL types are revealed to users right now, they write untyped code and only interact with types when they get type errors upon executing programs). Also adds a None type, which is the default case of the Optional enum.
2023-12-18 23:49:32 -06:00
|
|
|
|
2024-07-29 00:33:31 -07:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn test_fn_as_operand() {
|
|
|
|
let ast = r#"fn f = () => { return 1 }
|
|
|
|
let x = f()
|
|
|
|
let y = x + 1
|
|
|
|
let z = f() + 1
|
|
|
|
let w = f() + f()
|
|
|
|
"#;
|
|
|
|
parse_execute(ast).await.unwrap();
|
|
|
|
}
|
|
|
|
|
2024-02-11 15:08:54 -08:00
|
|
|
#[test]
|
|
|
|
fn test_serialize_memory_item() {
|
2024-09-27 15:44:44 -07:00
|
|
|
let mem = KclValue::Solids {
|
2024-02-11 15:08:54 -08:00
|
|
|
value: Default::default(),
|
|
|
|
};
|
|
|
|
let json = serde_json::to_string(&mem).unwrap();
|
2024-09-27 15:44:44 -07:00
|
|
|
assert_eq!(json, r#"{"type":"Solids","value":[]}"#);
|
2024-02-11 15:08:54 -08:00
|
|
|
}
|
2024-12-10 18:50:22 -08:00
|
|
|
|
2024-12-17 09:38:32 +13:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn kcl_test_ids_stable_between_executions() {
|
2025-02-27 15:58:58 +13:00
|
|
|
let code = r#"sketch001 = startSketchOn(XZ)
|
2024-12-17 09:38:32 +13:00
|
|
|
|> startProfileAt([61.74, 206.13], %)
|
|
|
|
|> xLine(305.11, %, $seg01)
|
|
|
|
|> yLine(-291.85, %)
|
|
|
|
|> xLine(-segLen(seg01), %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = 40.14)
|
2025-02-06 20:03:12 -06:00
|
|
|
|> shell(
|
|
|
|
thickness = 3.14,
|
|
|
|
faces = [seg01]
|
|
|
|
)
|
2024-12-17 09:38:32 +13:00
|
|
|
"#;
|
|
|
|
|
|
|
|
let ctx = crate::test_server::new_context(UnitLength::Mm, true, None)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
let old_program = crate::Program::parse_no_errs(code).unwrap();
|
2025-02-05 17:53:49 +13:00
|
|
|
|
2024-12-17 09:38:32 +13:00
|
|
|
// Execute the program.
|
2025-02-05 17:53:49 +13:00
|
|
|
ctx.run_with_caching(old_program).await.unwrap();
|
2024-12-17 09:38:32 +13:00
|
|
|
|
|
|
|
// Get the id_generator from the first execution.
|
2025-02-12 10:22:56 +13:00
|
|
|
let id_generator = cache::read_old_ast().await.unwrap().exec_state.global.id_generator;
|
2024-12-17 09:38:32 +13:00
|
|
|
|
2025-02-27 15:58:58 +13:00
|
|
|
let code = r#"sketch001 = startSketchOn(XZ)
|
2024-12-17 09:38:32 +13:00
|
|
|
|> startProfileAt([62.74, 206.13], %)
|
|
|
|
|> xLine(305.11, %, $seg01)
|
|
|
|
|> yLine(-291.85, %)
|
|
|
|
|> xLine(-segLen(seg01), %)
|
KCL: Use keyword arguments for line, lineTo, extrude and close (#5249)
Part of #4600.
PR: https://github.com/KittyCAD/modeling-app/pull/4826
# Changes to KCL stdlib
- `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)`
- `close(sketch, tag?)` is now `close(@sketch, tag?)`
- `extrude(length, sketch)` is now `extrude(@sketch, length)`
Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this:
```
sketch = startSketchAt([0, 0])
line(sketch, end = [3, 3], tag = $hi)
```
Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as
```
sketch = startSketchAt([0, 0])
|> line(end = [3, 3], tag = $hi)
```
Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main
The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are:
```
line\(([^=]*), %\)
line(end = $1)
line\((.*), %, (.*)\)
line(end = $1, tag = $2)
lineTo\((.*), %\)
line(endAbsolute = $1)
lineTo\((.*), %, (.*)\)
line(endAbsolute = $1, tag = $2)
extrude\((.*), %\)
extrude(length = $1)
extrude\(([^=]*), ([a-zA-Z0-9]+)\)
extrude($2, length = $1)
close\(%, (.*)\)
close(tag = $1)
```
# Selected notes from commits before I squash them all
* Fix test 'yRelative to horizontal distance'
Fixes:
- Make a lineTo helper
- Fix pathToNode to go through the labeled arg .arg property
* Fix test by changing lookups into transformMap
Parts of the code assumed that `line` is always a relative call. But
actually now it might be absolute, if it's got an `endAbsolute` parameter.
So, change whether to look up `line` or `lineTo` and the relevant absolute
or relative line types based on that parameter.
* Stop asserting on exact source ranges
When I changed line to kwargs, all the source ranges we assert on became
slightly different. I find these assertions to be very very low value.
So I'm removing them.
* Fix more tests: getConstraintType calls weren't checking if the
'line' fn was absolute or relative.
* Fixed another queryAst test
There were 2 problems:
- Test was looking for the old style of `line` call to choose an offset
for pathToNode
- Test assumed that the `tag` param was always the third one, but in
a kwarg call, you have to look it up by label
* Fix test: traverse was not handling CallExpressionKw
* Fix another test, addTagKw
addTag helper was not aware of kw args.
* Convert close from positional to kwargs
If the close() call has 0 args, or a single unlabeled arg, the parser
interprets it as a CallExpression (positional) not a CallExpressionKw.
But then if a codemod wants to add a tag to it, it tries adding a kwarg
called 'tag', which fails because the CallExpression doesn't need
kwargs inserted into it.
The fix is: change the node from CallExpression to CallExpressionKw, and
update getNodeFromPath to take a 'replacement' arg, so we can replace
the old node with the new node in the AST.
* Fix the last test
Test was looking for `lineTo` as a substring of the input KCL program.
But there's no more lineTo function, so I changed it to look for
line() with an endAbsolute arg, which is the new equivalent.
Also changed the getConstraintInfo code to look up the lineTo if using
line with endAbsolute.
* Fix many bad regex find-replaces
I wrote a regex find-and-replace which converted `line` calls from
positional to keyword calls. But it was accidentally applied to more
places than it should be, for example, angledLine, xLine and yLine calls.
Fixes this.
* Fixes test 'Basic sketch › code pane closed at start'
Problem was, the getNodeFromPath call might not actually find a callExpressionKw,
it might find a callExpression. So the `giveSketchFnCallTag` thought
it was modifying a kwargs call, but it was actually modifying a positional
call.
This meant it tried to push a labeled argument in, rather than a normal
arg, and a lot of other problems. Fixed by doing runtime typechecking.
* Fix: Optional args given with wrong type were silently ignored
Optional args don't have to be given. But if the user gives them, they
should be the right type.
Bug: if the KCL interpreter found an optional arg, which was given, but
was the wrong type, it would ignore it and pretend the arg was never
given at all. This was confusing for users.
Fix: Now if you give an optional arg, but it's the wrong type, KCL will
emit a type error just like it would for a mandatory argument.
---------
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@kittycad.io>
Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-02-04 08:31:43 -06:00
|
|
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = 40.14)
|
2025-02-06 20:03:12 -06:00
|
|
|
|> shell(
|
|
|
|
faces = [seg01],
|
|
|
|
thickness = 3.14,
|
|
|
|
)
|
2024-12-17 09:38:32 +13:00
|
|
|
"#;
|
|
|
|
|
|
|
|
// Execute a slightly different program again.
|
2025-02-05 17:53:49 +13:00
|
|
|
let program = crate::Program::parse_no_errs(code).unwrap();
|
2024-12-17 09:38:32 +13:00
|
|
|
// Execute the program.
|
2025-02-05 17:53:49 +13:00
|
|
|
ctx.run_with_caching(program).await.unwrap();
|
|
|
|
|
2025-02-12 10:22:56 +13:00
|
|
|
let new_id_generator = cache::read_old_ast().await.unwrap().exec_state.global.id_generator;
|
2024-12-17 09:38:32 +13:00
|
|
|
|
2025-02-05 17:53:49 +13:00
|
|
|
assert_eq!(id_generator, new_id_generator);
|
2024-12-17 09:38:32 +13:00
|
|
|
}
|
2025-02-20 22:08:49 -08:00
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn kcl_test_changing_a_setting_updates_the_cached_state() {
|
|
|
|
let code = r#"sketch001 = startSketchOn('XZ')
|
|
|
|
|> startProfileAt([61.74, 206.13], %)
|
|
|
|
|> xLine(305.11, %, $seg01)
|
|
|
|
|> yLine(-291.85, %)
|
|
|
|
|> xLine(-segLen(seg01), %)
|
|
|
|
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
|
|
|> close()
|
|
|
|
|> extrude(length = 40.14)
|
|
|
|
|> shell(
|
|
|
|
thickness = 3.14,
|
|
|
|
faces = [seg01]
|
|
|
|
)
|
|
|
|
"#;
|
|
|
|
|
|
|
|
let mut ctx = crate::test_server::new_context(UnitLength::Mm, true, None)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
let old_program = crate::Program::parse_no_errs(code).unwrap();
|
|
|
|
|
|
|
|
// Execute the program.
|
|
|
|
ctx.run_with_caching(old_program.clone()).await.unwrap();
|
|
|
|
|
|
|
|
// Get the id_generator from the first execution.
|
|
|
|
let settings_state = cache::read_old_ast().await.unwrap().settings;
|
|
|
|
|
|
|
|
// Ensure the settings are as expected.
|
|
|
|
assert_eq!(settings_state, ctx.settings);
|
|
|
|
|
|
|
|
// Change a setting.
|
|
|
|
ctx.settings.highlight_edges = !ctx.settings.highlight_edges;
|
|
|
|
|
|
|
|
// Execute the program.
|
|
|
|
ctx.run_with_caching(old_program.clone()).await.unwrap();
|
|
|
|
|
|
|
|
// Get the id_generator from the first execution.
|
|
|
|
let settings_state = cache::read_old_ast().await.unwrap().settings;
|
|
|
|
|
|
|
|
// Ensure the settings are as expected.
|
|
|
|
assert_eq!(settings_state, ctx.settings);
|
|
|
|
|
|
|
|
// Change a setting.
|
|
|
|
ctx.settings.highlight_edges = !ctx.settings.highlight_edges;
|
|
|
|
|
|
|
|
// Execute the program.
|
|
|
|
ctx.run_with_caching(old_program).await.unwrap();
|
|
|
|
|
|
|
|
// Get the id_generator from the first execution.
|
|
|
|
let settings_state = cache::read_old_ast().await.unwrap().settings;
|
|
|
|
|
|
|
|
// Ensure the settings are as expected.
|
|
|
|
assert_eq!(settings_state, ctx.settings);
|
|
|
|
}
|
2025-02-25 16:10:06 +13:00
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
async fn mock_after_not_mock() {
|
|
|
|
let ctx = ExecutorContext::new_with_default_client(UnitLength::Mm).await.unwrap();
|
|
|
|
let program = crate::Program::parse_no_errs("x = 2").unwrap();
|
|
|
|
let result = ctx.run_with_caching(program).await.unwrap();
|
|
|
|
assert_eq!(result.variables.get("x").unwrap().as_f64().unwrap(), 2.0);
|
|
|
|
|
|
|
|
let ctx2 = ExecutorContext::new_mock().await;
|
|
|
|
let program2 = crate::Program::parse_no_errs("z = x + 1").unwrap();
|
2025-03-08 04:04:57 +13:00
|
|
|
let result = ctx2.run_mock(program2, true).await.unwrap();
|
2025-02-25 16:10:06 +13:00
|
|
|
assert_eq!(result.variables.get("z").unwrap().as_f64().unwrap(), 3.0);
|
|
|
|
}
|
2023-08-24 15:34:51 -07:00
|
|
|
}
|