@ -20,7 +20,7 @@ statement[@isGroup=Statement] {
|
|||||||
ImportStatement { kw<"import"> ImportItems ImportFrom String } |
|
ImportStatement { kw<"import"> ImportItems ImportFrom String } |
|
||||||
FunctionDeclaration { kw<"export">? kw<"fn"> VariableDefinition Equals? ParamList Arrow? Body } |
|
FunctionDeclaration { kw<"export">? kw<"fn"> VariableDefinition Equals? ParamList Arrow? Body } |
|
||||||
VariableDeclaration { kw<"export">? (kw<"var"> | kw<"let"> | kw<"const">)? VariableDefinition Equals expression } |
|
VariableDeclaration { kw<"export">? (kw<"var"> | kw<"let"> | kw<"const">)? VariableDefinition Equals expression } |
|
||||||
TypeDeclaration { kw<"export">? kw<"type"> identifier } |
|
TypeDeclaration { kw<"export">? kw<"type"> identifier ("=" type)? } |
|
||||||
ReturnStatement { kw<"return"> expression } |
|
ReturnStatement { kw<"return"> expression } |
|
||||||
ExpressionStatement { expression } |
|
ExpressionStatement { expression } |
|
||||||
Annotation { AnnotationName AnnotationList? }
|
Annotation { AnnotationName AnnotationList? }
|
||||||
@ -79,7 +79,7 @@ type[@isGroup=Type] {
|
|||||||
identifier,
|
identifier,
|
||||||
"bool" | "number" | "string" | "tag" | "Sketch" | "SketchSurface" | "Solid" | "Plane"
|
"bool" | "number" | "string" | "tag" | "Sketch" | "SketchSurface" | "Solid" | "Plane"
|
||||||
> |
|
> |
|
||||||
ArrayType { type !member "[" "]" } |
|
ArrayType { "[" type !member (";" Number "+"?)? "]" } |
|
||||||
ObjectType { "{" commaSep<ObjectProperty { PropertyName ":" type }> "}" }
|
ObjectType { "{" commaSep<ObjectProperty { PropertyName ":" type }> "}" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ commaSep1NoTrailingComma<term> { term ("," term)* }
|
|||||||
"(" ")"
|
"(" ")"
|
||||||
"{" "}"
|
"{" "}"
|
||||||
"[" "]"
|
"[" "]"
|
||||||
"," "?" ":" "." ".."
|
"," "?" ":" "." ".." ";"
|
||||||
}
|
}
|
||||||
|
|
||||||
@external propSource kclHighlight from "./highlight"
|
@external propSource kclHighlight from "./highlight"
|
||||||
|
@ -29,6 +29,8 @@ use crate::{
|
|||||||
CompilationError,
|
CompilationError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::kcl_value::TypeDef;
|
||||||
|
|
||||||
enum StatementKind<'a> {
|
enum StatementKind<'a> {
|
||||||
Declaration { name: &'a str },
|
Declaration { name: &'a str },
|
||||||
Expression,
|
Expression,
|
||||||
@ -304,8 +306,9 @@ impl ExecutorContext {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let (t, props) = crate::std::std_ty(std_path, &ty.name.name);
|
||||||
let value = KclValue::Type {
|
let value = KclValue::Type {
|
||||||
value: Some(crate::std::std_ty(std_path, &ty.name.name)),
|
value: TypeDef::RustRepr(t, props),
|
||||||
meta: vec![metadata],
|
meta: vec![metadata],
|
||||||
};
|
};
|
||||||
exec_state
|
exec_state
|
||||||
@ -324,12 +327,40 @@ impl ExecutorContext {
|
|||||||
}
|
}
|
||||||
// Do nothing for primitive types, they get special treatment and their declarations are just for documentation.
|
// Do nothing for primitive types, they get special treatment and their declarations are just for documentation.
|
||||||
annotations::Impl::Primitive => {}
|
annotations::Impl::Primitive => {}
|
||||||
annotations::Impl::Kcl => {
|
annotations::Impl::Kcl => match &ty.alias {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
Some(alias) => {
|
||||||
message: "User-defined types are not yet supported.".to_owned(),
|
let value = KclValue::Type {
|
||||||
source_ranges: vec![metadata.source_range],
|
value: TypeDef::Alias(
|
||||||
}));
|
RuntimeType::from_parsed(
|
||||||
}
|
alias.inner.clone(),
|
||||||
|
exec_state,
|
||||||
|
metadata.source_range,
|
||||||
|
)
|
||||||
|
.map_err(|e| KclError::Semantic(e.into()))?,
|
||||||
|
),
|
||||||
|
meta: vec![metadata],
|
||||||
|
};
|
||||||
|
exec_state
|
||||||
|
.mut_stack()
|
||||||
|
.add(
|
||||||
|
format!("{}{}", memory::TYPE_PREFIX, ty.name.name),
|
||||||
|
value,
|
||||||
|
metadata.source_range,
|
||||||
|
)
|
||||||
|
.map_err(|_| {
|
||||||
|
KclError::Semantic(KclErrorDetails {
|
||||||
|
message: format!("Redefinition of type {}.", ty.name.name),
|
||||||
|
source_ranges: vec![metadata.source_range],
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
|
message: "User-defined types are not yet supported.".to_owned(),
|
||||||
|
source_ranges: vec![metadata.source_range],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
last_expr = None;
|
last_expr = None;
|
||||||
@ -646,30 +677,28 @@ impl ExecutorContext {
|
|||||||
let result = self
|
let result = self
|
||||||
.execute_expr(&expr.expr, exec_state, metadata, &[], statement_kind)
|
.execute_expr(&expr.expr, exec_state, metadata, &[], statement_kind)
|
||||||
.await?;
|
.await?;
|
||||||
coerce(&result, &expr.ty, exec_state).ok_or_else(|| {
|
coerce(&result, &expr.ty, exec_state, expr.into())?
|
||||||
KclError::Semantic(KclErrorDetails {
|
|
||||||
message: format!(
|
|
||||||
"could not coerce {} value to type {}",
|
|
||||||
result.human_friendly_type(),
|
|
||||||
expr.ty
|
|
||||||
),
|
|
||||||
source_ranges: vec![expr.into()],
|
|
||||||
})
|
|
||||||
})?
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(item)
|
Ok(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coerce(value: &KclValue, ty: &Node<Type>, exec_state: &mut ExecState) -> Option<KclValue> {
|
fn coerce(
|
||||||
|
value: &KclValue,
|
||||||
|
ty: &Node<Type>,
|
||||||
|
exec_state: &mut ExecState,
|
||||||
|
source_range: SourceRange,
|
||||||
|
) -> Result<KclValue, KclError> {
|
||||||
let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into())
|
let ty = RuntimeType::from_parsed(ty.inner.clone(), exec_state, value.into())
|
||||||
.map_err(|e| {
|
.map_err(|e| KclError::Semantic(e.into()))?;
|
||||||
exec_state.err(e);
|
|
||||||
})
|
|
||||||
.ok()??;
|
|
||||||
|
|
||||||
value.coerce(&ty, exec_state)
|
value.coerce(&ty, exec_state).ok_or_else(|| {
|
||||||
|
KclError::Semantic(KclErrorDetails {
|
||||||
|
message: format!("could not coerce {} value to type {}", value.human_friendly_type(), ty),
|
||||||
|
source_ranges: vec![source_range],
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BinaryPart {
|
impl BinaryPart {
|
||||||
|
@ -104,7 +104,7 @@ impl From<SolidOrSketchOrImportedGeometry> for crate::execution::KclValue {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|s| crate::execution::KclValue::Solid { value: Box::new(s) })
|
.map(|s| crate::execution::KclValue::Solid { value: Box::new(s) })
|
||||||
.collect(),
|
.collect(),
|
||||||
ty: crate::execution::PrimitiveType::Solid,
|
ty: crate::execution::kcl_value::RuntimeType::solid(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ pub enum KclValue {
|
|||||||
value: Vec<KclValue>,
|
value: Vec<KclValue>,
|
||||||
// The type of values, not the array type.
|
// The type of values, not the array type.
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
ty: PrimitiveType,
|
ty: RuntimeType,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
value: KclObjectFields,
|
value: KclObjectFields,
|
||||||
@ -105,7 +105,7 @@ pub enum KclValue {
|
|||||||
#[ts(skip)]
|
#[ts(skip)]
|
||||||
Type {
|
Type {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
value: Option<(PrimitiveType, StdFnProps)>,
|
value: TypeDef,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
meta: Vec<Metadata>,
|
meta: Vec<Metadata>,
|
||||||
},
|
},
|
||||||
@ -142,6 +142,12 @@ impl JsonSchema for FunctionSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum TypeDef {
|
||||||
|
RustRepr(PrimitiveType, StdFnProps),
|
||||||
|
Alias(RuntimeType),
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Vec<Sketch>> for KclValue {
|
impl From<Vec<Sketch>> for KclValue {
|
||||||
fn from(mut eg: Vec<Sketch>) -> Self {
|
fn from(mut eg: Vec<Sketch>) -> Self {
|
||||||
if eg.len() == 1 {
|
if eg.len() == 1 {
|
||||||
@ -154,7 +160,7 @@ impl From<Vec<Sketch>> for KclValue {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|s| KclValue::Sketch { value: Box::new(s) })
|
.map(|s| KclValue::Sketch { value: Box::new(s) })
|
||||||
.collect(),
|
.collect(),
|
||||||
ty: crate::execution::PrimitiveType::Sketch,
|
ty: RuntimeType::Primitive(PrimitiveType::Sketch),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +175,7 @@ impl From<Vec<Solid>> for KclValue {
|
|||||||
} else {
|
} else {
|
||||||
KclValue::HomArray {
|
KclValue::HomArray {
|
||||||
value: eg.into_iter().map(|s| KclValue::Solid { value: Box::new(s) }).collect(),
|
value: eg.into_iter().map(|s| KclValue::Solid { value: Box::new(s) }).collect(),
|
||||||
ty: crate::execution::PrimitiveType::Solid,
|
ty: RuntimeType::Primitive(PrimitiveType::Solid),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -635,10 +641,15 @@ impl KclValue {
|
|||||||
KclValue::ImportedGeometry { .. } => Some(value.clone()),
|
KclValue::ImportedGeometry { .. } => Some(value.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
PrimitiveType::Tag => match value {
|
||||||
|
KclValue::TagDeclarator { .. } => Some(value.clone()),
|
||||||
|
KclValue::TagIdentifier { .. } => Some(value.clone()),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coerce_to_array_type(&self, ty: &PrimitiveType, len: ArrayLen, exec_state: &mut ExecState) -> Option<KclValue> {
|
fn coerce_to_array_type(&self, ty: &RuntimeType, len: ArrayLen, exec_state: &mut ExecState) -> Option<KclValue> {
|
||||||
match self {
|
match self {
|
||||||
KclValue::HomArray { value, ty: aty } => {
|
KclValue::HomArray { value, ty: aty } => {
|
||||||
// TODO could check types of values individually
|
// TODO could check types of values individually
|
||||||
@ -685,10 +696,9 @@ impl KclValue {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let rt = RuntimeType::Primitive(ty.clone());
|
|
||||||
let value = value
|
let value = value
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| v.coerce(&rt, exec_state))
|
.map(|v| v.coerce(ty, exec_state))
|
||||||
.collect::<Option<Vec<_>>>()?;
|
.collect::<Option<Vec<_>>>()?;
|
||||||
|
|
||||||
Some(KclValue::HomArray { value, ty: ty.clone() })
|
Some(KclValue::HomArray { value, ty: ty.clone() })
|
||||||
@ -698,7 +708,7 @@ impl KclValue {
|
|||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
}),
|
}),
|
||||||
value if len.satisfied(1) => {
|
value if len.satisfied(1) => {
|
||||||
if value.has_type(&RuntimeType::Primitive(ty.clone())) {
|
if value.has_type(ty) {
|
||||||
Some(KclValue::HomArray {
|
Some(KclValue::HomArray {
|
||||||
value: vec![value.clone()],
|
value: vec![value.clone()],
|
||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
@ -711,7 +721,7 @@ impl KclValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn coerce_to_tuple_type(&self, tys: &[PrimitiveType], exec_state: &mut ExecState) -> Option<KclValue> {
|
fn coerce_to_tuple_type(&self, tys: &[RuntimeType], exec_state: &mut ExecState) -> Option<KclValue> {
|
||||||
match self {
|
match self {
|
||||||
KclValue::MixedArray { value, .. } | KclValue::HomArray { value, .. } => {
|
KclValue::MixedArray { value, .. } | KclValue::HomArray { value, .. } => {
|
||||||
if value.len() < tys.len() {
|
if value.len() < tys.len() {
|
||||||
@ -719,7 +729,7 @@ impl KclValue {
|
|||||||
}
|
}
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for (i, t) in tys.iter().enumerate() {
|
for (i, t) in tys.iter().enumerate() {
|
||||||
result.push(value[i].coerce_to_primitive_type(t, exec_state)?);
|
result.push(value[i].coerce(t, exec_state)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(KclValue::MixedArray {
|
Some(KclValue::MixedArray {
|
||||||
@ -732,7 +742,7 @@ impl KclValue {
|
|||||||
meta: meta.clone(),
|
meta: meta.clone(),
|
||||||
}),
|
}),
|
||||||
value if tys.len() == 1 => {
|
value if tys.len() == 1 => {
|
||||||
if value.has_type(&RuntimeType::Primitive(tys[0].clone())) {
|
if value.has_type(&tys[0]) {
|
||||||
Some(KclValue::MixedArray {
|
Some(KclValue::MixedArray {
|
||||||
value: vec![value.clone()],
|
value: vec![value.clone()],
|
||||||
meta: Vec::new(),
|
meta: Vec::new(),
|
||||||
@ -788,18 +798,15 @@ impl KclValue {
|
|||||||
KclValue::Solid { .. } => Some(RuntimeType::Primitive(PrimitiveType::Solid)),
|
KclValue::Solid { .. } => Some(RuntimeType::Primitive(PrimitiveType::Solid)),
|
||||||
KclValue::ImportedGeometry(..) => Some(RuntimeType::Primitive(PrimitiveType::ImportedGeometry)),
|
KclValue::ImportedGeometry(..) => Some(RuntimeType::Primitive(PrimitiveType::ImportedGeometry)),
|
||||||
KclValue::MixedArray { value, .. } => Some(RuntimeType::Tuple(
|
KclValue::MixedArray { value, .. } => Some(RuntimeType::Tuple(
|
||||||
value
|
value.iter().map(|v| v.principal_type()).collect::<Option<Vec<_>>>()?,
|
||||||
.iter()
|
|
||||||
.map(|v| v.principal_type().and_then(RuntimeType::primitive))
|
|
||||||
.collect::<Option<Vec<_>>>()?,
|
|
||||||
)),
|
)),
|
||||||
KclValue::HomArray { ty, value, .. } => Some(RuntimeType::Array(ty.clone(), ArrayLen::Known(value.len()))),
|
KclValue::HomArray { ty, value, .. } => {
|
||||||
KclValue::Face { .. } => None,
|
Some(RuntimeType::Array(Box::new(ty.clone()), ArrayLen::Known(value.len())))
|
||||||
KclValue::Helix { .. }
|
}
|
||||||
| KclValue::Function { .. }
|
KclValue::TagIdentifier(_) | KclValue::TagDeclarator(_) => Some(RuntimeType::Primitive(PrimitiveType::Tag)),
|
||||||
|
KclValue::Face { .. } | KclValue::Helix { .. } => None,
|
||||||
|
KclValue::Function { .. }
|
||||||
| KclValue::Module { .. }
|
| KclValue::Module { .. }
|
||||||
| KclValue::TagIdentifier(_)
|
|
||||||
| KclValue::TagDeclarator(_)
|
|
||||||
| KclValue::KclNone { .. }
|
| KclValue::KclNone { .. }
|
||||||
| KclValue::Type { .. }
|
| KclValue::Type { .. }
|
||||||
| KclValue::Uuid { .. } => None,
|
| KclValue::Uuid { .. } => None,
|
||||||
@ -923,42 +930,89 @@ impl KclValue {
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum RuntimeType {
|
pub enum RuntimeType {
|
||||||
Primitive(PrimitiveType),
|
Primitive(PrimitiveType),
|
||||||
Array(PrimitiveType, ArrayLen),
|
Array(Box<RuntimeType>, ArrayLen),
|
||||||
Union(Vec<RuntimeType>),
|
Union(Vec<RuntimeType>),
|
||||||
Tuple(Vec<PrimitiveType>),
|
Tuple(Vec<RuntimeType>),
|
||||||
Object(Vec<(String, RuntimeType)>),
|
Object(Vec<(String, RuntimeType)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RuntimeType {
|
impl RuntimeType {
|
||||||
|
/// `[Sketch; 1+]`
|
||||||
|
pub fn sketches() -> Self {
|
||||||
|
RuntimeType::Array(
|
||||||
|
Box::new(RuntimeType::Primitive(PrimitiveType::Sketch)),
|
||||||
|
ArrayLen::NonEmpty,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `[Solid; 1+]`
|
||||||
|
pub fn solids() -> Self {
|
||||||
|
RuntimeType::Array(
|
||||||
|
Box::new(RuntimeType::Primitive(PrimitiveType::Solid)),
|
||||||
|
ArrayLen::NonEmpty,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn solid() -> Self {
|
||||||
|
RuntimeType::Primitive(PrimitiveType::Solid)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn imported() -> Self {
|
||||||
|
RuntimeType::Primitive(PrimitiveType::ImportedGeometry)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_parsed(
|
pub fn from_parsed(
|
||||||
value: Type,
|
value: Type,
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<Option<Self>, CompilationError> {
|
) -> Result<Self, CompilationError> {
|
||||||
Ok(match value {
|
match value {
|
||||||
Type::Primitive(pt) => {
|
Type::Primitive(pt) => Self::from_parsed_primitive(pt, exec_state, source_range),
|
||||||
PrimitiveType::from_parsed(pt, exec_state, source_range)?.map(RuntimeType::Primitive)
|
|
||||||
}
|
|
||||||
Type::Array { ty, len } => {
|
Type::Array { ty, len } => {
|
||||||
PrimitiveType::from_parsed(ty, exec_state, source_range)?.map(|t| RuntimeType::Array(t, len))
|
Self::from_parsed_primitive(ty, exec_state, source_range).map(|t| RuntimeType::Array(Box::new(t), len))
|
||||||
}
|
}
|
||||||
Type::Union { tys } => tys
|
Type::Union { tys } => tys
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|t| PrimitiveType::from_parsed(t.inner, exec_state, source_range))
|
.map(|t| Self::from_parsed_primitive(t.inner, exec_state, source_range))
|
||||||
.collect::<Result<Option<Vec<_>>, CompilationError>>()?
|
.collect::<Result<Vec<_>, CompilationError>>()
|
||||||
.map(RuntimeType::Union),
|
.map(RuntimeType::Union),
|
||||||
Type::Object { properties } => properties
|
Type::Object { properties } => properties
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
let pt = match p.type_ {
|
RuntimeType::from_parsed(p.type_.unwrap().inner, exec_state, source_range)
|
||||||
Some(t) => t,
|
.map(|ty| (p.identifier.inner.name, ty))
|
||||||
None => return Ok(None),
|
|
||||||
};
|
|
||||||
Ok(RuntimeType::from_parsed(pt.inner, exec_state, source_range)?
|
|
||||||
.map(|ty| (p.identifier.inner.name, ty)))
|
|
||||||
})
|
})
|
||||||
.collect::<Result<Option<Vec<_>>, CompilationError>>()?
|
.collect::<Result<Vec<_>, CompilationError>>()
|
||||||
.map(RuntimeType::Object),
|
.map(RuntimeType::Object),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_parsed_primitive(
|
||||||
|
value: AstPrimitiveType,
|
||||||
|
exec_state: &mut ExecState,
|
||||||
|
source_range: SourceRange,
|
||||||
|
) -> Result<Self, CompilationError> {
|
||||||
|
Ok(match value {
|
||||||
|
AstPrimitiveType::String => RuntimeType::Primitive(PrimitiveType::String),
|
||||||
|
AstPrimitiveType::Boolean => RuntimeType::Primitive(PrimitiveType::Boolean),
|
||||||
|
AstPrimitiveType::Number(suffix) => RuntimeType::Primitive(PrimitiveType::Number(
|
||||||
|
NumericType::from_parsed(suffix, &exec_state.mod_local.settings),
|
||||||
|
)),
|
||||||
|
AstPrimitiveType::Named(name) => {
|
||||||
|
let ty_val = exec_state
|
||||||
|
.stack()
|
||||||
|
.get(&format!("{}{}", memory::TYPE_PREFIX, name.name), source_range)
|
||||||
|
.map_err(|_| CompilationError::err(source_range, format!("Unknown type: {}", name.name)))?;
|
||||||
|
|
||||||
|
match ty_val {
|
||||||
|
KclValue::Type { value, .. } => match value {
|
||||||
|
TypeDef::RustRepr(ty, _) => RuntimeType::Primitive(ty.clone()),
|
||||||
|
TypeDef::Alias(ty) => ty.clone(),
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AstPrimitiveType::Tag => RuntimeType::Primitive(PrimitiveType::Tag),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -975,7 +1029,7 @@ impl RuntimeType {
|
|||||||
.join(" or "),
|
.join(" or "),
|
||||||
RuntimeType::Tuple(tys) => format!(
|
RuntimeType::Tuple(tys) => format!(
|
||||||
"an array with values of types ({})",
|
"an array with values of types ({})",
|
||||||
tys.iter().map(PrimitiveType::to_string).collect::<Vec<_>>().join(", ")
|
tys.iter().map(Self::human_friendly_type).collect::<Vec<_>>().join(", ")
|
||||||
),
|
),
|
||||||
RuntimeType::Object(_) => format!("an object with fields {}", self),
|
RuntimeType::Object(_) => format!("an object with fields {}", self),
|
||||||
}
|
}
|
||||||
@ -990,7 +1044,7 @@ impl RuntimeType {
|
|||||||
// TODO arrays could be covariant
|
// TODO arrays could be covariant
|
||||||
(Array(t1, l1), Array(t2, l2)) => t1 == t2 && l1.subtype(*l2),
|
(Array(t1, l1), Array(t2, l2)) => t1 == t2 && l1.subtype(*l2),
|
||||||
(Tuple(t1), Tuple(t2)) => t1 == t2,
|
(Tuple(t1), Tuple(t2)) => t1 == t2,
|
||||||
(Tuple(t1), Array(t2, l2)) => (l2.satisfied(t1.len())) && t1.iter().all(|t| t == t2),
|
(Tuple(t1), Array(t2, l2)) => (l2.satisfied(t1.len())) && t1.iter().all(|t| t == &**t2),
|
||||||
(Union(ts1), Union(ts2)) => ts1.iter().all(|t| ts2.contains(t)),
|
(Union(ts1), Union(ts2)) => ts1.iter().all(|t| ts2.contains(t)),
|
||||||
(t1, Union(ts2)) => ts2.contains(t1),
|
(t1, Union(ts2)) => ts2.contains(t1),
|
||||||
// TODO record subtyping - subtype can be larger, fields can be covariant.
|
// TODO record subtyping - subtype can be larger, fields can be covariant.
|
||||||
@ -999,10 +1053,17 @@ impl RuntimeType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primitive(self) -> Option<PrimitiveType> {
|
fn display_multiple(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
RuntimeType::Primitive(t) => Some(t),
|
RuntimeType::Primitive(ty) => ty.display_multiple(),
|
||||||
_ => None,
|
RuntimeType::Array(..) => "arrays".to_owned(),
|
||||||
|
RuntimeType::Union(tys) => tys
|
||||||
|
.iter()
|
||||||
|
.map(|t| t.display_multiple())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" or "),
|
||||||
|
RuntimeType::Tuple(_) => "arrays".to_owned(),
|
||||||
|
RuntimeType::Object(_) => format!("objects with fields {self}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1072,6 +1133,7 @@ pub enum PrimitiveType {
|
|||||||
Number(NumericType),
|
Number(NumericType),
|
||||||
String,
|
String,
|
||||||
Boolean,
|
Boolean,
|
||||||
|
Tag,
|
||||||
Sketch,
|
Sketch,
|
||||||
Solid,
|
Solid,
|
||||||
Plane,
|
Plane,
|
||||||
@ -1079,35 +1141,6 @@ pub enum PrimitiveType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrimitiveType {
|
impl PrimitiveType {
|
||||||
fn from_parsed(
|
|
||||||
value: AstPrimitiveType,
|
|
||||||
exec_state: &mut ExecState,
|
|
||||||
source_range: SourceRange,
|
|
||||||
) -> Result<Option<Self>, CompilationError> {
|
|
||||||
Ok(match value {
|
|
||||||
AstPrimitiveType::String => Some(PrimitiveType::String),
|
|
||||||
AstPrimitiveType::Boolean => Some(PrimitiveType::Boolean),
|
|
||||||
AstPrimitiveType::Number(suffix) => Some(PrimitiveType::Number(NumericType::from_parsed(
|
|
||||||
suffix,
|
|
||||||
&exec_state.mod_local.settings,
|
|
||||||
))),
|
|
||||||
AstPrimitiveType::Named(name) => {
|
|
||||||
let ty_val = exec_state
|
|
||||||
.stack()
|
|
||||||
.get(&format!("{}{}", memory::TYPE_PREFIX, name.name), source_range)
|
|
||||||
.map_err(|_| CompilationError::err(source_range, format!("Unknown type: {}", name.name)))?;
|
|
||||||
|
|
||||||
let (ty, _) = match ty_val {
|
|
||||||
KclValue::Type { value: Some(ty), .. } => ty,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(ty.clone())
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn display_multiple(&self) -> String {
|
fn display_multiple(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
PrimitiveType::Number(NumericType::Known(unit)) => format!("numbers({unit})"),
|
PrimitiveType::Number(NumericType::Known(unit)) => format!("numbers({unit})"),
|
||||||
@ -1118,6 +1151,7 @@ impl PrimitiveType {
|
|||||||
PrimitiveType::Solid => "Solids".to_owned(),
|
PrimitiveType::Solid => "Solids".to_owned(),
|
||||||
PrimitiveType::Plane => "Planes".to_owned(),
|
PrimitiveType::Plane => "Planes".to_owned(),
|
||||||
PrimitiveType::ImportedGeometry => "imported geometries".to_owned(),
|
PrimitiveType::ImportedGeometry => "imported geometries".to_owned(),
|
||||||
|
PrimitiveType::Tag => "tags".to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1129,6 +1163,7 @@ impl fmt::Display for PrimitiveType {
|
|||||||
PrimitiveType::Number(_) => write!(f, "number"),
|
PrimitiveType::Number(_) => write!(f, "number"),
|
||||||
PrimitiveType::String => write!(f, "string"),
|
PrimitiveType::String => write!(f, "string"),
|
||||||
PrimitiveType::Boolean => write!(f, "bool"),
|
PrimitiveType::Boolean => write!(f, "bool"),
|
||||||
|
PrimitiveType::Tag => write!(f, "tag"),
|
||||||
PrimitiveType::Sketch => write!(f, "Sketch"),
|
PrimitiveType::Sketch => write!(f, "Sketch"),
|
||||||
PrimitiveType::Solid => write!(f, "Solid"),
|
PrimitiveType::Solid => write!(f, "Solid"),
|
||||||
PrimitiveType::Plane => write!(f, "Plane"),
|
PrimitiveType::Plane => write!(f, "Plane"),
|
||||||
|
@ -1397,6 +1397,22 @@ const answer = returnX()"#;
|
|||||||
assert!(errs.is_empty());
|
assert!(errs.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn type_aliases() {
|
||||||
|
let text = r#"type MyTy = [number; 2]
|
||||||
|
fn foo(x: MyTy) {
|
||||||
|
return x[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
foo([0, 1])
|
||||||
|
|
||||||
|
type Other = MyTy | string
|
||||||
|
"#;
|
||||||
|
let result = parse_execute(text).await.unwrap();
|
||||||
|
let errs = result.exec_state.errors();
|
||||||
|
assert!(errs.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn test_cannot_shebang_in_fn() {
|
async fn test_cannot_shebang_in_fn() {
|
||||||
let ast = r#"
|
let ast = r#"
|
||||||
|
@ -312,6 +312,9 @@ impl TypeDeclaration {
|
|||||||
hasher.update(a.compute_digest());
|
hasher.update(a.compute_digest());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(alias) = &mut slf.alias {
|
||||||
|
hasher.update(alias.compute_digest());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1895,6 +1895,7 @@ pub struct TypeDeclaration {
|
|||||||
pub args: Option<NodeList<Identifier>>,
|
pub args: Option<NodeList<Identifier>>,
|
||||||
#[serde(default, skip_serializing_if = "ItemVisibility::is_default")]
|
#[serde(default, skip_serializing_if = "ItemVisibility::is_default")]
|
||||||
pub visibility: ItemVisibility,
|
pub visibility: ItemVisibility,
|
||||||
|
pub alias: Option<Node<Type>>,
|
||||||
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
#[ts(optional)]
|
#[ts(optional)]
|
||||||
|
@ -2216,7 +2216,7 @@ fn ty_decl(i: &mut TokenSlice) -> PResult<BoxNode<TypeDeclaration>> {
|
|||||||
let name = identifier(i)?;
|
let name = identifier(i)?;
|
||||||
let mut end = name.end;
|
let mut end = name.end;
|
||||||
|
|
||||||
let args = if peek(open_paren).parse_next(i).is_ok() {
|
let args = if peek((opt(whitespace), open_paren)).parse_next(i).is_ok() {
|
||||||
ignore_whitespace(i);
|
ignore_whitespace(i);
|
||||||
open_paren(i)?;
|
open_paren(i)?;
|
||||||
ignore_whitespace(i);
|
ignore_whitespace(i);
|
||||||
@ -2229,11 +2229,28 @@ fn ty_decl(i: &mut TokenSlice) -> PResult<BoxNode<TypeDeclaration>> {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let alias = if peek((opt(whitespace), equals)).parse_next(i).is_ok() {
|
||||||
|
ignore_whitespace(i);
|
||||||
|
equals(i)?;
|
||||||
|
ignore_whitespace(i);
|
||||||
|
let ty = argument_type(i)?;
|
||||||
|
|
||||||
|
ParseContext::warn(CompilationError::err(
|
||||||
|
ty.as_source_range(),
|
||||||
|
"Type aliases are experimental, likely to change in the future, and likely to not work properly.",
|
||||||
|
));
|
||||||
|
|
||||||
|
Some(ty)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let module_id = name.module_id;
|
let module_id = name.module_id;
|
||||||
let result = Node::boxed(
|
let result = Node::boxed(
|
||||||
TypeDeclaration {
|
TypeDeclaration {
|
||||||
name,
|
name,
|
||||||
args,
|
args,
|
||||||
|
alias,
|
||||||
visibility,
|
visibility,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
@ -2686,13 +2703,21 @@ fn argument_type(i: &mut TokenSlice) -> PResult<Node<Type>> {
|
|||||||
let type_ = alt((
|
let type_ = alt((
|
||||||
// Object types
|
// Object types
|
||||||
// TODO it is buggy to treat object fields like parameters since the parameters parser assumes a terminating `)`.
|
// TODO it is buggy to treat object fields like parameters since the parameters parser assumes a terminating `)`.
|
||||||
(open_brace, parameters, close_brace).map(|(open, params, close)| {
|
(open_brace, parameters, close_brace).try_map(|(open, params, close)| {
|
||||||
Node::new(
|
for p in ¶ms {
|
||||||
|
if p.type_.is_none() {
|
||||||
|
return Err(CompilationError::fatal(
|
||||||
|
p.identifier.as_source_range(),
|
||||||
|
"Missing type for field in record type",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Node::new(
|
||||||
Type::Object { properties: params },
|
Type::Object { properties: params },
|
||||||
open.start,
|
open.start,
|
||||||
close.end,
|
close.end,
|
||||||
open.module_id,
|
open.module_id,
|
||||||
)
|
))
|
||||||
}),
|
}),
|
||||||
// Array types
|
// Array types
|
||||||
array_type,
|
array_type,
|
||||||
|
@ -12,10 +12,7 @@ use validator::Validate;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{
|
execution::{kcl_value::RuntimeType, ExecState, KclValue, Solid},
|
||||||
kcl_value::{ArrayLen, RuntimeType},
|
|
||||||
ExecState, KclValue, PrimitiveType, Solid,
|
|
||||||
},
|
|
||||||
std::Args,
|
std::Args,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,11 +39,7 @@ struct AppearanceData {
|
|||||||
|
|
||||||
/// Set the appearance of a solid. This only works on solids, not sketches or individual paths.
|
/// 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> {
|
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_typed("solids", &RuntimeType::solids(), exec_state)?;
|
||||||
"solids",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let color: String = args.get_kw_arg("color")?;
|
let color: String = args.get_kw_arg("color")?;
|
||||||
let metalness: Option<f64> = args.get_kw_arg_opt("metalness")?;
|
let metalness: Option<f64> = args.get_kw_arg_opt("metalness")?;
|
||||||
|
@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{
|
execution::{
|
||||||
kcl_value::{ArrayLen, FunctionSource, NumericType, RuntimeType},
|
kcl_value::{FunctionSource, NumericType, RuntimeType},
|
||||||
ExecState, ExecutorContext, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, PrimitiveType, Sketch,
|
ExecState, ExecutorContext, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, PrimitiveType, Sketch,
|
||||||
SketchSurface, Solid, TagIdentifier,
|
SketchSurface, Solid, TagIdentifier,
|
||||||
},
|
},
|
||||||
@ -309,8 +309,10 @@ impl Args {
|
|||||||
ty.human_friendly_type(),
|
ty.human_friendly_type(),
|
||||||
);
|
);
|
||||||
let suggestion = match (ty, actual_type_name) {
|
let suggestion = match (ty, actual_type_name) {
|
||||||
(RuntimeType::Primitive(PrimitiveType::Solid), "Sketch")
|
(RuntimeType::Primitive(PrimitiveType::Solid), "Sketch") => Some(
|
||||||
| (RuntimeType::Array(PrimitiveType::Solid, _), "Sketch") => Some(
|
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`",
|
||||||
|
),
|
||||||
|
(RuntimeType::Array(ty, _), "Sketch") if **ty == RuntimeType::Primitive(PrimitiveType::Solid) => Some(
|
||||||
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`",
|
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`",
|
||||||
),
|
),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -597,7 +599,7 @@ impl Args {
|
|||||||
};
|
};
|
||||||
let sarg = arg0
|
let sarg = arg0
|
||||||
.value
|
.value
|
||||||
.coerce(&RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::None), exec_state)
|
.coerce(&RuntimeType::sketches(), exec_state)
|
||||||
.ok_or(KclError::Type(KclErrorDetails {
|
.ok_or(KclError::Type(KclErrorDetails {
|
||||||
message: format!(
|
message: format!(
|
||||||
"Expected an array of sketches, found {}",
|
"Expected an array of sketches, found {}",
|
||||||
@ -685,7 +687,7 @@ impl Args {
|
|||||||
};
|
};
|
||||||
let sarg = arg1
|
let sarg = arg1
|
||||||
.value
|
.value
|
||||||
.coerce(&RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::None), exec_state)
|
.coerce(&RuntimeType::sketches(), exec_state)
|
||||||
.ok_or(KclError::Type(KclErrorDetails {
|
.ok_or(KclError::Type(KclErrorDetails {
|
||||||
message: format!(
|
message: format!(
|
||||||
"Expected one or more sketches for second argument, found {}",
|
"Expected one or more sketches for second argument, found {}",
|
||||||
|
@ -19,8 +19,8 @@ use uuid::Uuid;
|
|||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{
|
execution::{
|
||||||
kcl_value::{ArrayLen, RuntimeType},
|
kcl_value::RuntimeType, ArtifactId, ExecState, ExtrudeSurface, GeoMeta, KclValue, Path, Sketch, SketchSurface,
|
||||||
ArtifactId, ExecState, ExtrudeSurface, GeoMeta, KclValue, Path, PrimitiveType, Sketch, SketchSurface, Solid,
|
Solid,
|
||||||
},
|
},
|
||||||
parsing::ast::types::TagNode,
|
parsing::ast::types::TagNode,
|
||||||
std::Args,
|
std::Args,
|
||||||
@ -28,11 +28,7 @@ use crate::{
|
|||||||
|
|
||||||
/// Extrudes by a given amount.
|
/// Extrudes by a given amount.
|
||||||
pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let sketches = args.get_unlabeled_kw_arg_typed(
|
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
|
||||||
"sketches",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
let length = args.get_kw_arg("length")?;
|
let length = args.get_kw_arg("length")?;
|
||||||
let tag_start = args.get_kw_arg_opt("tagStart")?;
|
let tag_start = args.get_kw_arg_opt("tagStart")?;
|
||||||
let tag_end = args.get_kw_arg_opt("tagEnd")?;
|
let tag_end = args.get_kw_arg_opt("tagEnd")?;
|
||||||
|
@ -9,11 +9,7 @@ use kittycad_modeling_cmds as kcmc;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{
|
execution::{kcl_value::RuntimeType, ExecState, KclValue, Sketch, Solid},
|
||||||
kcl_value::{ArrayLen, RuntimeType},
|
|
||||||
ExecState, KclValue, PrimitiveType, Sketch, Solid,
|
|
||||||
},
|
|
||||||
parsing::ast::types::TagNode,
|
|
||||||
std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
|
std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,11 +17,7 @@ const DEFAULT_V_DEGREE: u32 = 2;
|
|||||||
|
|
||||||
/// Create a 3D surface or solid by interpolating between two or more sketches.
|
/// 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> {
|
pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let sketches = args.get_unlabeled_kw_arg_typed(
|
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
|
||||||
"sketches",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
let v_degree: NonZeroU32 = args
|
let v_degree: NonZeroU32 = args
|
||||||
.get_kw_arg_opt("vDegree")?
|
.get_kw_arg_opt("vDegree")?
|
||||||
.unwrap_or(NonZeroU32::new(DEFAULT_V_DEGREE).unwrap());
|
.unwrap_or(NonZeroU32::new(DEFAULT_V_DEGREE).unwrap());
|
||||||
|
@ -20,8 +20,8 @@ use super::args::Arg;
|
|||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{
|
execution::{
|
||||||
kcl_value::{ArrayLen, FunctionSource, NumericType, RuntimeType},
|
kcl_value::{FunctionSource, NumericType, RuntimeType},
|
||||||
ExecState, Geometries, Geometry, KclObjectFields, KclValue, Point2d, Point3d, PrimitiveType, Sketch, Solid,
|
ExecState, Geometries, Geometry, KclObjectFields, KclValue, Point2d, Point3d, Sketch, Solid,
|
||||||
},
|
},
|
||||||
std::Args,
|
std::Args,
|
||||||
ExecutorContext, SourceRange,
|
ExecutorContext, SourceRange,
|
||||||
@ -47,11 +47,7 @@ pub struct LinearPattern3dData {
|
|||||||
|
|
||||||
/// Repeat some 3D solid, changing each repetition slightly.
|
/// Repeat some 3D solid, changing each repetition slightly.
|
||||||
pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let solids = args.get_unlabeled_kw_arg_typed(
|
let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
|
||||||
"solids",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
let instances: u32 = args.get_kw_arg("instances")?;
|
let instances: u32 = args.get_kw_arg("instances")?;
|
||||||
let transform: &FunctionSource = args.get_kw_arg("transform")?;
|
let transform: &FunctionSource = args.get_kw_arg("transform")?;
|
||||||
let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
|
let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
|
||||||
@ -62,11 +58,7 @@ pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result
|
|||||||
|
|
||||||
/// Repeat some 2D sketch, changing each repetition slightly.
|
/// Repeat some 2D sketch, changing each repetition slightly.
|
||||||
pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let sketches = args.get_unlabeled_kw_arg_typed(
|
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
|
||||||
"sketches",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
let instances: u32 = args.get_kw_arg("instances")?;
|
let instances: u32 = args.get_kw_arg("instances")?;
|
||||||
let transform: &FunctionSource = args.get_kw_arg("transform")?;
|
let transform: &FunctionSource = args.get_kw_arg("transform")?;
|
||||||
let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
|
let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
|
||||||
@ -696,11 +688,7 @@ mod tests {
|
|||||||
|
|
||||||
/// A linear pattern on a 2D sketch.
|
/// A linear pattern on a 2D sketch.
|
||||||
pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let sketches = args.get_unlabeled_kw_arg_typed(
|
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
|
||||||
"sketches",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
let instances: u32 = args.get_kw_arg("instances")?;
|
let instances: u32 = args.get_kw_arg("instances")?;
|
||||||
let distance: f64 = args.get_kw_arg("distance")?;
|
let distance: f64 = args.get_kw_arg("distance")?;
|
||||||
let axis: [f64; 2] = args.get_kw_arg("axis")?;
|
let axis: [f64; 2] = args.get_kw_arg("axis")?;
|
||||||
@ -779,11 +767,7 @@ async fn inner_pattern_linear_2d(
|
|||||||
|
|
||||||
/// A linear pattern on a 3D model.
|
/// A linear pattern on a 3D model.
|
||||||
pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let solids = args.get_unlabeled_kw_arg_typed(
|
let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
|
||||||
"solids",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
let instances: u32 = args.get_kw_arg("instances")?;
|
let instances: u32 = args.get_kw_arg("instances")?;
|
||||||
let distance: f64 = args.get_kw_arg("distance")?;
|
let distance: f64 = args.get_kw_arg("distance")?;
|
||||||
let axis: [f64; 3] = args.get_kw_arg("axis")?;
|
let axis: [f64; 3] = args.get_kw_arg("axis")?;
|
||||||
@ -1028,11 +1012,7 @@ impl CircularPattern {
|
|||||||
|
|
||||||
/// A circular pattern on a 2D sketch.
|
/// A circular pattern on a 2D sketch.
|
||||||
pub async fn pattern_circular_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn pattern_circular_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let sketches = args.get_unlabeled_kw_arg_typed(
|
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
|
||||||
"sketches",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
let instances: u32 = args.get_kw_arg("instances")?;
|
let instances: u32 = args.get_kw_arg("instances")?;
|
||||||
let center: [f64; 2] = args.get_kw_arg("center")?;
|
let center: [f64; 2] = args.get_kw_arg("center")?;
|
||||||
let arc_degrees: f64 = args.get_kw_arg("arcDegrees")?;
|
let arc_degrees: f64 = args.get_kw_arg("arcDegrees")?;
|
||||||
@ -1136,11 +1116,7 @@ async fn inner_pattern_circular_2d(
|
|||||||
|
|
||||||
/// A circular pattern on a 3D model.
|
/// A circular pattern on a 3D model.
|
||||||
pub async fn pattern_circular_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn pattern_circular_3d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let solids = args.get_unlabeled_kw_arg_typed(
|
let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
|
||||||
"solids",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
// The number of total instances. Must be greater than or equal to 1.
|
// The number of total instances. Must be greater than or equal to 1.
|
||||||
// This includes the original entity. For example, if instances is 2,
|
// This includes the original entity. For example, if instances is 2,
|
||||||
// there will be two copies -- the original, and one new copy.
|
// there will be two copies -- the original, and one new copy.
|
||||||
|
@ -7,20 +7,13 @@ use kittycad_modeling_cmds as kcmc;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{
|
execution::{kcl_value::RuntimeType, ExecState, KclValue, Solid},
|
||||||
kcl_value::{ArrayLen, RuntimeType},
|
|
||||||
ExecState, KclValue, PrimitiveType, Solid,
|
|
||||||
},
|
|
||||||
std::{sketch::FaceTag, Args},
|
std::{sketch::FaceTag, Args},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Create a shell.
|
/// Create a shell.
|
||||||
pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let solids = args.get_unlabeled_kw_arg_typed(
|
let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
|
||||||
"solids",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
let thickness = args.get_kw_arg("thickness")?;
|
let thickness = args.get_kw_arg("thickness")?;
|
||||||
let faces = args.get_kw_arg("faces")?;
|
let faces = args.get_kw_arg("faces")?;
|
||||||
|
|
||||||
|
@ -9,10 +9,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::KclError,
|
errors::KclError,
|
||||||
execution::{
|
execution::{kcl_value::RuntimeType, ExecState, Helix, KclValue, Sketch, Solid},
|
||||||
kcl_value::{ArrayLen, RuntimeType},
|
|
||||||
ExecState, Helix, KclValue, PrimitiveType, Sketch, Solid,
|
|
||||||
},
|
|
||||||
parsing::ast::types::TagNode,
|
parsing::ast::types::TagNode,
|
||||||
std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
|
std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
|
||||||
};
|
};
|
||||||
@ -28,11 +25,7 @@ pub enum SweepPath {
|
|||||||
|
|
||||||
/// Extrude a sketch along a path.
|
/// Extrude a sketch along a path.
|
||||||
pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||||
let sketches = args.get_unlabeled_kw_arg_typed(
|
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
|
||||||
"sketches",
|
|
||||||
&RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::NonEmpty),
|
|
||||||
exec_state,
|
|
||||||
)?;
|
|
||||||
let path: SweepPath = args.get_kw_arg("path")?;
|
let path: SweepPath = args.get_kw_arg("path")?;
|
||||||
let sectional = args.get_kw_arg_opt("sectional")?;
|
let sectional = args.get_kw_arg_opt("sectional")?;
|
||||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||||
|
@ -13,10 +13,7 @@ use kittycad_modeling_cmds as kcmc;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{
|
execution::{kcl_value::RuntimeType, ExecState, KclValue, SolidOrSketchOrImportedGeometry},
|
||||||
kcl_value::{ArrayLen, RuntimeType},
|
|
||||||
ExecState, KclValue, PrimitiveType, SolidOrSketchOrImportedGeometry,
|
|
||||||
},
|
|
||||||
std::Args,
|
std::Args,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -25,9 +22,9 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
|||||||
let objects = args.get_unlabeled_kw_arg_typed(
|
let objects = args.get_unlabeled_kw_arg_typed(
|
||||||
"objects",
|
"objects",
|
||||||
&RuntimeType::Union(vec![
|
&RuntimeType::Union(vec![
|
||||||
RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::NonEmpty),
|
RuntimeType::sketches(),
|
||||||
RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty),
|
RuntimeType::solids(),
|
||||||
RuntimeType::Primitive(PrimitiveType::ImportedGeometry),
|
RuntimeType::imported(),
|
||||||
]),
|
]),
|
||||||
exec_state,
|
exec_state,
|
||||||
)?;
|
)?;
|
||||||
@ -187,9 +184,9 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
|||||||
let objects = args.get_unlabeled_kw_arg_typed(
|
let objects = args.get_unlabeled_kw_arg_typed(
|
||||||
"objects",
|
"objects",
|
||||||
&RuntimeType::Union(vec![
|
&RuntimeType::Union(vec![
|
||||||
RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::NonEmpty),
|
RuntimeType::sketches(),
|
||||||
RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty),
|
RuntimeType::solids(),
|
||||||
RuntimeType::Primitive(PrimitiveType::ImportedGeometry),
|
RuntimeType::imported(),
|
||||||
]),
|
]),
|
||||||
exec_state,
|
exec_state,
|
||||||
)?;
|
)?;
|
||||||
@ -390,9 +387,9 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|||||||
let objects = args.get_unlabeled_kw_arg_typed(
|
let objects = args.get_unlabeled_kw_arg_typed(
|
||||||
"objects",
|
"objects",
|
||||||
&RuntimeType::Union(vec![
|
&RuntimeType::Union(vec![
|
||||||
RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::NonEmpty),
|
RuntimeType::sketches(),
|
||||||
RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty),
|
RuntimeType::solids(),
|
||||||
RuntimeType::Primitive(PrimitiveType::ImportedGeometry),
|
RuntimeType::imported(),
|
||||||
]),
|
]),
|
||||||
exec_state,
|
exec_state,
|
||||||
)?;
|
)?;
|
||||||
|
@ -456,6 +456,10 @@ impl TypeDeclaration {
|
|||||||
}
|
}
|
||||||
arg_str.push(')');
|
arg_str.push(')');
|
||||||
}
|
}
|
||||||
|
if let Some(alias) = &self.alias {
|
||||||
|
arg_str.push_str(" = ");
|
||||||
|
arg_str.push_str(&alias.to_string());
|
||||||
|
}
|
||||||
format!("{}type {}{}", vis, self.name.name, arg_str)
|
format!("{}type {}{}", vis, self.name.name, arg_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -811,7 +815,7 @@ impl FunctionExpression {
|
|||||||
let tab0 = options.get_indentation(indentation_level);
|
let tab0 = options.get_indentation(indentation_level);
|
||||||
let tab1 = options.get_indentation(indentation_level + 1);
|
let tab1 = options.get_indentation(indentation_level + 1);
|
||||||
let return_type = match &self.return_type {
|
let return_type = match &self.return_type {
|
||||||
Some(rt) => format!(": {}", rt.to_string()),
|
Some(rt) => format!(": {rt}"),
|
||||||
None => String::new(),
|
None => String::new(),
|
||||||
};
|
};
|
||||||
let body = self.body.recast(&new_options, indentation_level + 1);
|
let body = self.body.recast(&new_options, indentation_level + 1);
|
||||||
@ -2427,6 +2431,7 @@ thickness = sqrt(distance * p * FOS * 6 / (sigmaAllow * width))"#;
|
|||||||
// A comment
|
// A comment
|
||||||
@(impl = primitive)
|
@(impl = primitive)
|
||||||
export type bar(unit, baz)
|
export type bar(unit, baz)
|
||||||
|
type baz = Foo | Bar
|
||||||
"#;
|
"#;
|
||||||
let program = crate::parsing::top_level_parse(some_program_string).unwrap();
|
let program = crate::parsing::top_level_parse(some_program_string).unwrap();
|
||||||
let recasted = program.recast(&Default::default(), 0);
|
let recasted = program.recast(&Default::default(), 0);
|
||||||
|
Reference in New Issue
Block a user