Merge remote-tracking branch 'origin/main' into ben/conics

This commit is contained in:
benjamaan476
2025-06-06 10:25:09 +01:00
435 changed files with 74399 additions and 9225 deletions

View File

@ -173,7 +173,11 @@ fn generate_example(index: usize, src: &str, props: &ExampleProperties, file_nam
return None;
}
let content = if props.inline { "" } else { src };
let content = if props.inline {
String::new()
} else {
crate::unparser::fmt(src).unwrap()
};
let image_base64 = if props.norun {
String::new()

View File

@ -676,7 +676,7 @@ impl EdgeCut {
#[serde(rename_all = "camelCase")]
pub struct ArtifactGraph {
map: IndexMap<ArtifactId, Artifact>,
item_count: usize,
pub(super) item_count: usize,
}
impl ArtifactGraph {

View File

@ -1,13 +1,12 @@
use indexmap::IndexMap;
use schemars::JsonSchema;
use serde::Serialize;
use super::{types::NumericType, ArtifactId, KclValue};
use crate::{ModuleId, SourceRange};
use crate::{ModuleId, NodePath, SourceRange};
/// A CAD modeling operation for display in the feature tree, AKA operations
/// timeline.
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(tag = "type")]
pub enum Operation {
@ -18,6 +17,8 @@ pub enum Operation {
unlabeled_arg: Option<OpArg>,
/// The labeled keyword arguments to the function.
labeled_args: IndexMap<String, OpArg>,
/// The node path of the operation in the source code.
node_path: NodePath,
/// The source range of the operation in the source code.
source_range: SourceRange,
/// True if the operation resulted in an error.
@ -28,6 +29,8 @@ pub enum Operation {
GroupBegin {
/// The details of the group.
group: Group,
/// The node path of the operation in the source code.
node_path: NodePath,
/// The source range of the operation in the source code.
source_range: SourceRange,
},
@ -64,7 +67,7 @@ impl Operation {
}
}
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(tag = "type")]
#[expect(clippy::large_enum_variant)]
@ -95,7 +98,7 @@ pub enum Group {
}
/// An argument to a CAD modeling operation.
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(rename_all = "camelCase")]
pub struct OpArg {
@ -119,7 +122,7 @@ fn is_false(b: &bool) -> bool {
/// A KCL value used in Operations. `ArtifactId`s are used to refer to the
/// actual scene objects. Any data not needed in the UI may be omitted.
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(tag = "type")]
pub enum OpKclValue {
@ -177,21 +180,21 @@ pub enum OpKclValue {
pub type OpKclObjectFields = IndexMap<String, OpKclValue>;
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(rename_all = "camelCase")]
pub struct OpSketch {
artifact_id: ArtifactId,
}
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(rename_all = "camelCase")]
pub struct OpSolid {
artifact_id: ArtifactId,
}
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
#[ts(export_to = "Operation.ts")]
#[serde(rename_all = "camelCase")]
pub struct OpHelix {

View File

@ -19,8 +19,8 @@ use crate::{
parsing::ast::types::{
Annotation, ArrayExpression, ArrayRangeExpression, AscribedExpression, BinaryExpression, BinaryOperator,
BinaryPart, BodyItem, Expr, IfExpression, ImportPath, ImportSelector, ItemVisibility, LiteralIdentifier,
LiteralValue, MemberExpression, MemberObject, Name, Node, NodeRef, ObjectExpression, PipeExpression, Program,
TagDeclarator, Type, UnaryExpression, UnaryOperator,
LiteralValue, MemberExpression, Name, Node, NodeRef, ObjectExpression, PipeExpression, Program, TagDeclarator,
Type, UnaryExpression, UnaryOperator,
},
source_range::SourceRange,
std::args::TyF64,
@ -307,7 +307,7 @@ impl ExecutorContext {
// During the evaluation of the variable's RHS, set context that this is all happening inside a variable
// declaration, for the given name. This helps improve user-facing error messages.
let lhs = variable_declaration.inner.name().to_owned();
let prev_being_declared = exec_state.mod_local.being_declared.clone();
let prev_being_declared = exec_state.mod_local.being_declared.take();
exec_state.mod_local.being_declared = Some(lhs);
let rhs_result = self
.execute_expr(
@ -739,7 +739,7 @@ impl ExecutorContext {
Expr::ArrayExpression(array_expression) => array_expression.execute(exec_state, self).await?,
Expr::ArrayRangeExpression(range_expression) => range_expression.execute(exec_state, self).await?,
Expr::ObjectExpression(object_expression) => object_expression.execute(exec_state, self).await?,
Expr::MemberExpression(member_expression) => member_expression.get_result(exec_state)?,
Expr::MemberExpression(member_expression) => member_expression.get_result(exec_state, self).await?,
Expr::UnaryExpression(unary_expression) => unary_expression.get_result(exec_state, self).await?,
Expr::IfExpression(expr) => expr.get_result(exec_state, self).await?,
Expr::LabelledExpression(expr) => {
@ -825,7 +825,7 @@ impl BinaryPart {
BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_result(exec_state, ctx).await,
BinaryPart::CallExpressionKw(call_expression) => call_expression.execute(exec_state, ctx).await,
BinaryPart::UnaryExpression(unary_expression) => unary_expression.get_result(exec_state, ctx).await,
BinaryPart::MemberExpression(member_expression) => member_expression.get_result(exec_state),
BinaryPart::MemberExpression(member_expression) => member_expression.get_result(exec_state, ctx).await,
BinaryPart::IfExpression(e) => e.get_result(exec_state, ctx).await,
BinaryPart::AscribedExpression(e) => e.get_result(exec_state, ctx).await,
}
@ -942,16 +942,14 @@ impl Node<Name> {
}
impl Node<MemberExpression> {
fn get_result(&self, exec_state: &mut ExecState) -> Result<KclValue, KclError> {
async fn get_result(&self, exec_state: &mut ExecState, ctx: &ExecutorContext) -> Result<KclValue, KclError> {
let property = Property::try_from(self.computed, self.property.clone(), exec_state, self.into())?;
let object = match &self.object {
// TODO: Don't use recursion here, use a loop.
MemberObject::MemberExpression(member_expr) => member_expr.get_result(exec_state)?,
MemberObject::Identifier(identifier) => {
let value = exec_state.stack().get(&identifier.name, identifier.into())?;
value.clone()
}
let meta = Metadata {
source_range: SourceRange::from(self),
};
let object = ctx
.execute_expr(&self.object, exec_state, &meta, &[], StatementKind::Expression)
.await?;
// Check the property and object match -- e.g. ints for arrays, strs for objects.
match (object, property, self.computed) {

View File

@ -14,7 +14,7 @@ use crate::{
parsing::ast::types::{CallExpressionKw, DefaultParamVal, FunctionExpression, Node, Program, Type},
source_range::SourceRange,
std::StdFn,
CompilationError,
CompilationError, NodePath,
};
#[derive(Debug, Clone)]
@ -322,6 +322,7 @@ impl FunctionDefinition<'_> {
.unlabeled_kw_arg_unconverted()
.map(|arg| OpArg::new(OpKclValue::from(&arg.value), arg.source_range)),
labeled_args: op_labeled_args,
node_path: NodePath::placeholder(),
source_range: callsite,
is_error: false,
})
@ -337,6 +338,7 @@ impl FunctionDefinition<'_> {
.map(|arg| OpArg::new(OpKclValue::from(&arg.1.value), arg.1.source_range)),
labeled_args: op_labeled_args,
},
node_path: NodePath::placeholder(),
source_range: callsite,
});

View File

@ -7,6 +7,7 @@ use anyhow::Result;
pub use artifact::{Artifact, ArtifactCommand, ArtifactGraph, CodeRef, StartSketchOnFace, StartSketchOnPlane};
use cache::GlobalState;
pub use cache::{bust_cache, clear_mem_cache};
#[cfg(feature = "artifact-graph")]
pub use cad_op::{Group, Operation};
pub use geometry::*;
pub use id_generator::IdGenerator;
@ -842,31 +843,14 @@ impl ExecutorContext {
let module_path = module_path.clone();
let source_range = SourceRange::from(import_stmt);
match &module_path {
ModulePath::Main => {
// This should never happen.
}
ModulePath::Local { value, .. } => {
// We only want to display the top-level module imports in
// the Feature Tree, not transitive imports.
if universe_map.contains_key(value) {
exec_state.push_op(Operation::GroupBegin {
group: Group::ModuleInstance {
name: value.file_name().unwrap_or_default(),
module_id,
},
source_range,
});
// Due to concurrent execution, we cannot easily
// group operations by module. So we leave the
// group empty and close it immediately.
exec_state.push_op(Operation::GroupEnd);
}
}
ModulePath::Std { .. } => {
// We don't want to display stdlib in the Feature Tree.
}
}
self.add_import_module_ops(
exec_state,
program,
module_id,
&module_path,
source_range,
&universe_map,
);
let repr = repr.clone();
let exec_state = exec_state.clone();
@ -1009,6 +993,67 @@ impl ExecutorContext {
Ok((universe, root_imports))
}
#[cfg(feature = "artifact-graph")]
fn add_import_module_ops(
&self,
exec_state: &mut ExecState,
program: &crate::Program,
module_id: ModuleId,
module_path: &ModulePath,
source_range: SourceRange,
universe_map: &UniverseMap,
) {
match module_path {
ModulePath::Main => {
// This should never happen.
}
ModulePath::Local { value, .. } => {
// We only want to display the top-level module imports in
// the Feature Tree, not transitive imports.
if universe_map.contains_key(value) {
use crate::NodePath;
let node_path = if source_range.is_top_level_module() {
let cached_body_items = exec_state.global.artifacts.cached_body_items();
NodePath::from_range(&program.ast, cached_body_items, source_range).unwrap_or_default()
} else {
// The frontend doesn't care about paths in
// files other than the top-level module.
NodePath::placeholder()
};
exec_state.push_op(Operation::GroupBegin {
group: Group::ModuleInstance {
name: value.file_name().unwrap_or_default(),
module_id,
},
node_path,
source_range,
});
// Due to concurrent execution, we cannot easily
// group operations by module. So we leave the
// group empty and close it immediately.
exec_state.push_op(Operation::GroupEnd);
}
}
ModulePath::Std { .. } => {
// We don't want to display stdlib in the Feature Tree.
}
}
}
#[cfg(not(feature = "artifact-graph"))]
fn add_import_module_ops(
&self,
_exec_state: &mut ExecState,
_program: &crate::Program,
_module_id: ModuleId,
_module_path: &ModulePath,
_source_range: SourceRange,
_universe_map: &UniverseMap,
) {
}
/// Perform the execution of a program. Accept all possible parameters and
/// output everything.
async fn inner_run(
@ -1059,6 +1104,11 @@ impl ExecutorContext {
// Don't early return! We need to build other outputs regardless of
// whether execution failed.
// Because of execution caching, we may start with operations from a
// previous run.
#[cfg(feature = "artifact-graph")]
let start_op = exec_state.global.artifacts.operations.len();
self.eval_prelude(exec_state, SourceRange::from(program).start_as_range())
.await?;
@ -1072,6 +1122,29 @@ impl ExecutorContext {
)
.await;
#[cfg(feature = "artifact-graph")]
{
// Fill in NodePath for operations.
let cached_body_items = exec_state.global.artifacts.cached_body_items();
for op in exec_state.global.artifacts.operations.iter_mut().skip(start_op) {
match op {
Operation::StdLibCall {
node_path,
source_range,
..
}
| Operation::GroupBegin {
node_path,
source_range,
..
} => {
node_path.fill_placeholder(program, cached_body_items, *source_range);
}
Operation::GroupEnd => {}
}
}
}
// Ensure all the async commands completed.
self.engine.ensure_async_commands_completed().await?;
@ -1949,7 +2022,7 @@ notPipeSub = 1 |> identity(!%))";
// a runtime error instead.
parse_execute(code11).await.unwrap_err(),
KclError::new_syntax(KclErrorDetails::new(
"There was an unexpected !. Try removing it.".to_owned(),
"There was an unexpected `!`. Try removing it.".to_owned(),
vec![SourceRange::new(56, 57, ModuleId::default())],
))
);

View File

@ -48,7 +48,7 @@ pub(super) struct GlobalState {
pub mod_loader: ModuleLoader,
/// Errors and warnings.
pub errors: Vec<CompilationError>,
#[allow(dead_code)]
#[cfg_attr(not(feature = "artifact-graph"), allow(dead_code))]
pub artifacts: ArtifactState,
}
@ -381,6 +381,13 @@ impl GlobalState {
}
}
#[cfg(feature = "artifact-graph")]
impl ArtifactState {
pub fn cached_body_items(&self) -> usize {
self.graph.item_count
}
}
impl ModuleState {
pub(super) fn new(path: ModulePath, memory: Arc<ProgramMemory>, module_id: Option<ModuleId>) -> Self {
ModuleState {

View File

@ -40,6 +40,10 @@ impl RuntimeType {
RuntimeType::Primitive(PrimitiveType::Edge)
}
pub fn function() -> Self {
RuntimeType::Primitive(PrimitiveType::Function)
}
pub fn sketch() -> Self {
RuntimeType::Primitive(PrimitiveType::Sketch)
}
@ -84,6 +88,10 @@ impl RuntimeType {
RuntimeType::Primitive(PrimitiveType::Tag)
}
pub fn tag_decl() -> Self {
RuntimeType::Primitive(PrimitiveType::TagDecl)
}
pub fn tag_identifier() -> Self {
RuntimeType::Primitive(PrimitiveType::TagId)
}
@ -376,8 +384,8 @@ pub enum PrimitiveType {
String,
Boolean,
Tag,
// Annoyingly some functions only want a TagIdentifier, not any kind of tag.
TagId,
TagDecl,
Sketch,
Solid,
Plane,
@ -409,6 +417,7 @@ impl PrimitiveType {
PrimitiveType::ImportedGeometry => "imported geometries".to_owned(),
PrimitiveType::Function => "functions".to_owned(),
PrimitiveType::Tag => "tags".to_owned(),
PrimitiveType::TagDecl => "tag declarators".to_owned(),
PrimitiveType::TagId => "tag identifiers".to_owned(),
}
}
@ -417,7 +426,7 @@ impl PrimitiveType {
match (self, other) {
(_, PrimitiveType::Any) => true,
(PrimitiveType::Number(n1), PrimitiveType::Number(n2)) => n1.subtype(n2),
(PrimitiveType::TagId, PrimitiveType::Tag) => true,
(PrimitiveType::TagId, PrimitiveType::Tag) | (PrimitiveType::TagDecl, PrimitiveType::Tag) => true,
(t1, t2) => t1 == t2,
}
}
@ -434,6 +443,7 @@ impl fmt::Display for PrimitiveType {
PrimitiveType::String => write!(f, "string"),
PrimitiveType::Boolean => write!(f, "bool"),
PrimitiveType::Tag => write!(f, "tag"),
PrimitiveType::TagDecl => write!(f, "tag declarator"),
PrimitiveType::TagId => write!(f, "tag identifier"),
PrimitiveType::Sketch => write!(f, "Sketch"),
PrimitiveType::Solid => write!(f, "Solid"),
@ -1291,6 +1301,10 @@ impl KclValue {
KclValue::TagIdentifier { .. } => Ok(self.clone()),
_ => Err(self.into()),
},
PrimitiveType::TagDecl => match self {
KclValue::TagDeclarator { .. } => Ok(self.clone()),
_ => Err(self.into()),
},
PrimitiveType::Tag => match self {
KclValue::TagDeclarator { .. } | KclValue::TagIdentifier { .. } | KclValue::Uuid { .. } => {
Ok(self.clone())
@ -1490,7 +1504,8 @@ impl KclValue {
Some(RuntimeType::Array(Box::new(ty.clone()), ArrayLen::Known(value.len())))
}
KclValue::TagIdentifier(_) => Some(RuntimeType::Primitive(PrimitiveType::TagId)),
KclValue::TagDeclarator(_) | KclValue::Uuid { .. } => Some(RuntimeType::Primitive(PrimitiveType::Tag)),
KclValue::TagDeclarator(_) => Some(RuntimeType::Primitive(PrimitiveType::TagDecl)),
KclValue::Uuid { .. } => Some(RuntimeType::Primitive(PrimitiveType::Tag)),
KclValue::Function { .. } => Some(RuntimeType::Primitive(PrimitiveType::Function)),
KclValue::Module { .. } | KclValue::KclNone { .. } | KclValue::Type { .. } => None,
}

View File

@ -247,17 +247,6 @@ impl ObjectProperty {
}
}
impl MemberObject {
fn get_hover_value_for_position(&self, pos: usize, code: &str, opts: &HoverOpts) -> Option<Hover> {
match self {
MemberObject::MemberExpression(member_expression) => {
member_expression.get_hover_value_for_position(pos, code, opts)
}
MemberObject::Identifier(_identifier) => None,
}
}
}
impl MemberExpression {
fn get_hover_value_for_position(&self, pos: usize, code: &str, opts: &HoverOpts) -> Option<Hover> {
let object_source_range: SourceRange = self.object.clone().into();

View File

@ -4,7 +4,7 @@ use crate::parsing::ast::types::{
Annotation, ArrayExpression, ArrayRangeExpression, AscribedExpression, BinaryExpression, BinaryPart, BodyItem,
CallExpressionKw, DefaultParamVal, ElseIf, Expr, ExpressionStatement, FunctionExpression, FunctionType, Identifier,
IfExpression, ImportItem, ImportSelector, ImportStatement, ItemVisibility, KclNone, LabelledExpression, Literal,
LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Name, ObjectExpression, ObjectProperty, Parameter,
LiteralIdentifier, LiteralValue, MemberExpression, Name, ObjectExpression, ObjectProperty, Parameter,
PipeExpression, PipeSubstitution, PrimitiveType, Program, ReturnStatement, TagDeclarator, Type, TypeDeclaration,
UnaryExpression, VariableDeclaration, VariableDeclarator, VariableKind,
};
@ -167,15 +167,6 @@ impl BinaryPart {
}
}
impl MemberObject {
pub fn compute_digest(&mut self) -> Digest {
match self {
MemberObject::MemberExpression(me) => me.compute_digest(),
MemberObject::Identifier(id) => id.compute_digest(),
}
}
}
impl LiteralIdentifier {
pub fn compute_digest(&mut self) -> Digest {
match self {

View File

@ -2,7 +2,7 @@ pub(crate) mod digest;
pub mod types;
use crate::{
parsing::ast::types::{BinaryPart, BodyItem, Expr, LiteralIdentifier, MemberObject},
parsing::ast::types::{BinaryPart, BodyItem, Expr, LiteralIdentifier},
ModuleId,
};
@ -57,15 +57,6 @@ impl BinaryPart {
}
}
impl MemberObject {
pub fn module_id(&self) -> ModuleId {
match self {
MemberObject::MemberExpression(member_expression) => member_expression.module_id,
MemberObject::Identifier(identifier) => identifier.module_id,
}
}
}
impl LiteralIdentifier {
pub fn module_id(&self) -> ModuleId {
match self {

View File

@ -2756,47 +2756,6 @@ impl ObjectProperty {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
pub enum MemberObject {
MemberExpression(BoxNode<MemberExpression>),
Identifier(BoxNode<Identifier>),
}
impl MemberObject {
pub fn start(&self) -> usize {
match self {
MemberObject::MemberExpression(member_expression) => member_expression.start,
MemberObject::Identifier(identifier) => identifier.start,
}
}
pub fn end(&self) -> usize {
match self {
MemberObject::MemberExpression(member_expression) => member_expression.end,
MemberObject::Identifier(identifier) => identifier.end,
}
}
pub(crate) fn contains_range(&self, range: &SourceRange) -> bool {
let sr = SourceRange::from(self);
sr.contains_range(range)
}
}
impl From<MemberObject> for SourceRange {
fn from(obj: MemberObject) -> Self {
Self::new(obj.start(), obj.end(), obj.module_id())
}
}
impl From<&MemberObject> for SourceRange {
fn from(obj: &MemberObject) -> Self {
Self::new(obj.start(), obj.end(), obj.module_id())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
@ -2842,7 +2801,7 @@ impl From<&LiteralIdentifier> for SourceRange {
#[ts(export)]
#[serde(tag = "type")]
pub struct MemberExpression {
pub object: MemberObject,
pub object: Expr,
pub property: LiteralIdentifier,
pub computed: bool,
@ -2864,12 +2823,7 @@ impl Node<MemberExpression> {
impl MemberExpression {
/// Rename all identifiers that have the old name to the new given name.
fn rename_identifiers(&mut self, old_name: &str, new_name: &str) {
match &mut self.object {
MemberObject::MemberExpression(ref mut member_expression) => {
member_expression.rename_identifiers(old_name, new_name)
}
MemberObject::Identifier(ref mut identifier) => identifier.rename(old_name, new_name),
}
self.object.rename_identifiers(old_name, new_name);
match &mut self.property {
LiteralIdentifier::Identifier(ref mut identifier) => identifier.rename(old_name, new_name),

View File

@ -1,6 +1,6 @@
use serde::Serialize;
use super::{BodyItem, Expr, MemberObject, Node, Program};
use super::{BodyItem, Expr, Node, Program};
use crate::SourceRange;
/// A traversal path through the AST to a node.
@ -60,6 +60,20 @@ pub enum Step {
}
impl NodePath {
/// Placeholder for when the AST isn't available to create a real path. It
/// will be filled in later.
pub(crate) fn placeholder() -> Self {
Self::default()
}
#[cfg(feature = "artifact-graph")]
pub(crate) fn fill_placeholder(&mut self, program: &Node<Program>, cached_body_items: usize, range: SourceRange) {
if !self.is_empty() {
return;
}
*self = Self::from_range(program, cached_body_items, range).unwrap_or_default();
}
/// Given a program and a [`SourceRange`], return the path to the node that
/// contains the range.
pub(crate) fn from_range(program: &Node<Program>, cached_body_items: usize, range: SourceRange) -> Option<Self> {
@ -248,7 +262,7 @@ impl NodePath {
Expr::MemberExpression(node) => {
if node.object.contains_range(&range) {
path.push(Step::MemberExpressionObject);
return Self::from_member_expr_object(&node.object, range, path);
return NodePath::from_expr(&node.object, range, path);
}
if node.property.contains_range(&range) {
path.push(Step::MemberExpressionProperty);
@ -313,18 +327,6 @@ impl NodePath {
Some(path)
}
fn from_member_expr_object(mut expr: &MemberObject, range: SourceRange, mut path: NodePath) -> Option<NodePath> {
while let MemberObject::MemberExpression(node) = expr {
if !node.object.contains_range(&range) {
break;
}
path.push(Step::MemberExpressionObject);
expr = &node.object;
}
Some(path)
}
pub fn is_empty(&self) -> bool {
self.steps.is_empty()
}
@ -402,4 +404,19 @@ mod tests {
}
);
}
#[test]
fn test_node_path_from_range_import() {
let code = r#"import "cube.step" as cube
import "cylinder.kcl" as cylinder
"#;
let program = crate::Program::parse_no_errs(code).unwrap();
// The entire cylinder import statement.
assert_eq!(
NodePath::from_range(&program.ast, 0, range(27, 60)).unwrap(),
NodePath {
steps: vec![Step::ProgramBodyItem { index: 1 }],
}
);
}
}

View File

@ -26,8 +26,8 @@ use crate::{
Annotation, ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem,
BoxNode, CallExpressionKw, CommentStyle, DefaultParamVal, ElseIf, Expr, ExpressionStatement,
FunctionExpression, FunctionType, Identifier, IfExpression, ImportItem, ImportSelector, ImportStatement,
ItemVisibility, LabeledArg, Literal, LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Name,
Node, NodeList, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty, Parameter,
ItemVisibility, LabeledArg, Literal, LiteralIdentifier, LiteralValue, MemberExpression, Name, Node,
NodeList, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty, Parameter,
PipeExpression, PipeSubstitution, PrimitiveType, Program, ReturnStatement, Shebang, TagDeclarator, Type,
TypeDeclaration, UnaryExpression, UnaryOperator, VariableDeclaration, VariableDeclarator, VariableKind,
},
@ -1326,10 +1326,7 @@ fn member_expression_subscript(i: &mut TokenSlice) -> ModalResult<(LiteralIdenti
/// Get a property of an object, or an index of an array, or a member of a collection.
/// Can be arbitrarily nested, e.g. `people[i]['adam'].age`.
fn member_expression(i: &mut TokenSlice) -> ModalResult<Node<MemberExpression>> {
// This is an identifier, followed by a sequence of members (aka properties)
// First, the identifier.
let id = nameable_identifier.context(expected("the identifier of the object whose property you're trying to access, e.g. in 'shape.size.width', 'shape' is the identifier")).parse_next(i)?;
fn build_member_expression(object: Expr, i: &mut TokenSlice) -> ModalResult<Node<MemberExpression>> {
// Now a sequence of members.
let member = alt((member_expression_dot, member_expression_subscript)).context(expected("a member/property, e.g. size.x and size['height'] and size[0] are all different ways to access a member/property of 'size'"));
let mut members: Vec<_> = repeat(1.., member)
@ -1340,11 +1337,11 @@ fn member_expression(i: &mut TokenSlice) -> ModalResult<Node<MemberExpression>>
// It's safe to call remove(0), because the vec is created from repeat(1..),
// which is guaranteed to have >=1 elements.
let (property, end, computed) = members.remove(0);
let start = id.start;
let module_id = id.module_id;
let start = object.start();
let module_id = object.module_id();
let initial_member_expression = Node::new(
MemberExpression {
object: MemberObject::Identifier(Box::new(id)),
object,
computed,
property,
digest: None,
@ -1362,7 +1359,7 @@ fn member_expression(i: &mut TokenSlice) -> ModalResult<Node<MemberExpression>>
.fold(initial_member_expression, |accumulated, (property, end, computed)| {
Node::new(
MemberExpression {
object: MemberObject::MemberExpression(Box::new(accumulated)),
object: Expr::MemberExpression(Box::new(accumulated)),
computed,
property,
digest: None,
@ -2085,8 +2082,7 @@ fn unnecessarily_bracketed(i: &mut TokenSlice) -> ModalResult<Expr> {
}
fn expr_allowed_in_pipe_expr(i: &mut TokenSlice) -> ModalResult<Expr> {
alt((
member_expression.map(Box::new).map(Expr::MemberExpression),
let parsed_expr = alt((
bool_value.map(Box::new).map(Expr::Literal),
tag.map(Box::new).map(Expr::TagDeclarator),
literal.map(Expr::Literal),
@ -2100,14 +2096,19 @@ fn expr_allowed_in_pipe_expr(i: &mut TokenSlice) -> ModalResult<Expr> {
unnecessarily_bracketed,
))
.context(expected("a KCL expression (but not a pipe expression)"))
.parse_next(i)
.parse_next(i)?;
let maybe_member = build_member_expression(parsed_expr.clone(), i);
if let Ok(mem) = maybe_member {
return Ok(Expr::MemberExpression(Box::new(mem)));
}
Ok(parsed_expr)
}
fn possible_operands(i: &mut TokenSlice) -> ModalResult<Expr> {
let mut expr = alt((
unary_expression.map(Box::new).map(Expr::UnaryExpression),
bool_value.map(Box::new).map(Expr::Literal),
member_expression.map(Box::new).map(Expr::MemberExpression),
literal.map(Expr::Literal),
fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),
name.map(Box::new).map(Expr::Name),
@ -2118,6 +2119,10 @@ fn possible_operands(i: &mut TokenSlice) -> ModalResult<Expr> {
"a KCL value which can be used as an argument/operand to an operator",
))
.parse_next(i)?;
let maybe_member = build_member_expression(expr.clone(), i);
if let Ok(mem) = maybe_member {
expr = Expr::MemberExpression(Box::new(mem));
}
let ty = opt((colon, opt(whitespace), type_)).parse_next(i)?;
if let Some((_, _, ty)) = ty {
@ -3258,7 +3263,7 @@ fn fn_call_kw(i: &mut TokenSlice) -> ModalResult<Node<CallExpressionKw>> {
return Err(ErrMode::Cut(
CompilationError::fatal(
SourceRange::from(&tok),
format!("There was an unexpected {}. Try removing it.", tok.value),
format!("There was an unexpected `{}`. Try removing it.", tok.value),
)
.into(),
));
@ -4427,7 +4432,7 @@ z(-[["#,
assert_err(
r#"z
(--#"#,
"There was an unexpected -. Try removing it.",
"There was an unexpected `-`. Try removing it.",
[3, 4],
);
}
@ -4997,6 +5002,17 @@ type foo = fn(fn, f: fn(number(_))): [fn([any]): string]
assert_no_err(some_program_string);
}
#[test]
fn test_parse_fn_call_then_field() {
let some_program_string = "myFunction().field";
let module_id = ModuleId::default();
let tokens = crate::parsing::token::lex(some_program_string, module_id).unwrap(); // Updated import path
let actual = expression.parse(tokens.as_slice()).unwrap();
let Expr::MemberExpression(_expr) = actual else {
panic!("expected member expression")
};
}
#[test]
fn test_parse_array_missing_closing_bracket() {
let some_program_string = r#"
@ -5185,7 +5201,7 @@ bar = 1
.cause
.as_ref()
.expect("Found an error, but there was no cause. Add a cause.");
assert_eq!(cause.message, "There was an unexpected }. Try removing it.",);
assert_eq!(cause.message, "There was an unexpected `}`. Try removing it.",);
assert_eq!(cause.source_range.start(), expected_src_start);
}

View File

@ -117,12 +117,20 @@ expression: actual
"computed": false,
"end": 45,
"object": {
"abs_path": false,
"commentStart": 40,
"end": 43,
"name": "obj",
"name": {
"commentStart": 40,
"end": 43,
"name": "obj",
"start": 40,
"type": "Identifier"
},
"path": [],
"start": 40,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 44,

View File

@ -117,12 +117,20 @@ expression: actual
"computed": false,
"end": 49,
"object": {
"abs_path": false,
"commentStart": 41,
"end": 44,
"name": "obj",
"name": {
"commentStart": 41,
"end": 44,
"name": "obj",
"start": 41,
"type": "Identifier"
},
"path": [],
"start": 41,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 45,

View File

@ -104,12 +104,20 @@ expression: actual
"computed": false,
"end": 44,
"object": {
"abs_path": false,
"commentStart": 36,
"end": 39,
"name": "obj",
"name": {
"commentStart": 36,
"end": 39,
"name": "obj",
"start": 36,
"type": "Identifier"
},
"path": [],
"start": 36,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 40,

View File

@ -120,12 +120,20 @@ expression: actual
"computed": false,
"end": 49,
"object": {
"abs_path": false,
"commentStart": 41,
"end": 44,
"name": "obj",
"name": {
"commentStart": 41,
"end": 44,
"name": "obj",
"start": 41,
"type": "Identifier"
},
"path": [],
"start": 41,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 45,

View File

@ -107,12 +107,20 @@ expression: actual
"computed": false,
"end": 45,
"object": {
"abs_path": false,
"commentStart": 37,
"end": 40,
"name": "obj",
"name": {
"commentStart": 37,
"end": 40,
"name": "obj",
"start": 37,
"type": "Identifier"
},
"path": [],
"start": 37,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 41,

View File

@ -107,12 +107,20 @@ expression: actual
"computed": false,
"end": 44,
"object": {
"abs_path": false,
"commentStart": 36,
"end": 39,
"name": "obj",
"name": {
"commentStart": 36,
"end": 39,
"name": "obj",
"start": 36,
"type": "Identifier"
},
"path": [],
"start": 36,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 40,

View File

@ -37,12 +37,20 @@ expression: actual
"computed": false,
"end": 18,
"object": {
"abs_path": false,
"commentStart": 13,
"end": 16,
"name": "obj",
"name": {
"commentStart": 13,
"end": 16,
"name": "obj",
"start": 13,
"type": "Identifier"
},
"path": [],
"start": 13,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 17,

View File

@ -24,12 +24,20 @@ expression: actual
"computed": false,
"end": 19,
"object": {
"abs_path": false,
"commentStart": 11,
"end": 14,
"name": "obj",
"name": {
"commentStart": 11,
"end": 14,
"name": "obj",
"start": 11,
"type": "Identifier"
},
"path": [],
"start": 11,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 15,

View File

@ -101,12 +101,20 @@ expression: actual
"computed": false,
"end": 44,
"object": {
"abs_path": false,
"commentStart": 36,
"end": 39,
"name": "obj",
"name": {
"commentStart": 36,
"end": 39,
"name": "obj",
"start": 36,
"type": "Identifier"
},
"path": [],
"start": 36,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 40,

View File

@ -25,12 +25,20 @@ expression: actual
"computed": false,
"end": 16,
"object": {
"abs_path": false,
"commentStart": 7,
"end": 9,
"name": "yo",
"name": {
"commentStart": 7,
"end": 9,
"name": "yo",
"start": 7,
"type": "Identifier"
},
"path": [],
"start": 7,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 10,

View File

@ -21,12 +21,20 @@ expression: actual
"computed": true,
"end": 11,
"object": {
"abs_path": false,
"commentStart": 6,
"end": 8,
"name": "b1",
"name": {
"commentStart": 6,
"end": 8,
"name": "b1",
"start": 6,
"type": "Identifier"
},
"path": [],
"start": 6,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 9,

View File

@ -33,12 +33,20 @@ expression: actual
"computed": false,
"end": 13,
"object": {
"abs_path": false,
"commentStart": 7,
"end": 9,
"name": "yo",
"name": {
"commentStart": 7,
"end": 9,
"name": "yo",
"start": 7,
"type": "Identifier"
},
"path": [],
"start": 7,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 10,

View File

@ -21,12 +21,20 @@ expression: actual
"computed": false,
"end": 11,
"object": {
"abs_path": false,
"commentStart": 6,
"end": 8,
"name": "b1",
"name": {
"commentStart": 6,
"end": 8,
"name": "b1",
"start": 6,
"type": "Identifier"
},
"path": [],
"start": 6,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 9,

View File

@ -21,12 +21,20 @@ expression: actual
"computed": false,
"end": 16,
"object": {
"abs_path": false,
"commentStart": 6,
"end": 8,
"name": "b1",
"name": {
"commentStart": 6,
"end": 8,
"name": "b1",
"start": 6,
"type": "Identifier"
},
"path": [],
"start": 6,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 9,

View File

@ -21,12 +21,20 @@ expression: actual
"computed": false,
"end": 13,
"object": {
"abs_path": false,
"commentStart": 6,
"end": 8,
"name": "b1",
"name": {
"commentStart": 6,
"end": 8,
"name": "b1",
"start": 6,
"type": "Identifier"
},
"path": [],
"start": 6,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"property": {
"commentStart": 9,

View File

@ -94,6 +94,11 @@ impl SourceRange {
ModuleId::from_usize(self.0[2])
}
/// True if this source range is from the top-level module.
pub fn is_top_level_module(&self) -> bool {
self.module_id().is_top_level()
}
/// Check if the range contains a position.
pub fn contains(&self, pos: usize) -> bool {
pos >= self.start() && pos <= self.end()

View File

@ -22,7 +22,7 @@ lazy_static::lazy_static! {
/// Construct a color from its red, blue and green components.
pub async fn hex_string(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let rgb: [TyF64; 3] = args.get_unlabeled_kw_arg_typed(
let rgb: [TyF64; 3] = args.get_unlabeled_kw_arg(
"rgb",
&RuntimeType::Array(Box::new(RuntimeType::count()), ArrayLen::Known(3)),
exec_state,
@ -50,15 +50,15 @@ async fn inner_hex_string(rgb: [TyF64; 3], _: &mut ExecState, args: Args) -> Res
/// Set the appearance of a solid. This only works on solids, not sketches or individual paths.
pub async fn appearance(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solids = args.get_unlabeled_kw_arg_typed(
let solids = args.get_unlabeled_kw_arg(
"solids",
&RuntimeType::Union(vec![RuntimeType::solids(), RuntimeType::imported()]),
exec_state,
)?;
let color: String = args.get_kw_arg_typed("color", &RuntimeType::string(), exec_state)?;
let metalness: Option<TyF64> = args.get_kw_arg_opt_typed("metalness", &RuntimeType::count(), exec_state)?;
let roughness: Option<TyF64> = args.get_kw_arg_opt_typed("roughness", &RuntimeType::count(), exec_state)?;
let color: String = args.get_kw_arg("color", &RuntimeType::string(), exec_state)?;
let metalness: Option<TyF64> = args.get_kw_arg_opt("metalness", &RuntimeType::count(), exec_state)?;
let roughness: Option<TyF64> = args.get_kw_arg_opt("roughness", &RuntimeType::count(), exec_state)?;
// Make sure the color if set is valid.
if !HEX_REGEX.is_match(&color) {

View File

@ -109,32 +109,7 @@ impl JsonSchema for TyF64 {
}
impl Args {
/// Get a keyword argument. If not set, returns None.
pub(crate) fn get_kw_arg_opt<'a, T>(&'a self, label: &str) -> Result<Option<T>, KclError>
where
T: FromKclValue<'a>,
{
let Some(arg) = self.kw_args.labeled.get(label) else {
return Ok(None);
};
if let KclValue::KclNone { .. } = arg.value {
// It is set, but it's an optional parameter that wasn't provided.
return Ok(None);
}
T::from_kcl_val(&arg.value).map(Some).ok_or_else(|| {
KclError::new_type(KclErrorDetails::new(
format!(
"The arg {label} was given, but it was the wrong type. It should be type {} but it was {}",
tynm::type_name::<T>(),
arg.value.human_friendly_type(),
),
vec![self.source_range],
))
})
}
pub(crate) fn get_kw_arg_opt_typed<T>(
pub(crate) fn get_kw_arg_opt<T>(
&self,
label: &str,
ty: &RuntimeType,
@ -152,28 +127,10 @@ impl Args {
}
}
self.get_kw_arg_typed(label, ty, exec_state).map(Some)
self.get_kw_arg(label, ty, exec_state).map(Some)
}
/// Get a keyword argument. If not set, returns Err.
pub(crate) fn get_kw_arg<'a, T>(&'a self, label: &str) -> Result<T, KclError>
where
T: FromKclValue<'a>,
{
self.get_kw_arg_opt(label)?.ok_or_else(|| {
KclError::new_semantic(KclErrorDetails::new(
format!("This function requires a keyword argument '{label}'"),
vec![self.source_range],
))
})
}
pub(crate) fn get_kw_arg_typed<T>(
&self,
label: &str,
ty: &RuntimeType,
exec_state: &mut ExecState,
) -> Result<T, KclError>
pub(crate) fn get_kw_arg<T>(&self, label: &str, ty: &RuntimeType, exec_state: &mut ExecState) -> Result<T, KclError>
where
T: for<'a> FromKclValue<'a>,
{
@ -254,7 +211,7 @@ impl Args {
label: &str,
exec_state: &mut ExecState,
) -> Result<(Vec<KclValue>, RuntimeType), KclError> {
let value = self.get_unlabeled_kw_arg_typed(label, &RuntimeType::any_array(), exec_state)?;
let value = self.get_unlabeled_kw_arg(label, &RuntimeType::any_array(), exec_state)?;
Ok(match value {
KclValue::HomArray { value, ty } => (value, ty),
KclValue::Tuple { value, .. } => (value, RuntimeType::any()),
@ -264,7 +221,7 @@ impl Args {
/// Get the unlabeled keyword argument. If not set, returns Err. If it
/// can't be converted to the given type, returns Err.
pub(crate) fn get_unlabeled_kw_arg_typed<T>(
pub(crate) fn get_unlabeled_kw_arg<T>(
&self,
label: &str,
ty: &RuntimeType,
@ -1393,9 +1350,9 @@ impl<'a> FromKclValue<'a> for Box<Solid> {
}
}
impl<'a> FromKclValue<'a> for &'a FunctionSource {
impl<'a> FromKclValue<'a> for FunctionSource {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
arg.as_function()
arg.as_function().cloned()
}
}

View File

@ -14,8 +14,8 @@ use crate::{
/// Apply a function to each element of an array.
pub async fn map(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let array: Vec<KclValue> = args.get_unlabeled_kw_arg_typed("array", &RuntimeType::any_array(), exec_state)?;
let f: &FunctionSource = args.get_kw_arg("f")?;
let array: Vec<KclValue> = args.get_unlabeled_kw_arg("array", &RuntimeType::any_array(), exec_state)?;
let f: FunctionSource = args.get_kw_arg("f", &RuntimeType::function(), exec_state)?;
let new_array = inner_map(array, f, exec_state, &args).await?;
Ok(KclValue::HomArray {
value: new_array,
@ -23,15 +23,15 @@ pub async fn map(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
})
}
async fn inner_map<'a>(
async fn inner_map(
array: Vec<KclValue>,
f: &'a FunctionSource,
f: FunctionSource,
exec_state: &mut ExecState,
args: &'a Args,
args: &Args,
) -> Result<Vec<KclValue>, KclError> {
let mut new_array = Vec::with_capacity(array.len());
for elem in array {
let new_elem = call_map_closure(elem, f, args.source_range, exec_state, &args.ctx).await?;
let new_elem = call_map_closure(elem, &f, args.source_range, exec_state, &args.ctx).await?;
new_array.push(new_elem);
}
Ok(new_array)
@ -68,22 +68,22 @@ async fn call_map_closure(
/// For each item in an array, update a value.
pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let array: Vec<KclValue> = args.get_unlabeled_kw_arg_typed("array", &RuntimeType::any_array(), exec_state)?;
let f: &FunctionSource = args.get_kw_arg("f")?;
let initial: KclValue = args.get_kw_arg_typed("initial", &RuntimeType::any(), exec_state)?;
let array: Vec<KclValue> = args.get_unlabeled_kw_arg("array", &RuntimeType::any_array(), exec_state)?;
let f: FunctionSource = args.get_kw_arg("f", &RuntimeType::function(), exec_state)?;
let initial: KclValue = args.get_kw_arg("initial", &RuntimeType::any(), exec_state)?;
inner_reduce(array, initial, f, exec_state, &args).await
}
async fn inner_reduce<'a>(
async fn inner_reduce(
array: Vec<KclValue>,
initial: KclValue,
f: &'a FunctionSource,
f: FunctionSource,
exec_state: &mut ExecState,
args: &'a Args,
args: &Args,
) -> Result<KclValue, KclError> {
let mut reduced = initial;
for elem in array {
reduced = call_reduce_closure(elem, reduced, f, args.source_range, exec_state, &args.ctx).await?;
reduced = call_reduce_closure(elem, reduced, &f, args.source_range, exec_state, &args.ctx).await?;
}
Ok(reduced)
@ -128,7 +128,7 @@ async fn call_reduce_closure(
pub async fn push(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (mut array, ty) = args.get_unlabeled_kw_arg_array_and_type("array", exec_state)?;
let item: KclValue = args.get_kw_arg_typed("item", &RuntimeType::any(), exec_state)?;
let item: KclValue = args.get_kw_arg("item", &RuntimeType::any(), exec_state)?;
array.push(item);

View File

@ -20,8 +20,8 @@ async fn _assert(value: bool, message: &str, args: &Args) -> Result<(), KclError
}
pub async fn assert_is(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let actual = args.get_unlabeled_kw_arg_typed("actual", &RuntimeType::bool(), exec_state)?;
let error = args.get_kw_arg_opt_typed("error", &RuntimeType::string(), exec_state)?;
let actual = args.get_unlabeled_kw_arg("actual", &RuntimeType::bool(), exec_state)?;
let error = args.get_kw_arg_opt("error", &RuntimeType::string(), exec_state)?;
inner_assert_is(actual, error, &args).await?;
Ok(KclValue::none())
}
@ -29,14 +29,14 @@ pub async fn assert_is(exec_state: &mut ExecState, args: Args) -> Result<KclValu
/// Check that the provided value is true, or raise a [KclError]
/// with the provided description.
pub async fn assert(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let actual = args.get_unlabeled_kw_arg_typed("actual", &RuntimeType::num_any(), exec_state)?;
let gt = args.get_kw_arg_opt_typed("isGreaterThan", &RuntimeType::num_any(), exec_state)?;
let lt = args.get_kw_arg_opt_typed("isLessThan", &RuntimeType::num_any(), exec_state)?;
let gte = args.get_kw_arg_opt_typed("isGreaterThanOrEqual", &RuntimeType::num_any(), exec_state)?;
let lte = args.get_kw_arg_opt_typed("isLessThanOrEqual", &RuntimeType::num_any(), exec_state)?;
let eq = args.get_kw_arg_opt_typed("isEqualTo", &RuntimeType::num_any(), exec_state)?;
let tolerance = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::num_any(), exec_state)?;
let error = args.get_kw_arg_opt_typed("error", &RuntimeType::string(), exec_state)?;
let actual = args.get_unlabeled_kw_arg("actual", &RuntimeType::num_any(), exec_state)?;
let gt = args.get_kw_arg_opt("isGreaterThan", &RuntimeType::num_any(), exec_state)?;
let lt = args.get_kw_arg_opt("isLessThan", &RuntimeType::num_any(), exec_state)?;
let gte = args.get_kw_arg_opt("isGreaterThanOrEqual", &RuntimeType::num_any(), exec_state)?;
let lte = args.get_kw_arg_opt("isLessThanOrEqual", &RuntimeType::num_any(), exec_state)?;
let eq = args.get_kw_arg_opt("isEqualTo", &RuntimeType::num_any(), exec_state)?;
let tolerance = args.get_kw_arg_opt("tolerance", &RuntimeType::num_any(), exec_state)?;
let error = args.get_kw_arg_opt("error", &RuntimeType::string(), exec_state)?;
inner_assert(actual, gt, lt, gte, lte, eq, tolerance, error, &args).await?;
Ok(KclValue::none())
}

View File

@ -7,10 +7,7 @@ use kittycad_modeling_cmds as kcmc;
use super::args::TyF64;
use crate::{
errors::{KclError, KclErrorDetails},
execution::{
types::{PrimitiveType, RuntimeType},
ChamferSurface, EdgeCut, ExecState, ExtrudeSurface, GeoMeta, KclValue, Solid,
},
execution::{types::RuntimeType, ChamferSurface, EdgeCut, ExecState, ExtrudeSurface, GeoMeta, KclValue, Solid},
parsing::ast::types::TagNode,
std::{fillet::EdgeReference, Args},
};
@ -19,10 +16,10 @@ pub(crate) const DEFAULT_TOLERANCE: f64 = 0.0000001;
/// Create chamfers on tagged paths.
pub async fn chamfer(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solid = args.get_unlabeled_kw_arg_typed("solid", &RuntimeType::Primitive(PrimitiveType::Solid), exec_state)?;
let length: TyF64 = args.get_kw_arg_typed("length", &RuntimeType::length(), exec_state)?;
let solid = args.get_unlabeled_kw_arg("solid", &RuntimeType::solid(), exec_state)?;
let length: TyF64 = args.get_kw_arg("length", &RuntimeType::length(), exec_state)?;
let tags = args.kw_arg_edge_array_and_source("tags")?;
let tag = args.get_kw_arg_opt("tag")?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
super::fillet::validate_unique(&tags)?;
let tags: Vec<EdgeReference> = tags.into_iter().map(|item| item.0).collect();

View File

@ -26,7 +26,7 @@ use crate::{
///
/// This works essentially like a copy-paste operation.
pub async fn clone(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let geometry = args.get_unlabeled_kw_arg_typed(
let geometry = args.get_unlabeled_kw_arg(
"geometry",
&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Sketch),

View File

@ -19,8 +19,8 @@ use crate::{
/// Union two or more solids into a single solid.
pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solids: Vec<Solid> =
args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::Union(vec![RuntimeType::solids()]), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
args.get_unlabeled_kw_arg("solids", &RuntimeType::Union(vec![RuntimeType::solids()]), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt("tolerance", &RuntimeType::length(), exec_state)?;
if solids.len() < 2 {
return Err(KclError::new_semantic(KclErrorDetails::new(
@ -84,8 +84,8 @@ pub(crate) async fn inner_union(
/// Intersect returns the shared volume between multiple solids, preserving only
/// overlapping regions.
pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solids: Vec<Solid> = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
let solids: Vec<Solid> = args.get_unlabeled_kw_arg("solids", &RuntimeType::solids(), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt("tolerance", &RuntimeType::length(), exec_state)?;
if solids.len() < 2 {
return Err(KclError::new_semantic(KclErrorDetails::new(
@ -148,10 +148,10 @@ pub(crate) async fn inner_intersect(
/// Subtract removes tool solids from base solids, leaving the remaining material.
pub async fn subtract(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solids: Vec<Solid> = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
let tools: Vec<Solid> = args.get_kw_arg_typed("tools", &RuntimeType::solids(), exec_state)?;
let solids: Vec<Solid> = args.get_unlabeled_kw_arg("solids", &RuntimeType::solids(), exec_state)?;
let tools: Vec<Solid> = args.get_kw_arg("tools", &RuntimeType::solids(), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt("tolerance", &RuntimeType::length(), exec_state)?;
let solids = inner_subtract(solids, tools, tolerance, exec_state, args).await?;
Ok(solids.into())

View File

@ -16,7 +16,7 @@ use crate::{
/// Get the opposite edge to the edge given.
pub async fn get_opposite_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input_edge = args.get_unlabeled_kw_arg_typed("edge", &RuntimeType::tag_identifier(), exec_state)?;
let input_edge = args.get_unlabeled_kw_arg("edge", &RuntimeType::tag_identifier(), exec_state)?;
let edge = inner_get_opposite_edge(input_edge, exec_state, args.clone()).await?;
Ok(KclValue::Uuid {
@ -63,7 +63,7 @@ async fn inner_get_opposite_edge(
/// Get the next adjacent edge to the edge given.
pub async fn get_next_adjacent_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input_edge = args.get_unlabeled_kw_arg_typed("edge", &RuntimeType::tag_identifier(), exec_state)?;
let input_edge = args.get_unlabeled_kw_arg("edge", &RuntimeType::tag_identifier(), exec_state)?;
let edge = inner_get_next_adjacent_edge(input_edge, exec_state, args.clone()).await?;
Ok(KclValue::Uuid {
@ -119,7 +119,7 @@ async fn inner_get_next_adjacent_edge(
/// Get the previous adjacent edge to the edge given.
pub async fn get_previous_adjacent_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input_edge = args.get_unlabeled_kw_arg_typed("edge", &RuntimeType::tag_identifier(), exec_state)?;
let input_edge = args.get_unlabeled_kw_arg("edge", &RuntimeType::tag_identifier(), exec_state)?;
let edge = inner_get_previous_adjacent_edge(input_edge, exec_state, args.clone()).await?;
Ok(KclValue::Uuid {
@ -174,7 +174,7 @@ async fn inner_get_previous_adjacent_edge(
/// Get the shared edge between two faces.
pub async fn get_common_edge(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let faces: Vec<TagIdentifier> = args.get_kw_arg_typed(
let faces: Vec<TagIdentifier> = args.get_kw_arg(
"faces",
&RuntimeType::Array(Box::new(RuntimeType::tag_identifier()), ArrayLen::Known(2)),
exec_state,

View File

@ -28,13 +28,13 @@ use crate::{
/// Extrudes by a given amount.
pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let length: TyF64 = args.get_kw_arg_typed("length", &RuntimeType::length(), exec_state)?;
let symmetric = args.get_kw_arg_opt_typed("symmetric", &RuntimeType::bool(), exec_state)?;
let sketches = args.get_unlabeled_kw_arg("sketches", &RuntimeType::sketches(), exec_state)?;
let length: TyF64 = args.get_kw_arg("length", &RuntimeType::length(), exec_state)?;
let symmetric = args.get_kw_arg_opt("symmetric", &RuntimeType::bool(), exec_state)?;
let bidirectional_length: Option<TyF64> =
args.get_kw_arg_opt_typed("bidirectionalLength", &RuntimeType::length(), exec_state)?;
let tag_start = args.get_kw_arg_opt("tagStart")?;
let tag_end = args.get_kw_arg_opt("tagEnd")?;
args.get_kw_arg_opt("bidirectionalLength", &RuntimeType::length(), exec_state)?;
let tag_start = args.get_kw_arg_opt("tagStart", &RuntimeType::tag_decl(), exec_state)?;
let tag_end = args.get_kw_arg_opt("tagEnd", &RuntimeType::tag_decl(), exec_state)?;
let result = inner_extrude(
sketches,

View File

@ -60,11 +60,11 @@ pub(super) fn validate_unique<T: Eq + std::hash::Hash>(tags: &[(T, SourceRange)]
/// Create fillets on tagged paths.
pub async fn fillet(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solid = args.get_unlabeled_kw_arg_typed("solid", &RuntimeType::solid(), exec_state)?;
let radius: TyF64 = args.get_kw_arg_typed("radius", &RuntimeType::length(), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
let solid = args.get_unlabeled_kw_arg("solid", &RuntimeType::solid(), exec_state)?;
let radius: TyF64 = args.get_kw_arg("radius", &RuntimeType::length(), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt("tolerance", &RuntimeType::length(), exec_state)?;
let tags = args.kw_arg_edge_array_and_source("tags")?;
let tag = args.get_kw_arg_opt("tag")?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
// Run the function.
validate_unique(&tags)?;

View File

@ -16,11 +16,11 @@ use crate::{
/// Create a helix.
pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let angle_start: TyF64 = args.get_kw_arg_typed("angleStart", &RuntimeType::degrees(), exec_state)?;
let revolutions: TyF64 = args.get_kw_arg_typed("revolutions", &RuntimeType::count(), exec_state)?;
let ccw = args.get_kw_arg_opt_typed("ccw", &RuntimeType::bool(), exec_state)?;
let radius: Option<TyF64> = args.get_kw_arg_opt_typed("radius", &RuntimeType::length(), exec_state)?;
let axis: Option<Axis3dOrEdgeReference> = args.get_kw_arg_opt_typed(
let angle_start: TyF64 = args.get_kw_arg("angleStart", &RuntimeType::degrees(), exec_state)?;
let revolutions: TyF64 = args.get_kw_arg("revolutions", &RuntimeType::count(), exec_state)?;
let ccw = args.get_kw_arg_opt("ccw", &RuntimeType::bool(), exec_state)?;
let radius: Option<TyF64> = args.get_kw_arg_opt("radius", &RuntimeType::length(), exec_state)?;
let axis: Option<Axis3dOrEdgeReference> = args.get_kw_arg_opt(
"axis",
&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Edge),
@ -28,8 +28,8 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
]),
exec_state,
)?;
let length: Option<TyF64> = args.get_kw_arg_opt_typed("length", &RuntimeType::length(), exec_state)?;
let cylinder = args.get_kw_arg_opt_typed("cylinder", &RuntimeType::solid(), exec_state)?;
let length: Option<TyF64> = args.get_kw_arg_opt("length", &RuntimeType::length(), exec_state)?;
let cylinder = args.get_kw_arg_opt("cylinder", &RuntimeType::solid(), exec_state)?;
// Make sure we have a radius if we don't have a cylinder.
if radius.is_none() && cylinder.is_none() {

View File

@ -21,23 +21,22 @@ const DEFAULT_V_DEGREE: u32 = 2;
/// Create a 3D surface or solid by interpolating between two or more sketches.
pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let sketches = args.get_unlabeled_kw_arg("sketches", &RuntimeType::sketches(), exec_state)?;
let v_degree: NonZeroU32 = args
.get_kw_arg_opt_typed("vDegree", &RuntimeType::count(), exec_state)?
.get_kw_arg_opt("vDegree", &RuntimeType::count(), exec_state)?
.unwrap_or(NonZeroU32::new(DEFAULT_V_DEGREE).unwrap());
// Attempt to approximate rational curves (such as arcs) using a bezier.
// This will remove banding around interpolations between arcs and non-arcs. It may produce errors in other scenarios
// Over time, this field won't be necessary.
let bez_approximate_rational = args
.get_kw_arg_opt_typed("bezApproximateRational", &RuntimeType::bool(), exec_state)?
.get_kw_arg_opt("bezApproximateRational", &RuntimeType::bool(), exec_state)?
.unwrap_or(false);
// This can be set to override the automatically determined topological base curve, which is usually the first section encountered.
let base_curve_index: Option<u32> =
args.get_kw_arg_opt_typed("baseCurveIndex", &RuntimeType::count(), exec_state)?;
let base_curve_index: Option<u32> = args.get_kw_arg_opt("baseCurveIndex", &RuntimeType::count(), exec_state)?;
// Tolerance for the loft operation.
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
let tag_start = args.get_kw_arg_opt("tagStart")?;
let tag_end = args.get_kw_arg_opt("tagEnd")?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt("tolerance", &RuntimeType::length(), exec_state)?;
let tag_start = args.get_kw_arg_opt("tagStart", &RuntimeType::tag_decl(), exec_state)?;
let tag_end = args.get_kw_arg_opt("tagEnd", &RuntimeType::tag_decl(), exec_state)?;
let value = inner_loft(
sketches,

View File

@ -15,8 +15,8 @@ use crate::{
/// Compute the remainder after dividing `num` by `div`.
/// If `num` is negative, the result will be too.
pub async fn rem(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let n: TyF64 = args.get_unlabeled_kw_arg_typed("number to divide", &RuntimeType::num_any(), exec_state)?;
let d: TyF64 = args.get_kw_arg_typed("divisor", &RuntimeType::num_any(), exec_state)?;
let n: TyF64 = args.get_unlabeled_kw_arg("number to divide", &RuntimeType::num_any(), exec_state)?;
let d: TyF64 = args.get_kw_arg("divisor", &RuntimeType::num_any(), exec_state)?;
let (n, d, ty) = NumericType::combine_div(n, d);
if ty == NumericType::Unknown {
@ -32,28 +32,28 @@ pub async fn rem(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
/// Compute the cosine of a number (in radians).
pub async fn cos(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let num: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::angle(), exec_state)?;
let num: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::angle(), exec_state)?;
let num = num.to_radians();
Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.cos())))
}
/// Compute the sine of a number (in radians).
pub async fn sin(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let num: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::angle(), exec_state)?;
let num: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::angle(), exec_state)?;
let num = num.to_radians();
Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.sin())))
}
/// Compute the tangent of a number (in radians).
pub async fn tan(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let num: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::angle(), exec_state)?;
let num: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::angle(), exec_state)?;
let num = num.to_radians();
Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.tan())))
}
/// Compute the square root of a number.
pub async fn sqrt(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::num_any(), exec_state)?;
if input.n < 0.0 {
return Err(KclError::new_semantic(KclErrorDetails::new(
@ -72,7 +72,7 @@ pub async fn sqrt(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
/// Compute the absolute value of a number.
pub async fn abs(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::num_any(), exec_state)?;
let result = input.n.abs();
Ok(args.make_user_val_from_f64_with_type(input.map_value(result)))
@ -80,7 +80,7 @@ pub async fn abs(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
/// Round a number to the nearest integer.
pub async fn round(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::num_any(), exec_state)?;
let result = input.n.round();
Ok(args.make_user_val_from_f64_with_type(input.map_value(result)))
@ -88,7 +88,7 @@ pub async fn round(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// Compute the largest integer less than or equal to a number.
pub async fn floor(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::num_any(), exec_state)?;
let result = input.n.floor();
Ok(args.make_user_val_from_f64_with_type(input.map_value(result)))
@ -96,7 +96,7 @@ pub async fn floor(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// Compute the smallest integer greater than or equal to a number.
pub async fn ceil(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::num_any(), exec_state)?;
let result = input.n.ceil();
Ok(args.make_user_val_from_f64_with_type(input.map_value(result)))
@ -104,7 +104,7 @@ pub async fn ceil(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
/// Compute the minimum of the given arguments.
pub async fn min(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let nums: Vec<TyF64> = args.get_unlabeled_kw_arg_typed(
let nums: Vec<TyF64> = args.get_unlabeled_kw_arg(
"input",
&RuntimeType::Array(Box::new(RuntimeType::num_any()), ArrayLen::Minimum(1)),
exec_state,
@ -129,7 +129,7 @@ pub async fn min(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
/// Compute the maximum of the given arguments.
pub async fn max(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let nums: Vec<TyF64> = args.get_unlabeled_kw_arg_typed(
let nums: Vec<TyF64> = args.get_unlabeled_kw_arg(
"input",
&RuntimeType::Array(Box::new(RuntimeType::num_any()), ArrayLen::Minimum(1)),
exec_state,
@ -154,8 +154,8 @@ pub async fn max(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
/// Compute the number to a power.
pub async fn pow(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
let exp: TyF64 = args.get_kw_arg_typed("exp", &RuntimeType::count(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::num_any(), exec_state)?;
let exp: TyF64 = args.get_kw_arg("exp", &RuntimeType::count(), exec_state)?;
let result = input.n.powf(exp.n);
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
@ -163,7 +163,7 @@ pub async fn pow(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
/// Compute the arccosine of a number (in radians).
pub async fn acos(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::count(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::count(), exec_state)?;
let result = input.n.acos();
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::radians())))
@ -171,7 +171,7 @@ pub async fn acos(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
/// Compute the arcsine of a number (in radians).
pub async fn asin(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::count(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::count(), exec_state)?;
let result = input.n.asin();
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::radians())))
@ -179,7 +179,7 @@ pub async fn asin(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
/// Compute the arctangent of a number (in radians).
pub async fn atan(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::count(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::count(), exec_state)?;
let result = input.n.atan();
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::radians())))
@ -187,8 +187,8 @@ pub async fn atan(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
/// Compute the four quadrant arctangent of Y and X (in radians).
pub async fn atan2(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let y = args.get_kw_arg_typed("y", &RuntimeType::length(), exec_state)?;
let x = args.get_kw_arg_typed("x", &RuntimeType::length(), exec_state)?;
let y = args.get_kw_arg("y", &RuntimeType::length(), exec_state)?;
let x = args.get_kw_arg("x", &RuntimeType::length(), exec_state)?;
let (y, x, _) = NumericType::combine_eq_coerce(y, x);
let result = y.atan2(x);
@ -201,8 +201,8 @@ pub async fn atan2(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// details; `log2()` can produce more accurate results for base 2,
/// and `log10()` can produce more accurate results for base 10.
pub async fn log(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
let base: TyF64 = args.get_kw_arg_typed("base", &RuntimeType::count(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::num_any(), exec_state)?;
let base: TyF64 = args.get_kw_arg("base", &RuntimeType::count(), exec_state)?;
let result = input.n.log(base.n);
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
@ -210,7 +210,7 @@ pub async fn log(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
/// Compute the base 2 logarithm of the number.
pub async fn log2(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::num_any(), exec_state)?;
let result = input.n.log2();
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
@ -218,7 +218,7 @@ pub async fn log2(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
/// Compute the base 10 logarithm of the number.
pub async fn log10(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::num_any(), exec_state)?;
let result = input.n.log10();
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
@ -226,7 +226,7 @@ pub async fn log10(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// Compute the natural logarithm of the number.
pub async fn ln(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
let input: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::num_any(), exec_state)?;
let result = input.n.ln();
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
@ -234,8 +234,8 @@ pub async fn ln(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclE
/// Compute the length of the given leg.
pub async fn leg_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let hypotenuse: TyF64 = args.get_kw_arg_typed("hypotenuse", &RuntimeType::length(), exec_state)?;
let leg: TyF64 = args.get_kw_arg_typed("leg", &RuntimeType::length(), exec_state)?;
let hypotenuse: TyF64 = args.get_kw_arg("hypotenuse", &RuntimeType::length(), exec_state)?;
let leg: TyF64 = args.get_kw_arg("leg", &RuntimeType::length(), exec_state)?;
let (hypotenuse, leg, ty) = NumericType::combine_eq_coerce(hypotenuse, leg);
let result = (hypotenuse.powi(2) - f64::min(hypotenuse.abs(), leg.abs()).powi(2)).sqrt();
Ok(KclValue::from_number_with_type(result, ty, vec![args.into()]))
@ -243,8 +243,8 @@ pub async fn leg_length(exec_state: &mut ExecState, args: Args) -> Result<KclVal
/// Compute the angle of the given leg for x.
pub async fn leg_angle_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let hypotenuse: TyF64 = args.get_kw_arg_typed("hypotenuse", &RuntimeType::length(), exec_state)?;
let leg: TyF64 = args.get_kw_arg_typed("leg", &RuntimeType::length(), exec_state)?;
let hypotenuse: TyF64 = args.get_kw_arg("hypotenuse", &RuntimeType::length(), exec_state)?;
let leg: TyF64 = args.get_kw_arg("leg", &RuntimeType::length(), exec_state)?;
let (hypotenuse, leg, _ty) = NumericType::combine_eq_coerce(hypotenuse, leg);
let result = (leg.min(hypotenuse) / hypotenuse).acos().to_degrees();
Ok(KclValue::from_number_with_type(
@ -256,8 +256,8 @@ pub async fn leg_angle_x(exec_state: &mut ExecState, args: Args) -> Result<KclVa
/// Compute the angle of the given leg for y.
pub async fn leg_angle_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let hypotenuse: TyF64 = args.get_kw_arg_typed("hypotenuse", &RuntimeType::length(), exec_state)?;
let leg: TyF64 = args.get_kw_arg_typed("leg", &RuntimeType::length(), exec_state)?;
let hypotenuse: TyF64 = args.get_kw_arg("hypotenuse", &RuntimeType::length(), exec_state)?;
let leg: TyF64 = args.get_kw_arg("leg", &RuntimeType::length(), exec_state)?;
let (hypotenuse, leg, _ty) = NumericType::combine_eq_coerce(hypotenuse, leg);
let result = (leg.min(hypotenuse) / hypotenuse).asin().to_degrees();
Ok(KclValue::from_number_with_type(

View File

@ -18,8 +18,8 @@ use crate::{
/// Mirror a sketch.
pub async fn mirror_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let axis = args.get_kw_arg_typed(
let sketches = args.get_unlabeled_kw_arg("sketches", &RuntimeType::sketches(), exec_state)?;
let axis = args.get_kw_arg(
"axis",
&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Edge),

View File

@ -170,7 +170,7 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp
),
("transform", "mirror2d") => (
|e, a| Box::pin(crate::std::mirror::mirror_2d(e, a)),
StdFnProps::default("std::transform::mirror2d"),
StdFnProps::default("std::transform::mirror2d").include_in_feature_tree(),
),
("transform", "translate") => (
|e, a| Box::pin(crate::std::transform::translate(e, a)),
@ -406,47 +406,47 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp
),
("sketch", "involuteCircular") => (
|e, a| Box::pin(crate::std::sketch::involute_circular(e, a)),
StdFnProps::default("std::sketch::startProfile"),
StdFnProps::default("std::sketch::involuteCircular"),
),
("sketch", "line") => (
|e, a| Box::pin(crate::std::sketch::line(e, a)),
StdFnProps::default("std::sketch::startProfile"),
StdFnProps::default("std::sketch::line"),
),
("sketch", "xLine") => (
|e, a| Box::pin(crate::std::sketch::x_line(e, a)),
StdFnProps::default("std::sketch::startProfile"),
StdFnProps::default("std::sketch::xLine"),
),
("sketch", "yLine") => (
|e, a| Box::pin(crate::std::sketch::y_line(e, a)),
StdFnProps::default("std::sketch::startProfile"),
StdFnProps::default("std::sketch::yLine"),
),
("sketch", "angledLine") => (
|e, a| Box::pin(crate::std::sketch::angled_line(e, a)),
StdFnProps::default("std::sketch::startProfile"),
StdFnProps::default("std::sketch::angledLine"),
),
("sketch", "angledLineThatIntersects") => (
|e, a| Box::pin(crate::std::sketch::angled_line_that_intersects(e, a)),
StdFnProps::default("std::sketch::startProfile"),
StdFnProps::default("std::sketch::angledLineThatIntersects"),
),
("sketch", "close") => (
|e, a| Box::pin(crate::std::sketch::close(e, a)),
StdFnProps::default("std::sketch::startProfile"),
StdFnProps::default("std::sketch::close"),
),
("sketch", "arc") => (
|e, a| Box::pin(crate::std::sketch::arc(e, a)),
StdFnProps::default("std::sketch::startProfile"),
StdFnProps::default("std::sketch::arc"),
),
("sketch", "tangentialArc") => (
|e, a| Box::pin(crate::std::sketch::tangential_arc(e, a)),
StdFnProps::default("std::sketch::startProfile"),
StdFnProps::default("std::sketch::tangentialArc"),
),
("sketch", "bezierCurve") => (
|e, a| Box::pin(crate::std::sketch::bezier_curve(e, a)),
StdFnProps::default("std::sketch::startProfile"),
StdFnProps::default("std::sketch::bezierCurve"),
),
("sketch", "subtract2d") => (
|e, a| Box::pin(crate::std::sketch::subtract_2d(e, a)),
StdFnProps::default("std::sketch::startProfile").include_in_feature_tree(),
StdFnProps::default("std::sketch::subtract2d").include_in_feature_tree(),
),
("appearance", "hexString") => (
|e, a| Box::pin(crate::std::appearance::hex_string(e, a)),

View File

@ -35,10 +35,10 @@ const MUST_HAVE_ONE_INSTANCE: &str = "There must be at least 1 instance of your
/// Repeat some 3D solid, changing each repetition slightly.
pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
let transform: &FunctionSource = args.get_kw_arg("transform")?;
let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
let solids = args.get_unlabeled_kw_arg("solids", &RuntimeType::solids(), exec_state)?;
let instances: u32 = args.get_kw_arg("instances", &RuntimeType::count(), exec_state)?;
let transform: FunctionSource = args.get_kw_arg("transform", &RuntimeType::function(), exec_state)?;
let use_original = args.get_kw_arg_opt("useOriginal", &RuntimeType::bool(), exec_state)?;
let solids = inner_pattern_transform(solids, instances, transform, use_original, exec_state, &args).await?;
Ok(solids.into())
@ -46,22 +46,22 @@ pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result
/// Repeat some 2D sketch, changing each repetition slightly.
pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
let transform: &FunctionSource = args.get_kw_arg("transform")?;
let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
let sketches = args.get_unlabeled_kw_arg("sketches", &RuntimeType::sketches(), exec_state)?;
let instances: u32 = args.get_kw_arg("instances", &RuntimeType::count(), exec_state)?;
let transform: FunctionSource = args.get_kw_arg("transform", &RuntimeType::function(), exec_state)?;
let use_original = args.get_kw_arg_opt("useOriginal", &RuntimeType::bool(), exec_state)?;
let sketches = inner_pattern_transform_2d(sketches, instances, transform, use_original, exec_state, &args).await?;
Ok(sketches.into())
}
async fn inner_pattern_transform<'a>(
async fn inner_pattern_transform(
solids: Vec<Solid>,
instances: u32,
transform: &'a FunctionSource,
transform: FunctionSource,
use_original: Option<bool>,
exec_state: &mut ExecState,
args: &'a Args,
args: &Args,
) -> Result<Vec<Solid>, KclError> {
// Build the vec of transforms, one for each repetition.
let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
@ -72,7 +72,7 @@ async fn inner_pattern_transform<'a>(
)));
}
for i in 1..instances {
let t = make_transform::<Solid>(i, transform, args.source_range, exec_state, &args.ctx).await?;
let t = make_transform::<Solid>(i, &transform, args.source_range, exec_state, &args.ctx).await?;
transform_vec.push(t);
}
execute_pattern_transform(
@ -85,13 +85,13 @@ async fn inner_pattern_transform<'a>(
.await
}
async fn inner_pattern_transform_2d<'a>(
async fn inner_pattern_transform_2d(
sketches: Vec<Sketch>,
instances: u32,
transform: &'a FunctionSource,
transform: FunctionSource,
use_original: Option<bool>,
exec_state: &mut ExecState,
args: &'a Args,
args: &Args,
) -> Result<Vec<Sketch>, KclError> {
// Build the vec of transforms, one for each repetition.
let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
@ -102,7 +102,7 @@ async fn inner_pattern_transform_2d<'a>(
)));
}
for i in 1..instances {
let t = make_transform::<Sketch>(i, transform, args.source_range, exec_state, &args.ctx).await?;
let t = make_transform::<Sketch>(i, &transform, args.source_range, exec_state, &args.ctx).await?;
transform_vec.push(t);
}
execute_pattern_transform(
@ -519,10 +519,10 @@ mod tests {
/// A linear pattern on a 2D sketch.
pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
let distance: TyF64 = args.get_kw_arg_typed("distance", &RuntimeType::length(), exec_state)?;
let axis: Axis2dOrPoint2d = args.get_kw_arg_typed(
let sketches = args.get_unlabeled_kw_arg("sketches", &RuntimeType::sketches(), exec_state)?;
let instances: u32 = args.get_kw_arg("instances", &RuntimeType::count(), exec_state)?;
let distance: TyF64 = args.get_kw_arg("distance", &RuntimeType::length(), exec_state)?;
let axis: Axis2dOrPoint2d = args.get_kw_arg(
"axis",
&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Axis2d),
@ -530,7 +530,7 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
]),
exec_state,
)?;
let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
let use_original = args.get_kw_arg_opt("useOriginal", &RuntimeType::bool(), exec_state)?;
let axis = axis.to_point2d();
if axis[0].n == 0.0 && axis[1].n == 0.0 {
@ -579,10 +579,10 @@ async fn inner_pattern_linear_2d(
/// A linear pattern on a 3D model.
pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
let distance: TyF64 = args.get_kw_arg_typed("distance", &RuntimeType::length(), exec_state)?;
let axis: Axis3dOrPoint3d = args.get_kw_arg_typed(
let solids = args.get_unlabeled_kw_arg("solids", &RuntimeType::solids(), exec_state)?;
let instances: u32 = args.get_kw_arg("instances", &RuntimeType::count(), exec_state)?;
let distance: TyF64 = args.get_kw_arg("distance", &RuntimeType::length(), exec_state)?;
let axis: Axis3dOrPoint3d = args.get_kw_arg(
"axis",
&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Axis3d),
@ -590,7 +590,7 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
]),
exec_state,
)?;
let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
let use_original = args.get_kw_arg_opt("useOriginal", &RuntimeType::bool(), exec_state)?;
let axis = axis.to_point3d();
if axis[0].n == 0.0 && axis[1].n == 0.0 && axis[2].n == 0.0 {
@ -747,12 +747,12 @@ impl CircularPattern {
/// A circular pattern on a 2D sketch.
pub async fn pattern_circular_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
let center: [TyF64; 2] = args.get_kw_arg_typed("center", &RuntimeType::point2d(), exec_state)?;
let arc_degrees: Option<TyF64> = args.get_kw_arg_opt_typed("arcDegrees", &RuntimeType::degrees(), exec_state)?;
let rotate_duplicates = args.get_kw_arg_opt_typed("rotateDuplicates", &RuntimeType::bool(), exec_state)?;
let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
let sketches = args.get_unlabeled_kw_arg("sketches", &RuntimeType::sketches(), exec_state)?;
let instances: u32 = args.get_kw_arg("instances", &RuntimeType::count(), exec_state)?;
let center: [TyF64; 2] = args.get_kw_arg("center", &RuntimeType::point2d(), exec_state)?;
let arc_degrees: Option<TyF64> = args.get_kw_arg_opt("arcDegrees", &RuntimeType::degrees(), exec_state)?;
let rotate_duplicates = args.get_kw_arg_opt("rotateDuplicates", &RuntimeType::bool(), exec_state)?;
let use_original = args.get_kw_arg_opt("useOriginal", &RuntimeType::bool(), exec_state)?;
let sketches = inner_pattern_circular_2d(
sketches,
@ -817,14 +817,14 @@ async fn inner_pattern_circular_2d(
/// A circular pattern on a 3D model.
pub async fn pattern_circular_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
let solids = args.get_unlabeled_kw_arg("solids", &RuntimeType::solids(), exec_state)?;
// The number of total instances. Must be greater than or equal to 1.
// This includes the original entity. For example, if instances is 2,
// there will be two copies -- the original, and one new copy.
// If instances is 1, this has no effect.
let instances: u32 = args.get_kw_arg_typed("instances", &RuntimeType::count(), exec_state)?;
let instances: u32 = args.get_kw_arg("instances", &RuntimeType::count(), exec_state)?;
// The axis around which to make the pattern. This is a 3D vector.
let axis: Axis3dOrPoint3d = args.get_kw_arg_typed(
let axis: Axis3dOrPoint3d = args.get_kw_arg(
"axis",
&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Axis3d),
@ -835,14 +835,14 @@ pub async fn pattern_circular_3d(exec_state: &mut ExecState, args: Args) -> Resu
let axis = axis.to_point3d();
// The center about which to make the pattern. This is a 3D vector.
let center: [TyF64; 3] = args.get_kw_arg_typed("center", &RuntimeType::point3d(), exec_state)?;
let center: [TyF64; 3] = args.get_kw_arg("center", &RuntimeType::point3d(), exec_state)?;
// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
let arc_degrees: Option<TyF64> = args.get_kw_arg_opt_typed("arcDegrees", &RuntimeType::degrees(), exec_state)?;
let arc_degrees: Option<TyF64> = args.get_kw_arg_opt("arcDegrees", &RuntimeType::degrees(), exec_state)?;
// Whether or not to rotate the duplicates as they are copied.
let rotate_duplicates = args.get_kw_arg_opt_typed("rotateDuplicates", &RuntimeType::bool(), exec_state)?;
let rotate_duplicates = args.get_kw_arg_opt("rotateDuplicates", &RuntimeType::bool(), exec_state)?;
// If the target being patterned is itself a pattern, then, should you use the original solid,
// or the pattern?
let use_original = args.get_kw_arg_opt_typed("useOriginal", &RuntimeType::bool(), exec_state)?;
let use_original = args.get_kw_arg_opt("useOriginal", &RuntimeType::bool(), exec_state)?;
let solids = inner_pattern_circular_3d(
solids,

View File

@ -12,8 +12,8 @@ use crate::{
/// Offset a plane by a distance along its normal.
pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let std_plane = args.get_unlabeled_kw_arg_typed("plane", &RuntimeType::plane(), exec_state)?;
let offset: TyF64 = args.get_kw_arg_typed("offset", &RuntimeType::length(), exec_state)?;
let std_plane = args.get_unlabeled_kw_arg("plane", &RuntimeType::plane(), exec_state)?;
let offset: TyF64 = args.get_kw_arg("offset", &RuntimeType::length(), exec_state)?;
let plane = inner_offset_plane(std_plane, offset, exec_state, &args).await?;
Ok(KclValue::Plane { value: Box::new(plane) })
}

View File

@ -24,8 +24,8 @@ extern crate nalgebra_glm as glm;
/// Revolve a sketch or set of sketches around an axis.
pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let axis = args.get_kw_arg_typed(
let sketches = args.get_unlabeled_kw_arg("sketches", &RuntimeType::sketches(), exec_state)?;
let axis = args.get_kw_arg(
"axis",
&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Edge),
@ -33,13 +33,13 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
]),
exec_state,
)?;
let angle: Option<TyF64> = args.get_kw_arg_opt_typed("angle", &RuntimeType::degrees(), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
let tag_start = args.get_kw_arg_opt("tagStart")?;
let tag_end = args.get_kw_arg_opt("tagEnd")?;
let symmetric = args.get_kw_arg_opt_typed("symmetric", &RuntimeType::bool(), exec_state)?;
let angle: Option<TyF64> = args.get_kw_arg_opt("angle", &RuntimeType::degrees(), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt("tolerance", &RuntimeType::length(), exec_state)?;
let tag_start = args.get_kw_arg_opt("tagStart", &RuntimeType::tag_decl(), exec_state)?;
let tag_end = args.get_kw_arg_opt("tagEnd", &RuntimeType::tag_decl(), exec_state)?;
let symmetric = args.get_kw_arg_opt("symmetric", &RuntimeType::bool(), exec_state)?;
let bidirectional_angle: Option<TyF64> =
args.get_kw_arg_opt_typed("bidirectionalAngle", &RuntimeType::angle(), exec_state)?;
args.get_kw_arg_opt("bidirectionalAngle", &RuntimeType::angle(), exec_state)?;
let value = inner_revolve(
sketches,

View File

@ -15,7 +15,7 @@ use crate::{
/// Returns the point at the end of the given segment.
pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tag_identifier(), exec_state)?;
let pt = inner_segment_end(&tag, exec_state, args.clone())?;
args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone())
@ -38,7 +38,7 @@ fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args
/// Returns the segment end of x.
pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tag_identifier(), exec_state)?;
let result = inner_segment_end_x(&tag, exec_state, args.clone())?;
Ok(args.make_user_val_from_f64_with_type(result))
@ -58,7 +58,7 @@ fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
/// Returns the segment end of y.
pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tag_identifier(), exec_state)?;
let result = inner_segment_end_y(&tag, exec_state, args.clone())?;
Ok(args.make_user_val_from_f64_with_type(result))
@ -78,7 +78,7 @@ fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
/// Returns the point at the start of the given segment.
pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tag_identifier(), exec_state)?;
let pt = inner_segment_start(&tag, exec_state, args.clone())?;
args.make_kcl_val_from_point([pt[0].n, pt[1].n], pt[0].ty.clone())
@ -101,7 +101,7 @@ fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
/// Returns the segment start of x.
pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tag_identifier(), exec_state)?;
let result = inner_segment_start_x(&tag, exec_state, args.clone())?;
Ok(args.make_user_val_from_f64_with_type(result))
@ -121,7 +121,7 @@ fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args:
/// Returns the segment start of y.
pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tag_identifier(), exec_state)?;
let result = inner_segment_start_y(&tag, exec_state, args.clone())?;
Ok(args.make_user_val_from_f64_with_type(result))
@ -140,8 +140,7 @@ fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args:
}
/// Returns the last segment of x.
pub async fn last_segment_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let result = inner_last_segment_x(sketch, args.clone())?;
Ok(args.make_user_val_from_f64_with_type(result))
@ -164,8 +163,7 @@ fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
/// Returns the last segment of y.
pub async fn last_segment_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let result = inner_last_segment_y(sketch, args.clone())?;
Ok(args.make_user_val_from_f64_with_type(result))
@ -188,7 +186,7 @@ fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<TyF64, KclError> {
/// Returns the length of the segment.
pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tag_identifier(), exec_state)?;
let result = inner_segment_length(&tag, exec_state, args.clone())?;
Ok(args.make_user_val_from_f64_with_type(result))
}
@ -207,7 +205,7 @@ fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: A
/// Returns the angle of the segment.
pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tag_identifier(), exec_state)?;
let result = inner_segment_angle(&tag, exec_state, args.clone())?;
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))
@ -229,7 +227,7 @@ fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
/// Returns the angle coming out of the end of the segment in degrees.
pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let tag: TagIdentifier = args.get_unlabeled_kw_arg_typed("tag", &RuntimeType::tag_identifier(), exec_state)?;
let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag", &RuntimeType::tag_identifier(), exec_state)?;
let result = inner_tangent_to_end(&tag, exec_state, args.clone()).await?;
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::degrees())))

View File

@ -24,7 +24,6 @@ use crate::{
},
parsing::ast::types::TagNode,
std::{
sketch::NEW_TAG_KW,
utils::{calculate_circle_center, distance},
Args,
},
@ -43,11 +42,11 @@ pub enum SketchOrSurface {
/// Sketch a circle.
pub async fn circle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch_or_surface =
args.get_unlabeled_kw_arg_typed("sketchOrSurface", &RuntimeType::sketch_or_surface(), exec_state)?;
let center = args.get_kw_arg_typed("center", &RuntimeType::point2d(), exec_state)?;
let radius: Option<TyF64> = args.get_kw_arg_opt_typed("radius", &RuntimeType::length(), exec_state)?;
let diameter: Option<TyF64> = args.get_kw_arg_opt_typed("diameter", &RuntimeType::length(), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
args.get_unlabeled_kw_arg("sketchOrSurface", &RuntimeType::sketch_or_surface(), exec_state)?;
let center = args.get_kw_arg("center", &RuntimeType::point2d(), exec_state)?;
let radius: Option<TyF64> = args.get_kw_arg_opt("radius", &RuntimeType::length(), exec_state)?;
let diameter: Option<TyF64> = args.get_kw_arg_opt("diameter", &RuntimeType::length(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let sketch = inner_circle(sketch_or_surface, center, radius, diameter, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
@ -130,11 +129,11 @@ async fn inner_circle(
/// Sketch a 3-point circle.
pub async fn circle_three_point(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch_or_surface =
args.get_unlabeled_kw_arg_typed("sketchOrSurface", &RuntimeType::sketch_or_surface(), exec_state)?;
let p1 = args.get_kw_arg_typed("p1", &RuntimeType::point2d(), exec_state)?;
let p2 = args.get_kw_arg_typed("p2", &RuntimeType::point2d(), exec_state)?;
let p3 = args.get_kw_arg_typed("p3", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt("tag")?;
args.get_unlabeled_kw_arg("sketchOrSurface", &RuntimeType::sketch_or_surface(), exec_state)?;
let p1 = args.get_kw_arg("p1", &RuntimeType::point2d(), exec_state)?;
let p2 = args.get_kw_arg("p2", &RuntimeType::point2d(), exec_state)?;
let p3 = args.get_kw_arg("p3", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let sketch = inner_circle_three_point(sketch_or_surface, p1, p2, p3, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
@ -239,11 +238,11 @@ pub enum PolygonType {
/// Create a regular polygon with the specified number of sides and radius.
pub async fn polygon(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch_or_surface =
args.get_unlabeled_kw_arg_typed("sketchOrSurface", &RuntimeType::sketch_or_surface(), exec_state)?;
let radius: TyF64 = args.get_kw_arg_typed("radius", &RuntimeType::length(), exec_state)?;
let num_sides: TyF64 = args.get_kw_arg_typed("numSides", &RuntimeType::count(), exec_state)?;
let center = args.get_kw_arg_typed("center", &RuntimeType::point2d(), exec_state)?;
let inscribed = args.get_kw_arg_opt_typed("inscribed", &RuntimeType::bool(), exec_state)?;
args.get_unlabeled_kw_arg("sketchOrSurface", &RuntimeType::sketch_or_surface(), exec_state)?;
let radius: TyF64 = args.get_kw_arg("radius", &RuntimeType::length(), exec_state)?;
let num_sides: TyF64 = args.get_kw_arg("numSides", &RuntimeType::count(), exec_state)?;
let center = args.get_kw_arg("center", &RuntimeType::point2d(), exec_state)?;
let inscribed = args.get_kw_arg_opt("inscribed", &RuntimeType::bool(), exec_state)?;
let sketch = inner_polygon(
sketch_or_surface,

View File

@ -16,9 +16,9 @@ use crate::{
/// Create a shell.
pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
let thickness: TyF64 = args.get_kw_arg_typed("thickness", &RuntimeType::length(), exec_state)?;
let faces = args.get_kw_arg_typed(
let solids = args.get_unlabeled_kw_arg("solids", &RuntimeType::solids(), exec_state)?;
let thickness: TyF64 = args.get_kw_arg("thickness", &RuntimeType::length(), exec_state)?;
let faces = args.get_kw_arg(
"faces",
&RuntimeType::Array(Box::new(RuntimeType::tag()), ArrayLen::Minimum(1)),
exec_state,
@ -94,8 +94,8 @@ async fn inner_shell(
/// Make the inside of a 3D object hollow.
pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let solid = args.get_unlabeled_kw_arg_typed("solid", &RuntimeType::solid(), exec_state)?;
let thickness: TyF64 = args.get_kw_arg_typed("thickness", &RuntimeType::length(), exec_state)?;
let solid = args.get_unlabeled_kw_arg("solid", &RuntimeType::solid(), exec_state)?;
let thickness: TyF64 = args.get_kw_arg("thickness", &RuntimeType::length(), exec_state)?;
let value = inner_hollow(solid, thickness, exec_state, args).await?;
Ok(KclValue::Solid { value })

View File

@ -102,13 +102,13 @@ pub enum StartOrEnd {
pub const NEW_TAG_KW: &str = "tag";
pub async fn involute_circular(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch = args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::sketch(), exec_state)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::sketch(), exec_state)?;
let start_radius: TyF64 = args.get_kw_arg_typed("startRadius", &RuntimeType::length(), exec_state)?;
let end_radius: TyF64 = args.get_kw_arg_typed("endRadius", &RuntimeType::length(), exec_state)?;
let angle: TyF64 = args.get_kw_arg_typed("angle", &RuntimeType::angle(), exec_state)?;
let reverse = args.get_kw_arg_opt_typed("reverse", &RuntimeType::bool(), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
let start_radius: TyF64 = args.get_kw_arg("startRadius", &RuntimeType::length(), exec_state)?;
let end_radius: TyF64 = args.get_kw_arg("endRadius", &RuntimeType::length(), exec_state)?;
let angle: TyF64 = args.get_kw_arg("angle", &RuntimeType::angle(), exec_state)?;
let reverse = args.get_kw_arg_opt("reverse", &RuntimeType::bool(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let new_sketch =
inner_involute_circular(sketch, start_radius, end_radius, angle, reverse, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
@ -195,10 +195,10 @@ async fn inner_involute_circular(
/// Draw a line to a point.
pub async fn line(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch = args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::sketch(), exec_state)?;
let end = args.get_kw_arg_opt_typed("end", &RuntimeType::point2d(), exec_state)?;
let end_absolute = args.get_kw_arg_opt_typed("endAbsolute", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::sketch(), exec_state)?;
let end = args.get_kw_arg_opt("end", &RuntimeType::point2d(), exec_state)?;
let end_absolute = args.get_kw_arg_opt("endAbsolute", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let new_sketch = inner_line(sketch, end_absolute, end, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
@ -332,11 +332,10 @@ async fn straight_line(
/// Draw a line on the x-axis.
pub async fn x_line(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let length: Option<TyF64> = args.get_kw_arg_opt_typed("length", &RuntimeType::length(), exec_state)?;
let end_absolute: Option<TyF64> = args.get_kw_arg_opt_typed("endAbsolute", &RuntimeType::length(), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let length: Option<TyF64> = args.get_kw_arg_opt("length", &RuntimeType::length(), exec_state)?;
let end_absolute: Option<TyF64> = args.get_kw_arg_opt("endAbsolute", &RuntimeType::length(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let new_sketch = inner_x_line(sketch, length, end_absolute, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
@ -369,11 +368,10 @@ async fn inner_x_line(
/// Draw a line on the y-axis.
pub async fn y_line(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let length: Option<TyF64> = args.get_kw_arg_opt_typed("length", &RuntimeType::length(), exec_state)?;
let end_absolute: Option<TyF64> = args.get_kw_arg_opt_typed("endAbsolute", &RuntimeType::length(), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let length: Option<TyF64> = args.get_kw_arg_opt("length", &RuntimeType::length(), exec_state)?;
let end_absolute: Option<TyF64> = args.get_kw_arg_opt("endAbsolute", &RuntimeType::length(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let new_sketch = inner_y_line(sketch, length, end_absolute, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
@ -406,16 +404,14 @@ async fn inner_y_line(
/// Draw an angled line.
pub async fn angled_line(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch = args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::sketch(), exec_state)?;
let angle: TyF64 = args.get_kw_arg_typed("angle", &RuntimeType::degrees(), exec_state)?;
let length: Option<TyF64> = args.get_kw_arg_opt_typed("length", &RuntimeType::length(), exec_state)?;
let length_x: Option<TyF64> = args.get_kw_arg_opt_typed("lengthX", &RuntimeType::length(), exec_state)?;
let length_y: Option<TyF64> = args.get_kw_arg_opt_typed("lengthY", &RuntimeType::length(), exec_state)?;
let end_absolute_x: Option<TyF64> =
args.get_kw_arg_opt_typed("endAbsoluteX", &RuntimeType::length(), exec_state)?;
let end_absolute_y: Option<TyF64> =
args.get_kw_arg_opt_typed("endAbsoluteY", &RuntimeType::length(), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::sketch(), exec_state)?;
let angle: TyF64 = args.get_kw_arg("angle", &RuntimeType::degrees(), exec_state)?;
let length: Option<TyF64> = args.get_kw_arg_opt("length", &RuntimeType::length(), exec_state)?;
let length_x: Option<TyF64> = args.get_kw_arg_opt("lengthX", &RuntimeType::length(), exec_state)?;
let length_y: Option<TyF64> = args.get_kw_arg_opt("lengthY", &RuntimeType::length(), exec_state)?;
let end_absolute_x: Option<TyF64> = args.get_kw_arg_opt("endAbsoluteX", &RuntimeType::length(), exec_state)?;
let end_absolute_y: Option<TyF64> = args.get_kw_arg_opt("endAbsoluteY", &RuntimeType::length(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let new_sketch = inner_angled_line(
sketch,
@ -686,13 +682,11 @@ async fn inner_angled_line_to_y(
/// Draw an angled line that intersects with a given line.
pub async fn angled_line_that_intersects(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let angle: TyF64 = args.get_kw_arg_typed("angle", &RuntimeType::angle(), exec_state)?;
let intersect_tag: TagIdentifier =
args.get_kw_arg_typed("intersectTag", &RuntimeType::tag_identifier(), exec_state)?;
let offset = args.get_kw_arg_opt_typed("offset", &RuntimeType::length(), exec_state)?;
let tag: Option<TagNode> = args.get_kw_arg_opt("tag")?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let angle: TyF64 = args.get_kw_arg("angle", &RuntimeType::angle(), exec_state)?;
let intersect_tag: TagIdentifier = args.get_kw_arg("intersectTag", &RuntimeType::tag_identifier(), exec_state)?;
let offset = args.get_kw_arg_opt("offset", &RuntimeType::length(), exec_state)?;
let tag: Option<TagNode> = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let new_sketch =
inner_angled_line_that_intersects(sketch, angle, intersect_tag, offset, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
@ -777,12 +771,12 @@ pub enum PlaneData {
/// Start a sketch on a specific plane or face.
pub async fn start_sketch_on(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let data = args.get_unlabeled_kw_arg_typed(
let data = args.get_unlabeled_kw_arg(
"planeOrSolid",
&RuntimeType::Union(vec![RuntimeType::solid(), RuntimeType::plane()]),
exec_state,
)?;
let face = args.get_kw_arg_opt_typed("face", &RuntimeType::tag(), exec_state)?;
let face = args.get_kw_arg_opt("face", &RuntimeType::tag(), exec_state)?;
match inner_start_sketch_on(data, face, exec_state, &args).await? {
SketchSurface::Plane(value) => Ok(KclValue::Plane { value }),
@ -901,13 +895,13 @@ async fn make_sketch_plane_from_orientation(
/// Start a new profile at a given point.
pub async fn start_profile(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch_surface = args.get_unlabeled_kw_arg_typed(
let sketch_surface = args.get_unlabeled_kw_arg(
"startProfileOn",
&RuntimeType::Union(vec![RuntimeType::plane(), RuntimeType::face()]),
exec_state,
)?;
let start: [TyF64; 2] = args.get_kw_arg_typed("at", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
let start: [TyF64; 2] = args.get_kw_arg("at", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let sketch = inner_start_profile(sketch_surface, start, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
@ -1031,7 +1025,7 @@ pub(crate) async fn inner_start_profile(
/// Returns the X component of the sketch profile start point.
pub async fn profile_start_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch: Sketch = args.get_unlabeled_kw_arg_typed("profile", &RuntimeType::sketch(), exec_state)?;
let sketch: Sketch = args.get_unlabeled_kw_arg("profile", &RuntimeType::sketch(), exec_state)?;
let ty = sketch.units.into();
let x = inner_profile_start_x(sketch)?;
Ok(args.make_user_val_from_f64_with_type(TyF64::new(x, ty)))
@ -1043,7 +1037,7 @@ pub(crate) fn inner_profile_start_x(profile: Sketch) -> Result<f64, KclError> {
/// Returns the Y component of the sketch profile start point.
pub async fn profile_start_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch: Sketch = args.get_unlabeled_kw_arg_typed("profile", &RuntimeType::sketch(), exec_state)?;
let sketch: Sketch = args.get_unlabeled_kw_arg("profile", &RuntimeType::sketch(), exec_state)?;
let ty = sketch.units.into();
let x = inner_profile_start_y(sketch)?;
Ok(args.make_user_val_from_f64_with_type(TyF64::new(x, ty)))
@ -1055,7 +1049,7 @@ pub(crate) fn inner_profile_start_y(profile: Sketch) -> Result<f64, KclError> {
/// Returns the sketch profile start point.
pub async fn profile_start(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch: Sketch = args.get_unlabeled_kw_arg_typed("profile", &RuntimeType::sketch(), exec_state)?;
let sketch: Sketch = args.get_unlabeled_kw_arg("profile", &RuntimeType::sketch(), exec_state)?;
let ty = sketch.units.into();
let point = inner_profile_start(sketch)?;
Ok(KclValue::from_point2d(point, ty, args.into()))
@ -1067,9 +1061,8 @@ pub(crate) fn inner_profile_start(profile: Sketch) -> Result<[f64; 2], KclError>
/// Close the current sketch.
pub async fn close(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let new_sketch = inner_close(sketch, tag, exec_state, args).await?;
Ok(KclValue::Sketch {
value: Box::new(new_sketch),
@ -1115,18 +1108,16 @@ pub(crate) async fn inner_close(
/// Draw an arc.
pub async fn arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let angle_start: Option<TyF64> = args.get_kw_arg_opt_typed("angleStart", &RuntimeType::degrees(), exec_state)?;
let angle_end: Option<TyF64> = args.get_kw_arg_opt_typed("angleEnd", &RuntimeType::degrees(), exec_state)?;
let radius: Option<TyF64> = args.get_kw_arg_opt_typed("radius", &RuntimeType::length(), exec_state)?;
let diameter: Option<TyF64> = args.get_kw_arg_opt_typed("diameter", &RuntimeType::length(), exec_state)?;
let end_absolute: Option<[TyF64; 2]> =
args.get_kw_arg_opt_typed("endAbsolute", &RuntimeType::point2d(), exec_state)?;
let angle_start: Option<TyF64> = args.get_kw_arg_opt("angleStart", &RuntimeType::degrees(), exec_state)?;
let angle_end: Option<TyF64> = args.get_kw_arg_opt("angleEnd", &RuntimeType::degrees(), exec_state)?;
let radius: Option<TyF64> = args.get_kw_arg_opt("radius", &RuntimeType::length(), exec_state)?;
let diameter: Option<TyF64> = args.get_kw_arg_opt("diameter", &RuntimeType::length(), exec_state)?;
let end_absolute: Option<[TyF64; 2]> = args.get_kw_arg_opt("endAbsolute", &RuntimeType::point2d(), exec_state)?;
let interior_absolute: Option<[TyF64; 2]> =
args.get_kw_arg_opt_typed("interiorAbsolute", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
args.get_kw_arg_opt("interiorAbsolute", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let new_sketch = inner_arc(
sketch,
angle_start,
@ -1307,14 +1298,13 @@ pub async fn relative_arc(
/// Draw a tangential arc to a specific point.
pub async fn tangential_arc(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let end = args.get_kw_arg_opt_typed("end", &RuntimeType::point2d(), exec_state)?;
let end_absolute = args.get_kw_arg_opt_typed("endAbsolute", &RuntimeType::point2d(), exec_state)?;
let radius = args.get_kw_arg_opt_typed("radius", &RuntimeType::length(), exec_state)?;
let diameter = args.get_kw_arg_opt_typed("diameter", &RuntimeType::length(), exec_state)?;
let angle = args.get_kw_arg_opt_typed("angle", &RuntimeType::angle(), exec_state)?;
let tag = args.get_kw_arg_opt(NEW_TAG_KW)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let end = args.get_kw_arg_opt("end", &RuntimeType::point2d(), exec_state)?;
let end_absolute = args.get_kw_arg_opt("endAbsolute", &RuntimeType::point2d(), exec_state)?;
let radius = args.get_kw_arg_opt("radius", &RuntimeType::length(), exec_state)?;
let diameter = args.get_kw_arg_opt("diameter", &RuntimeType::length(), exec_state)?;
let angle = args.get_kw_arg_opt("angle", &RuntimeType::angle(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let new_sketch = inner_tangential_arc(
sketch,
@ -1563,15 +1553,14 @@ async fn inner_tangential_arc_to_point(
/// Draw a bezier curve.
pub async fn bezier_curve(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let control1 = args.get_kw_arg_opt_typed("control1", &RuntimeType::point2d(), exec_state)?;
let control2 = args.get_kw_arg_opt_typed("control2", &RuntimeType::point2d(), exec_state)?;
let end = args.get_kw_arg_opt_typed("end", &RuntimeType::point2d(), exec_state)?;
let control1_absolute = args.get_kw_arg_opt_typed("control1Absolute", &RuntimeType::point2d(), exec_state)?;
let control2_absolute = args.get_kw_arg_opt_typed("control2Absolute", &RuntimeType::point2d(), exec_state)?;
let end_absolute = args.get_kw_arg_opt_typed("endAbsolute", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt("tag")?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let control1 = args.get_kw_arg_opt("control1", &RuntimeType::point2d(), exec_state)?;
let control2 = args.get_kw_arg_opt("control2", &RuntimeType::point2d(), exec_state)?;
let end = args.get_kw_arg_opt("end", &RuntimeType::point2d(), exec_state)?;
let control1_absolute = args.get_kw_arg_opt("control1Absolute", &RuntimeType::point2d(), exec_state)?;
let control2_absolute = args.get_kw_arg_opt("control2Absolute", &RuntimeType::point2d(), exec_state)?;
let end_absolute = args.get_kw_arg_opt("endAbsolute", &RuntimeType::point2d(), exec_state)?;
let tag = args.get_kw_arg_opt("tag", &RuntimeType::tag_decl(), exec_state)?;
let new_sketch = inner_bezier_curve(
sketch,
@ -1689,10 +1678,9 @@ async fn inner_bezier_curve(
/// Use a sketch to cut a hole in another sketch.
pub async fn subtract_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketch =
args.get_unlabeled_kw_arg_typed("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let sketch = args.get_unlabeled_kw_arg("sketch", &RuntimeType::Primitive(PrimitiveType::Sketch), exec_state)?;
let tool: Vec<Sketch> = args.get_kw_arg_typed(
let tool: Vec<Sketch> = args.get_kw_arg(
"tool",
&RuntimeType::Array(
Box::new(RuntimeType::Primitive(PrimitiveType::Sketch)),

View File

@ -29,17 +29,17 @@ pub enum SweepPath {
/// Extrude a sketch along a path.
pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let path: SweepPath = args.get_kw_arg_typed(
let sketches = args.get_unlabeled_kw_arg("sketches", &RuntimeType::sketches(), exec_state)?;
let path: SweepPath = args.get_kw_arg(
"path",
&RuntimeType::Union(vec![RuntimeType::sketch(), RuntimeType::helix()]),
exec_state,
)?;
let sectional = args.get_kw_arg_opt_typed("sectional", &RuntimeType::bool(), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt_typed("tolerance", &RuntimeType::length(), exec_state)?;
let relative_to: Option<String> = args.get_kw_arg_opt_typed("relativeTo", &RuntimeType::string(), exec_state)?;
let tag_start = args.get_kw_arg_opt("tagStart")?;
let tag_end = args.get_kw_arg_opt("tagEnd")?;
let sectional = args.get_kw_arg_opt("sectional", &RuntimeType::bool(), exec_state)?;
let tolerance: Option<TyF64> = args.get_kw_arg_opt("tolerance", &RuntimeType::length(), exec_state)?;
let relative_to: Option<String> = args.get_kw_arg_opt("relativeTo", &RuntimeType::string(), exec_state)?;
let tag_start = args.get_kw_arg_opt("tagStart", &RuntimeType::tag_decl(), exec_state)?;
let tag_end = args.get_kw_arg_opt("tagEnd", &RuntimeType::tag_decl(), exec_state)?;
let value = inner_sweep(
sketches,

View File

@ -21,7 +21,7 @@ use crate::{
/// Scale a solid or a sketch.
pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let objects = args.get_unlabeled_kw_arg_typed(
let objects = args.get_unlabeled_kw_arg(
"objects",
&RuntimeType::Union(vec![
RuntimeType::sketches(),
@ -30,10 +30,10 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
]),
exec_state,
)?;
let scale_x: Option<TyF64> = args.get_kw_arg_opt_typed("x", &RuntimeType::count(), exec_state)?;
let scale_y: Option<TyF64> = args.get_kw_arg_opt_typed("y", &RuntimeType::count(), exec_state)?;
let scale_z: Option<TyF64> = args.get_kw_arg_opt_typed("z", &RuntimeType::count(), exec_state)?;
let global = args.get_kw_arg_opt_typed("global", &RuntimeType::bool(), exec_state)?;
let scale_x: Option<TyF64> = args.get_kw_arg_opt("x", &RuntimeType::count(), exec_state)?;
let scale_y: Option<TyF64> = args.get_kw_arg_opt("y", &RuntimeType::count(), exec_state)?;
let scale_z: Option<TyF64> = args.get_kw_arg_opt("z", &RuntimeType::count(), exec_state)?;
let global = args.get_kw_arg_opt("global", &RuntimeType::bool(), exec_state)?;
// Ensure at least one scale value is provided.
if scale_x.is_none() && scale_y.is_none() && scale_z.is_none() {
@ -103,7 +103,7 @@ async fn inner_scale(
/// Move a solid or a sketch.
pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let objects = args.get_unlabeled_kw_arg_typed(
let objects = args.get_unlabeled_kw_arg(
"objects",
&RuntimeType::Union(vec![
RuntimeType::sketches(),
@ -112,10 +112,10 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
]),
exec_state,
)?;
let translate_x: Option<TyF64> = args.get_kw_arg_opt_typed("x", &RuntimeType::length(), exec_state)?;
let translate_y: Option<TyF64> = args.get_kw_arg_opt_typed("y", &RuntimeType::length(), exec_state)?;
let translate_z: Option<TyF64> = args.get_kw_arg_opt_typed("z", &RuntimeType::length(), exec_state)?;
let global = args.get_kw_arg_opt_typed("global", &RuntimeType::bool(), exec_state)?;
let translate_x: Option<TyF64> = args.get_kw_arg_opt("x", &RuntimeType::length(), exec_state)?;
let translate_y: Option<TyF64> = args.get_kw_arg_opt("y", &RuntimeType::length(), exec_state)?;
let translate_z: Option<TyF64> = args.get_kw_arg_opt("z", &RuntimeType::length(), exec_state)?;
let global = args.get_kw_arg_opt("global", &RuntimeType::bool(), exec_state)?;
// Ensure at least one translation value is provided.
if translate_x.is_none() && translate_y.is_none() && translate_z.is_none() {
@ -176,7 +176,7 @@ async fn inner_translate(
/// Rotate a solid or a sketch.
pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let objects = args.get_unlabeled_kw_arg_typed(
let objects = args.get_unlabeled_kw_arg(
"objects",
&RuntimeType::Union(vec![
RuntimeType::sketches(),
@ -185,10 +185,10 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
]),
exec_state,
)?;
let roll: Option<TyF64> = args.get_kw_arg_opt_typed("roll", &RuntimeType::degrees(), exec_state)?;
let pitch: Option<TyF64> = args.get_kw_arg_opt_typed("pitch", &RuntimeType::degrees(), exec_state)?;
let yaw: Option<TyF64> = args.get_kw_arg_opt_typed("yaw", &RuntimeType::degrees(), exec_state)?;
let axis: Option<Axis3dOrPoint3d> = args.get_kw_arg_opt_typed(
let roll: Option<TyF64> = args.get_kw_arg_opt("roll", &RuntimeType::degrees(), exec_state)?;
let pitch: Option<TyF64> = args.get_kw_arg_opt("pitch", &RuntimeType::degrees(), exec_state)?;
let yaw: Option<TyF64> = args.get_kw_arg_opt("yaw", &RuntimeType::degrees(), exec_state)?;
let axis: Option<Axis3dOrPoint3d> = args.get_kw_arg_opt(
"axis",
&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Axis3d),
@ -197,8 +197,8 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
exec_state,
)?;
let axis = axis.map(|a| a.to_point3d());
let angle: Option<TyF64> = args.get_kw_arg_opt_typed("angle", &RuntimeType::degrees(), exec_state)?;
let global = args.get_kw_arg_opt_typed("global", &RuntimeType::bool(), exec_state)?;
let angle: Option<TyF64> = args.get_kw_arg_opt("angle", &RuntimeType::degrees(), exec_state)?;
let global = args.get_kw_arg_opt("global", &RuntimeType::bool(), exec_state)?;
// Check if no rotation values are provided.
if roll.is_none() && pitch.is_none() && yaw.is_none() && axis.is_none() && angle.is_none() {

View File

@ -1,16 +1,26 @@
use std::fmt::Write;
use crate::parsing::{
ast::types::{
Annotation, ArrayExpression, ArrayRangeExpression, AscribedExpression, BinaryExpression, BinaryOperator,
BinaryPart, BodyItem, CallExpressionKw, CommentStyle, DefaultParamVal, Expr, FormatOptions, FunctionExpression,
IfExpression, ImportSelector, ImportStatement, ItemVisibility, LabeledArg, Literal, LiteralIdentifier,
LiteralValue, MemberExpression, MemberObject, Node, NonCodeNode, NonCodeValue, ObjectExpression, Parameter,
PipeExpression, Program, TagDeclarator, TypeDeclaration, UnaryExpression, VariableDeclaration, VariableKind,
use crate::{
parsing::{
ast::types::{
Annotation, ArrayExpression, ArrayRangeExpression, AscribedExpression, BinaryExpression, BinaryOperator,
BinaryPart, BodyItem, CallExpressionKw, CommentStyle, DefaultParamVal, Expr, FormatOptions,
FunctionExpression, IfExpression, ImportSelector, ImportStatement, ItemVisibility, LabeledArg, Literal,
LiteralIdentifier, LiteralValue, MemberExpression, Node, NonCodeNode, NonCodeValue, ObjectExpression,
Parameter, PipeExpression, Program, TagDeclarator, TypeDeclaration, UnaryExpression, VariableDeclaration,
VariableKind,
},
deprecation, DeprecationKind, PIPE_OPERATOR,
},
deprecation, DeprecationKind, PIPE_OPERATOR,
KclError, ModuleId,
};
#[allow(dead_code)]
pub fn fmt(input: &str) -> Result<String, KclError> {
let program = crate::parsing::parse_str(input, ModuleId::default()).parse_errs_as_err()?;
Ok(program.recast(&Default::default(), 0))
}
impl Program {
pub fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String {
let indentation = options.get_indentation(indentation_level);
@ -278,11 +288,11 @@ impl Expr {
ctxt = ExprContext::Other;
}
match &self {
Expr::BinaryExpression(bin_exp) => bin_exp.recast(options),
Expr::BinaryExpression(bin_exp) => bin_exp.recast(options, indentation_level, ctxt),
Expr::ArrayExpression(array_exp) => array_exp.recast(options, indentation_level, ctxt),
Expr::ArrayRangeExpression(range_exp) => range_exp.recast(options, indentation_level, ctxt),
Expr::ObjectExpression(ref obj_exp) => obj_exp.recast(options, indentation_level, ctxt),
Expr::MemberExpression(mem_exp) => mem_exp.recast(),
Expr::MemberExpression(mem_exp) => mem_exp.recast(options, indentation_level, ctxt),
Expr::Literal(literal) => literal.recast(),
Expr::FunctionExpression(func_exp) => {
let mut result = if is_decl { String::new() } else { "fn".to_owned() };
@ -299,7 +309,7 @@ impl Expr {
}
Expr::TagDeclarator(tag) => tag.recast(),
Expr::PipeExpression(pipe_exp) => pipe_exp.recast(options, indentation_level),
Expr::UnaryExpression(unary_exp) => unary_exp.recast(options),
Expr::UnaryExpression(unary_exp) => unary_exp.recast(options, indentation_level, ctxt),
Expr::IfExpression(e) => e.recast(options, indentation_level, ctxt),
Expr::PipeSubstitution(_) => crate::parsing::PIPE_SUBSTITUTION_OPERATOR.to_string(),
Expr::LabelledExpression(e) => {
@ -332,7 +342,7 @@ impl AscribedExpression {
}
impl BinaryPart {
fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String {
fn recast(&self, options: &FormatOptions, indentation_level: usize, ctxt: ExprContext) -> String {
match &self {
BinaryPart::Literal(literal) => literal.recast(),
BinaryPart::Name(name) => {
@ -342,12 +352,16 @@ impl BinaryPart {
None => result,
}
}
BinaryPart::BinaryExpression(binary_expression) => binary_expression.recast(options),
BinaryPart::BinaryExpression(binary_expression) => {
binary_expression.recast(options, indentation_level, ctxt)
}
BinaryPart::CallExpressionKw(call_expression) => {
call_expression.recast(options, indentation_level, ExprContext::Other)
}
BinaryPart::UnaryExpression(unary_expression) => unary_expression.recast(options),
BinaryPart::MemberExpression(member_expression) => member_expression.recast(),
BinaryPart::UnaryExpression(unary_expression) => unary_expression.recast(options, indentation_level, ctxt),
BinaryPart::MemberExpression(member_expression) => {
member_expression.recast(options, indentation_level, ctxt)
}
BinaryPart::IfExpression(e) => e.recast(options, indentation_level, ExprContext::Other),
BinaryPart::AscribedExpression(e) => e.recast(options, indentation_level, ExprContext::Other),
}
@ -670,7 +684,7 @@ impl ObjectExpression {
}
impl MemberExpression {
fn recast(&self) -> String {
fn recast(&self, options: &FormatOptions, indentation_level: usize, ctxt: ExprContext) -> String {
let key_str = match &self.property {
LiteralIdentifier::Identifier(identifier) => {
if self.computed {
@ -682,15 +696,12 @@ impl MemberExpression {
LiteralIdentifier::Literal(lit) => format!("[{}]", &(*lit.raw)),
};
match &self.object {
MemberObject::MemberExpression(member_exp) => member_exp.recast() + key_str.as_str(),
MemberObject::Identifier(identifier) => identifier.name.to_string() + key_str.as_str(),
}
self.object.recast(options, indentation_level, ctxt) + key_str.as_str()
}
}
impl BinaryExpression {
fn recast(&self, options: &FormatOptions) -> String {
fn recast(&self, options: &FormatOptions, _indentation_level: usize, ctxt: ExprContext) -> String {
let maybe_wrap_it = |a: String, doit: bool| -> String {
if doit {
format!("({})", a)
@ -715,15 +726,15 @@ impl BinaryExpression {
format!(
"{} {} {}",
maybe_wrap_it(self.left.recast(options, 0), should_wrap_left),
maybe_wrap_it(self.left.recast(options, 0, ctxt), should_wrap_left),
self.operator,
maybe_wrap_it(self.right.recast(options, 0), should_wrap_right)
maybe_wrap_it(self.right.recast(options, 0, ctxt), should_wrap_right)
)
}
}
impl UnaryExpression {
fn recast(&self, options: &FormatOptions) -> String {
fn recast(&self, options: &FormatOptions, _indentation_level: usize, ctxt: ExprContext) -> String {
match self.argument {
BinaryPart::Literal(_)
| BinaryPart::Name(_)
@ -731,10 +742,10 @@ impl UnaryExpression {
| BinaryPart::IfExpression(_)
| BinaryPart::AscribedExpression(_)
| BinaryPart::CallExpressionKw(_) => {
format!("{}{}", &self.operator, self.argument.recast(options, 0))
format!("{}{}", &self.operator, self.argument.recast(options, 0, ctxt))
}
BinaryPart::BinaryExpression(_) | BinaryPart::UnaryExpression(_) => {
format!("{}({})", &self.operator, self.argument.recast(options, 0))
format!("{}({})", &self.operator, self.argument.recast(options, 0, ctxt))
}
}
}

View File

@ -226,15 +226,6 @@ impl<'tree> From<&'tree types::BinaryPart> for Node<'tree> {
}
}
impl<'tree> From<&'tree types::MemberObject> for Node<'tree> {
fn from(node: &'tree types::MemberObject) -> Self {
match node {
types::MemberObject::MemberExpression(me) => me.as_ref().into(),
types::MemberObject::Identifier(id) => id.as_ref().into(),
}
}
}
impl<'tree> From<&'tree types::LiteralIdentifier> for Node<'tree> {
fn from(node: &'tree types::LiteralIdentifier) -> Self {
match node {