Display numeric units in the variables pane (#6683)
This commit is contained in:
@ -126685,7 +126685,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -126693,6 +126694,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -128804,6 +128808,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -129165,7 +129172,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -129173,6 +129181,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -131284,6 +131295,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -131649,7 +131663,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -131657,6 +131672,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -133768,6 +133786,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -203436,7 +203457,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -203444,6 +203466,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -205555,6 +205580,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -205914,7 +205942,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -205922,6 +205951,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -206708,7 +206740,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -206716,6 +206749,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -208419,6 +208455,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -213896,7 +213935,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -213904,6 +213944,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -216015,6 +216058,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -216373,7 +216419,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -216381,6 +216428,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -216759,7 +216809,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -216767,6 +216818,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -218878,6 +218932,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -219237,7 +219294,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -219245,6 +219303,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -220031,7 +220092,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -220039,6 +220101,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -221742,6 +221807,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -222123,7 +222191,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -222131,6 +222200,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -224242,6 +224314,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -224600,7 +224675,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -224608,6 +224684,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -224986,7 +225065,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -224994,6 +225074,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -227105,6 +227188,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -227466,7 +227552,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -227474,6 +227561,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -229585,6 +229675,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
@ -229944,7 +230037,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -229952,6 +230046,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -230738,7 +230835,8 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
"type",
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
@ -230746,6 +230844,9 @@
|
||||
"enum": [
|
||||
"Function"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/components/schemas/FunctionSource"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -232449,6 +232550,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"FunctionSource": {
|
||||
"type": "null"
|
||||
},
|
||||
"ModuleId": {
|
||||
"description": "Identifier of a source file. Uses a u32 to keep the size small.",
|
||||
"type": "integer",
|
||||
|
@ -170,7 +170,9 @@ extrude001 = extrude(sketch001, length = 50)
|
||||
await variablesTabButton.click()
|
||||
// expect to see "myVar:5"
|
||||
await expect(
|
||||
page.locator('.pretty-json-container >> text=myVar:5')
|
||||
// There's a double quote before the number value since the units are
|
||||
// formatted into a string.
|
||||
page.locator('.pretty-json-container >> text=myVar:"5')
|
||||
).toBeVisible()
|
||||
|
||||
// change 5 to 67
|
||||
@ -180,7 +182,7 @@ extrude001 = extrude(sketch001, length = 50)
|
||||
await page.keyboard.type('67')
|
||||
|
||||
await expect(
|
||||
page.locator('.pretty-json-container >> text=myVar:67')
|
||||
page.locator('.pretty-json-container >> text=myVar:"67')
|
||||
).toBeVisible()
|
||||
})
|
||||
test('ProgramMemory can be serialised', async ({ page, homePage }) => {
|
||||
|
@ -83,9 +83,9 @@ pub enum KclValue {
|
||||
value: Box<Helix>,
|
||||
},
|
||||
ImportedGeometry(ImportedGeometry),
|
||||
#[ts(skip)]
|
||||
Function {
|
||||
#[serde(skip)]
|
||||
#[serde(serialize_with = "function_value_stub")]
|
||||
#[ts(type = "null")]
|
||||
value: FunctionSource,
|
||||
#[serde(skip)]
|
||||
meta: Vec<Metadata>,
|
||||
@ -109,6 +109,13 @@ pub enum KclValue {
|
||||
},
|
||||
}
|
||||
|
||||
fn function_value_stub<S>(_value: &FunctionSource, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_unit()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub enum FunctionSource {
|
||||
#[default]
|
||||
|
@ -399,7 +399,7 @@ impl fmt::Display for PrimitiveType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum NumericType {
|
||||
|
137
rust/kcl-lib/src/fmt.rs
Normal file
137
rust/kcl-lib/src/fmt.rs
Normal file
@ -0,0 +1,137 @@
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{execution::types::NumericType, pretty::NumericSuffix};
|
||||
|
||||
/// For the UI, display a number and its type for debugging purposes. This is
|
||||
/// used by TS.
|
||||
pub fn human_display_number(value: f64, ty: NumericType) -> String {
|
||||
match ty {
|
||||
NumericType::Known(unit_type) => format!("{value}: number({unit_type})"),
|
||||
NumericType::Default { len, angle } => format!("{value} (no units, defaulting to {len} or {angle})"),
|
||||
NumericType::Unknown => format!("{value} (number with unknown units)"),
|
||||
NumericType::Any => format!("{value} (number with any units)"),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, thiserror::Error)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum FormatNumericSuffixError {
|
||||
#[error("Invalid numeric suffix: {0}")]
|
||||
Invalid(NumericSuffix),
|
||||
}
|
||||
|
||||
/// For UI code generation, format a number with a suffix. The result must parse
|
||||
/// as a literal. If it can't be done, returns an error.
|
||||
///
|
||||
/// This is used by TS.
|
||||
pub fn format_number_literal(value: f64, suffix: NumericSuffix) -> Result<String, FormatNumericSuffixError> {
|
||||
match suffix {
|
||||
// There isn't a syntactic suffix for these. For unknown, we don't want
|
||||
// to ever generate the unknown suffix. We currently warn on it, and we
|
||||
// may remove it in the future.
|
||||
NumericSuffix::Length | NumericSuffix::Angle | NumericSuffix::Unknown => {
|
||||
Err(FormatNumericSuffixError::Invalid(suffix))
|
||||
}
|
||||
NumericSuffix::None
|
||||
| NumericSuffix::Count
|
||||
| NumericSuffix::Mm
|
||||
| NumericSuffix::Cm
|
||||
| NumericSuffix::M
|
||||
| NumericSuffix::Inch
|
||||
| NumericSuffix::Ft
|
||||
| NumericSuffix::Yd
|
||||
| NumericSuffix::Deg
|
||||
| NumericSuffix::Rad => Ok(format!("{value}{suffix}")),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::execution::types::{UnitAngle, UnitLen, UnitType};
|
||||
|
||||
#[test]
|
||||
fn test_human_display_number() {
|
||||
assert_eq!(
|
||||
human_display_number(1.0, NumericType::Known(UnitType::Count)),
|
||||
"1: number(Count)"
|
||||
);
|
||||
assert_eq!(
|
||||
human_display_number(1.0, NumericType::Known(UnitType::Length(UnitLen::M))),
|
||||
"1: number(m)"
|
||||
);
|
||||
assert_eq!(
|
||||
human_display_number(1.0, NumericType::Known(UnitType::Length(UnitLen::Mm))),
|
||||
"1: number(mm)"
|
||||
);
|
||||
assert_eq!(
|
||||
human_display_number(1.0, NumericType::Known(UnitType::Length(UnitLen::Inches))),
|
||||
"1: number(in)"
|
||||
);
|
||||
assert_eq!(
|
||||
human_display_number(1.0, NumericType::Known(UnitType::Length(UnitLen::Feet))),
|
||||
"1: number(ft)"
|
||||
);
|
||||
assert_eq!(
|
||||
human_display_number(1.0, NumericType::Known(UnitType::Angle(UnitAngle::Degrees))),
|
||||
"1: number(deg)"
|
||||
);
|
||||
assert_eq!(
|
||||
human_display_number(1.0, NumericType::Known(UnitType::Angle(UnitAngle::Radians))),
|
||||
"1: number(rad)"
|
||||
);
|
||||
assert_eq!(
|
||||
human_display_number(
|
||||
1.0,
|
||||
NumericType::Default {
|
||||
len: UnitLen::Mm,
|
||||
angle: UnitAngle::Degrees,
|
||||
}
|
||||
),
|
||||
"1 (no units, defaulting to mm or deg)"
|
||||
);
|
||||
assert_eq!(
|
||||
human_display_number(
|
||||
1.0,
|
||||
NumericType::Default {
|
||||
len: UnitLen::Feet,
|
||||
angle: UnitAngle::Radians,
|
||||
}
|
||||
),
|
||||
"1 (no units, defaulting to ft or rad)"
|
||||
);
|
||||
assert_eq!(
|
||||
human_display_number(1.0, NumericType::Unknown),
|
||||
"1 (number with unknown units)"
|
||||
);
|
||||
assert_eq!(human_display_number(1.0, NumericType::Any), "1 (number with any units)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_number_literal() {
|
||||
assert_eq!(
|
||||
format_number_literal(1.0, NumericSuffix::Length),
|
||||
Err(FormatNumericSuffixError::Invalid(NumericSuffix::Length))
|
||||
);
|
||||
assert_eq!(
|
||||
format_number_literal(1.0, NumericSuffix::Angle),
|
||||
Err(FormatNumericSuffixError::Invalid(NumericSuffix::Angle))
|
||||
);
|
||||
assert_eq!(format_number_literal(1.0, NumericSuffix::None), Ok("1".to_owned()));
|
||||
assert_eq!(format_number_literal(1.0, NumericSuffix::Count), Ok("1_".to_owned()));
|
||||
assert_eq!(format_number_literal(1.0, NumericSuffix::Mm), Ok("1mm".to_owned()));
|
||||
assert_eq!(format_number_literal(1.0, NumericSuffix::Cm), Ok("1cm".to_owned()));
|
||||
assert_eq!(format_number_literal(1.0, NumericSuffix::M), Ok("1m".to_owned()));
|
||||
assert_eq!(format_number_literal(1.0, NumericSuffix::Inch), Ok("1in".to_owned()));
|
||||
assert_eq!(format_number_literal(1.0, NumericSuffix::Ft), Ok("1ft".to_owned()));
|
||||
assert_eq!(format_number_literal(1.0, NumericSuffix::Yd), Ok("1yd".to_owned()));
|
||||
assert_eq!(format_number_literal(1.0, NumericSuffix::Deg), Ok("1deg".to_owned()));
|
||||
assert_eq!(format_number_literal(1.0, NumericSuffix::Rad), Ok("1rad".to_owned()));
|
||||
assert_eq!(
|
||||
format_number_literal(1.0, NumericSuffix::Unknown),
|
||||
Err(FormatNumericSuffixError::Invalid(NumericSuffix::Unknown))
|
||||
);
|
||||
}
|
||||
}
|
@ -61,6 +61,7 @@ mod docs;
|
||||
mod engine;
|
||||
mod errors;
|
||||
mod execution;
|
||||
mod fmt;
|
||||
mod fs;
|
||||
pub mod lint;
|
||||
mod log;
|
||||
@ -108,7 +109,10 @@ pub use unparser::{recast_dir, walk_dir};
|
||||
pub mod exec {
|
||||
#[cfg(feature = "artifact-graph")]
|
||||
pub use crate::execution::ArtifactCommand;
|
||||
pub use crate::execution::{DefaultPlanes, IdGenerator, KclValue, PlaneType, Sketch};
|
||||
pub use crate::execution::{
|
||||
types::{NumericType, UnitAngle, UnitLen, UnitType},
|
||||
DefaultPlanes, IdGenerator, KclValue, PlaneType, Sketch,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
@ -134,7 +138,10 @@ pub mod std_utils {
|
||||
}
|
||||
|
||||
pub mod pretty {
|
||||
pub use crate::{parsing::token::NumericSuffix, unparser::format_number};
|
||||
pub use crate::{
|
||||
fmt::{format_number_literal, human_display_number},
|
||||
parsing::token::NumericSuffix,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
|
@ -8,9 +8,7 @@ use crate::parsing::{
|
||||
MemberExpression, MemberObject, Node, NonCodeNode, NonCodeValue, ObjectExpression, Parameter, PipeExpression,
|
||||
Program, TagDeclarator, TypeDeclaration, UnaryExpression, VariableDeclaration, VariableKind,
|
||||
},
|
||||
deprecation,
|
||||
token::NumericSuffix,
|
||||
DeprecationKind, PIPE_OPERATOR,
|
||||
deprecation, DeprecationKind, PIPE_OPERATOR,
|
||||
};
|
||||
|
||||
impl Program {
|
||||
@ -465,11 +463,6 @@ impl TypeDeclaration {
|
||||
}
|
||||
}
|
||||
|
||||
// Used by TS.
|
||||
pub fn format_number(value: f64, suffix: NumericSuffix) -> String {
|
||||
format!("{value}{suffix}")
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
fn recast(&self) -> String {
|
||||
match self.value {
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing add_lots.kcl
|
||||
---
|
||||
{
|
||||
"f": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"x": {
|
||||
"type": "Number",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing cube.kcl
|
||||
---
|
||||
{
|
||||
"cube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"myCube": {
|
||||
"type": "Solid",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing double_map_fn.kcl
|
||||
---
|
||||
{
|
||||
"increment": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"xs": {
|
||||
"type": "MixedArray",
|
||||
|
@ -435,7 +435,8 @@ description: Variables in memory after executing fillet-and-shell.kcl
|
||||
}
|
||||
},
|
||||
"m25Screw": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"microUsb1Distance": {
|
||||
"type": "Number",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing function_sketch.kcl
|
||||
---
|
||||
{
|
||||
"box": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"fnBox": {
|
||||
"type": "Solid",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing function_sketch_with_position.k
|
||||
---
|
||||
{
|
||||
"box": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"thing": {
|
||||
"type": "Solid",
|
||||
|
@ -2201,7 +2201,8 @@ description: Variables in memory after executing import_async.kcl
|
||||
}
|
||||
},
|
||||
"leftInvolute": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"module": {
|
||||
"type": "Number",
|
||||
@ -2263,7 +2264,8 @@ description: Variables in memory after executing import_async.kcl
|
||||
}
|
||||
},
|
||||
"rightInvolute": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"rs": {
|
||||
"type": "MixedArray",
|
||||
|
@ -4,9 +4,11 @@ description: Variables in memory after executing import_function_not_sketch.kcl
|
||||
---
|
||||
{
|
||||
"one": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"two": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing import_glob.kcl
|
||||
---
|
||||
{
|
||||
"foo": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"three": {
|
||||
"type": "Number",
|
||||
|
@ -4,6 +4,7 @@ description: Variables in memory after executing import_side_effect.kcl
|
||||
---
|
||||
{
|
||||
"foo": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing intersect_cubes.kcl
|
||||
---
|
||||
{
|
||||
"cube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"fullPart": {
|
||||
"type": "Solid",
|
||||
|
@ -4,6 +4,7 @@ description: Variables in memory after executing 80-20-rail.kcl
|
||||
---
|
||||
{
|
||||
"rail8020": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,12 @@ description: Variables in memory after executing bench.kcl
|
||||
---
|
||||
{
|
||||
"armRest": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"backSlats": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"benchLength": {
|
||||
"type": "Number",
|
||||
@ -23,10 +25,12 @@ description: Variables in memory after executing bench.kcl
|
||||
}
|
||||
},
|
||||
"connector": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"divider": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"dividerThickness": {
|
||||
"type": "Number",
|
||||
@ -42,6 +46,7 @@ description: Variables in memory after executing bench.kcl
|
||||
}
|
||||
},
|
||||
"seatSlats": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +197,8 @@ description: Variables in memory after executing color-cube.kcl
|
||||
}
|
||||
},
|
||||
"sketchRectangle": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"tealPlane": {
|
||||
"type": "Plane",
|
||||
|
@ -4,6 +4,7 @@ description: Variables in memory after executing cycloidal-gear.kcl
|
||||
---
|
||||
{
|
||||
"cycloidalGear": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,16 @@ description: Variables in memory after executing dodecahedron.kcl
|
||||
---
|
||||
{
|
||||
"calculateArrayLength": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"createFaceTemplate": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"createIntersection": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"dihedral": {
|
||||
"type": "Number",
|
||||
|
@ -1352,7 +1352,8 @@ description: Variables in memory after executing enclosure.kcl
|
||||
}
|
||||
},
|
||||
"function001": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"height": {
|
||||
"type": "Number",
|
||||
|
@ -774,7 +774,8 @@ description: Variables in memory after executing exhaust-manifold.kcl
|
||||
}
|
||||
},
|
||||
"primaryTube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"primaryTubeDiameter": {
|
||||
"type": "Number",
|
||||
|
@ -673,7 +673,8 @@ description: Variables in memory after executing focusrite-scarlett-mounting-bra
|
||||
}
|
||||
},
|
||||
"bracketSketch": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"bs": {
|
||||
"type": "Sketch",
|
||||
|
@ -2832,7 +2832,8 @@ description: Variables in memory after executing food-service-spatula.kcl
|
||||
}
|
||||
},
|
||||
"slot": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"slotProfile000": {
|
||||
"type": "Sketch",
|
||||
|
@ -19763,7 +19763,8 @@ description: Variables in memory after executing gear-rack.kcl
|
||||
]
|
||||
},
|
||||
"tooth": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"width": {
|
||||
"type": "Number",
|
||||
|
@ -2201,7 +2201,8 @@ description: Variables in memory after executing gear.kcl
|
||||
}
|
||||
},
|
||||
"leftInvolute": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"module": {
|
||||
"type": "Number",
|
||||
@ -2256,7 +2257,8 @@ description: Variables in memory after executing gear.kcl
|
||||
}
|
||||
},
|
||||
"rightInvolute": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"rs": {
|
||||
"type": "MixedArray",
|
||||
|
@ -10850,7 +10850,8 @@ description: Variables in memory after executing gridfinity-baseplate-magnets.kc
|
||||
}
|
||||
},
|
||||
"face": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"firstStep": {
|
||||
"type": "Number",
|
||||
@ -10938,10 +10939,12 @@ description: Variables in memory after executing gridfinity-baseplate-magnets.kc
|
||||
}
|
||||
},
|
||||
"magnetBase": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"magnetCenterCutout": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"magnetCutoutExtrude": {
|
||||
"type": "Solid",
|
||||
|
@ -10850,7 +10850,8 @@ description: Variables in memory after executing gridfinity-baseplate.kcl
|
||||
}
|
||||
},
|
||||
"face": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"firstStep": {
|
||||
"type": "Number",
|
||||
|
@ -14220,7 +14220,8 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
|
||||
}
|
||||
},
|
||||
"face": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"firstStep": {
|
||||
"type": "Number",
|
||||
@ -15659,7 +15660,8 @@ description: Variables in memory after executing gridfinity-bins-stacking-lip.kc
|
||||
]
|
||||
},
|
||||
"lipFace": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"lipHeight": {
|
||||
"type": "Number",
|
||||
|
@ -14148,7 +14148,8 @@ description: Variables in memory after executing gridfinity-bins.kcl
|
||||
}
|
||||
},
|
||||
"face": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"firstStep": {
|
||||
"type": "Number",
|
||||
|
@ -17,7 +17,8 @@ description: Variables in memory after executing hex-nut.kcl
|
||||
}
|
||||
},
|
||||
"hexNut": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"thickness": {
|
||||
"type": "Number",
|
||||
|
@ -29,7 +29,8 @@ description: Variables in memory after executing keyboard.kcl
|
||||
}
|
||||
},
|
||||
"keyFn": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"keyHeight": {
|
||||
"type": "Number",
|
||||
@ -45,7 +46,8 @@ description: Variables in memory after executing keyboard.kcl
|
||||
}
|
||||
},
|
||||
"o": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"plane001": {
|
||||
"type": "Object",
|
||||
@ -2885,6 +2887,7 @@ description: Variables in memory after executing keyboard.kcl
|
||||
}
|
||||
},
|
||||
"z": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
|
@ -6262,7 +6262,8 @@ description: Variables in memory after executing kitt.kcl
|
||||
}
|
||||
},
|
||||
"kitEar": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"kitEarDepth": {
|
||||
"type": "Number",
|
||||
@ -13308,7 +13309,8 @@ description: Variables in memory after executing kitt.kcl
|
||||
}
|
||||
},
|
||||
"kitLeg": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"kitLegOffset": {
|
||||
"type": "Number",
|
||||
@ -22321,7 +22323,8 @@ description: Variables in memory after executing kitt.kcl
|
||||
}
|
||||
},
|
||||
"pixelBox": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"seg01": {
|
||||
"type": "TagIdentifier",
|
||||
|
@ -43,7 +43,8 @@ description: Variables in memory after executing makeup-mirror.kcl
|
||||
}
|
||||
},
|
||||
"armFn": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"armLength": {
|
||||
"type": "Number",
|
||||
@ -288,7 +289,8 @@ description: Variables in memory after executing makeup-mirror.kcl
|
||||
}
|
||||
},
|
||||
"hingeFn": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"hingeGap": {
|
||||
"type": "Number",
|
||||
@ -1194,7 +1196,8 @@ description: Variables in memory after executing makeup-mirror.kcl
|
||||
}
|
||||
},
|
||||
"mirrorFn": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"mirrorRadius": {
|
||||
"type": "Number",
|
||||
|
@ -435,7 +435,8 @@ description: Variables in memory after executing mounting-plate.kcl
|
||||
}
|
||||
},
|
||||
"rectShape": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"rs": {
|
||||
"type": "Sketch",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing pipe-flange-assembly.kcl
|
||||
---
|
||||
{
|
||||
"bolt": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"boltDiameter": {
|
||||
"type": "Number",
|
||||
@ -103,7 +104,8 @@ description: Variables in memory after executing pipe-flange-assembly.kcl
|
||||
"value": "filletEdge"
|
||||
},
|
||||
"flange": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"flangeBackDiameter": {
|
||||
"type": "Number",
|
||||
@ -240,7 +242,8 @@ description: Variables in memory after executing pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"hexNut": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"hexNutDiameter": {
|
||||
"type": "Number",
|
||||
@ -321,7 +324,8 @@ description: Variables in memory after executing pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"pipe": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"pipeDiameter": {
|
||||
"type": "Number",
|
||||
@ -376,7 +380,8 @@ description: Variables in memory after executing pipe-flange-assembly.kcl
|
||||
}
|
||||
},
|
||||
"washer": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"washerInnerDia": {
|
||||
"type": "Number",
|
||||
|
@ -77,7 +77,8 @@ description: Variables in memory after executing walkie-talkie.kcl
|
||||
"value": 2
|
||||
},
|
||||
"button": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"buttonHeight": {
|
||||
"type": "Number",
|
||||
|
@ -4,10 +4,12 @@ description: Variables in memory after executing kw_fn.kcl
|
||||
---
|
||||
{
|
||||
"add": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"increment": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"three": {
|
||||
"type": "Number",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing kw_fn_with_defaults.kcl
|
||||
---
|
||||
{
|
||||
"increment": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"twentyOne": {
|
||||
"type": "Number",
|
||||
|
@ -17,7 +17,8 @@ description: Variables in memory after executing loop_tag.kcl
|
||||
}
|
||||
},
|
||||
"calculatePoint": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"closedSketch": {
|
||||
"type": "Sketch",
|
||||
|
@ -4,6 +4,7 @@ description: Variables in memory after executing multi_transform.kcl
|
||||
---
|
||||
{
|
||||
"transform": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ description: Variables in memory after executing pattern_circular_in_module.kcl
|
||||
---
|
||||
{
|
||||
"thing": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ description: Variables in memory after executing pattern_linear_in_module.kcl
|
||||
---
|
||||
{
|
||||
"thing": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
|
@ -652,7 +652,8 @@ description: Variables in memory after executing pentagon_fillet_sugar.kcl
|
||||
}
|
||||
},
|
||||
"circl": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"p": {
|
||||
"type": "Solid",
|
||||
|
@ -4,10 +4,12 @@ description: Variables in memory after executing pipe_as_arg.kcl
|
||||
---
|
||||
{
|
||||
"cube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"double": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"myCube": {
|
||||
"type": "Number",
|
||||
@ -23,6 +25,7 @@ description: Variables in memory after executing pipe_as_arg.kcl
|
||||
}
|
||||
},
|
||||
"width": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +223,8 @@ description: Variables in memory after executing riddle_small.kcl
|
||||
}
|
||||
},
|
||||
"t": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"xs": {
|
||||
"type": "Number",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing rotate_after_fillet.kcl
|
||||
---
|
||||
{
|
||||
"bolt": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"boltDiameter": {
|
||||
"type": "Number",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing scale_after_fillet.kcl
|
||||
---
|
||||
{
|
||||
"bolt": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"boltDiameter": {
|
||||
"type": "Number",
|
||||
|
@ -4,10 +4,12 @@ description: Variables in memory after executing sketch_in_object.kcl
|
||||
---
|
||||
{
|
||||
"test": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"test2": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"x": {
|
||||
"type": "Sketch",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing sketch_on_face_circle_tagged.kc
|
||||
---
|
||||
{
|
||||
"cube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"myCircle": {
|
||||
"type": "TagIdentifier",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing sketch_on_face_end.kcl
|
||||
---
|
||||
{
|
||||
"cube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"part001": {
|
||||
"type": "Solid",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing sketch_on_face_end_negative_ext
|
||||
---
|
||||
{
|
||||
"cube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"part001": {
|
||||
"type": "Solid",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing sketch_on_face_start.kcl
|
||||
---
|
||||
{
|
||||
"cube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"foo": {
|
||||
"type": "Solid",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing subtract_cylinder_from_cube.kcl
|
||||
---
|
||||
{
|
||||
"cube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"fullPart": {
|
||||
"type": "Solid",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing subtract_doesnt_need_brackets.k
|
||||
---
|
||||
{
|
||||
"cube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"part001": {
|
||||
"type": "Solid",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing translate_after_fillet.kcl
|
||||
---
|
||||
{
|
||||
"bolt": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"boltDiameter": {
|
||||
"type": "Number",
|
||||
|
@ -4,7 +4,8 @@ description: Variables in memory after executing union_cubes.kcl
|
||||
---
|
||||
{
|
||||
"cube": {
|
||||
"type": "Function"
|
||||
"type": "Function",
|
||||
"value": null
|
||||
},
|
||||
"fullPart": {
|
||||
"type": "Solid",
|
||||
|
@ -1,7 +1,11 @@
|
||||
//! Wasm bindings for `kcl`.
|
||||
|
||||
use gloo_utils::format::JsValueSerdeExt;
|
||||
use kcl_lib::{pretty::NumericSuffix, CoreDump, Program, SourceRange};
|
||||
use kcl_lib::{
|
||||
exec::{NumericType, UnitAngle, UnitLen, UnitType},
|
||||
pretty::NumericSuffix,
|
||||
CoreDump, Program, SourceRange,
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// wasm_bindgen wrapper for lint
|
||||
@ -50,11 +54,34 @@ pub fn recast_wasm(json_str: &str) -> Result<JsValue, JsError> {
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn format_number(value: f64, suffix_json: &str) -> Result<String, JsError> {
|
||||
pub fn format_number_literal(value: f64, suffix_json: &str) -> Result<String, JsError> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let suffix: NumericSuffix = serde_json::from_str(suffix_json).map_err(JsError::from)?;
|
||||
Ok(kcl_lib::pretty::format_number(value, suffix))
|
||||
kcl_lib::pretty::format_number_literal(value, suffix).map_err(JsError::from)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn human_display_number(value: f64, ty_json: &str) -> Result<String, String> {
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
// ts-rs can't handle tuple types, so it mashes all of these types together.
|
||||
if let Ok(ty) = serde_json::from_str::<NumericType>(ty_json) {
|
||||
return Ok(kcl_lib::pretty::human_display_number(value, ty));
|
||||
}
|
||||
if let Ok(unit_type) = serde_json::from_str::<UnitType>(ty_json) {
|
||||
let ty = NumericType::Known(unit_type);
|
||||
return Ok(kcl_lib::pretty::human_display_number(value, ty));
|
||||
}
|
||||
if let Ok(unit_len) = serde_json::from_str::<UnitLen>(ty_json) {
|
||||
let ty = NumericType::Known(UnitType::Length(unit_len));
|
||||
return Ok(kcl_lib::pretty::human_display_number(value, ty));
|
||||
}
|
||||
if let Ok(unit_angle) = serde_json::from_str::<UnitAngle>(ty_json) {
|
||||
let ty = NumericType::Known(UnitType::Angle(unit_angle));
|
||||
return Ok(kcl_lib::pretty::human_display_number(value, ty));
|
||||
}
|
||||
Err(format!("Invalid type: {ty_json}"))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
@ -16,6 +16,13 @@ describe('processMemory', () => {
|
||||
return a - 2
|
||||
}
|
||||
otherVar = myFn(5)
|
||||
nFeet = 2ft
|
||||
nInches = 2in
|
||||
nMm = 2mm
|
||||
nDegrees = 2deg
|
||||
nRadians = 2rad
|
||||
nCount = 2_
|
||||
nUnknown = 1rad * PI
|
||||
|
||||
theExtrude = startSketchOn(XY)
|
||||
|> startProfile(at = [0, 0])
|
||||
@ -32,8 +39,17 @@ describe('processMemory', () => {
|
||||
const ast = assertParse(code)
|
||||
const execState = await enginelessExecutor(ast)
|
||||
const output = processMemory(execState.variables)
|
||||
expect(output.myVar).toEqual(5)
|
||||
expect(output.otherVar).toEqual(3)
|
||||
expect(output.nFeet).toEqual('2: number(ft)')
|
||||
expect(output.nInches).toEqual('2: number(in)')
|
||||
expect(output.nMm).toEqual('2: number(mm)')
|
||||
expect(output.nDegrees).toEqual('2: number(deg)')
|
||||
expect(output.nRadians).toEqual('2: number(rad)')
|
||||
expect(output.nCount).toEqual('2: number(Count)')
|
||||
expect(output.nUnknown).toEqual(
|
||||
'3.141592653589793 (number with unknown units)'
|
||||
)
|
||||
expect(output.myVar).toEqual('5 (no units, defaulting to mm or deg)')
|
||||
expect(output.otherVar).toEqual('3 (no units, defaulting to mm or deg)')
|
||||
expect(output.myFn).toEqual('__function__')
|
||||
expect(output.theExtrude).toEqual([
|
||||
{
|
||||
|
@ -11,7 +11,7 @@ import { useModelingContext } from '@src/hooks/useModelingContext'
|
||||
import { useResolvedTheme } from '@src/hooks/useResolvedTheme'
|
||||
import { useKclContext } from '@src/lang/KclProvider'
|
||||
import type { VariableMap } from '@src/lang/wasm'
|
||||
import { sketchFromKclValueOptional } from '@src/lang/wasm'
|
||||
import { humanDisplayNumber, sketchFromKclValueOptional } from '@src/lang/wasm'
|
||||
import { Reason, trap } from '@src/lib/trap'
|
||||
|
||||
export const MemoryPaneMenu = () => {
|
||||
@ -81,31 +81,29 @@ export const MemoryPane = () => {
|
||||
}
|
||||
|
||||
export const processMemory = (variables: VariableMap) => {
|
||||
const processedMemory: any = {}
|
||||
const processedMemory: Record<
|
||||
string,
|
||||
string | number | boolean | object | undefined
|
||||
> = {}
|
||||
for (const [key, val] of Object.entries(variables)) {
|
||||
if (val === undefined) continue
|
||||
if (
|
||||
val.type === 'Sketch' ||
|
||||
// @ts-ignore
|
||||
val.type !== 'Function'
|
||||
) {
|
||||
const sk = sketchFromKclValueOptional(val, key)
|
||||
if (val.type === 'Solid') {
|
||||
processedMemory[key] = val.value.value.map(
|
||||
({ ...rest }: ExtrudeSurface) => {
|
||||
return rest
|
||||
}
|
||||
)
|
||||
} else if (!(sk instanceof Reason)) {
|
||||
processedMemory[key] = sk.paths.map(({ __geoMeta, ...rest }: Path) => {
|
||||
const sk = sketchFromKclValueOptional(val, key)
|
||||
if (val.type === 'Solid') {
|
||||
processedMemory[key] = val.value.value.map(
|
||||
({ ...rest }: ExtrudeSurface) => {
|
||||
return rest
|
||||
})
|
||||
} else {
|
||||
processedMemory[key] = val.value
|
||||
}
|
||||
//@ts-ignore
|
||||
}
|
||||
)
|
||||
} else if (!(sk instanceof Reason)) {
|
||||
processedMemory[key] = sk.paths.map(({ __geoMeta, ...rest }: Path) => {
|
||||
return rest
|
||||
})
|
||||
} else if (val.type === 'Function') {
|
||||
processedMemory[key] = `__function__`
|
||||
processedMemory[key] = '__function__'
|
||||
} else if (val.type === 'Number') {
|
||||
processedMemory[key] = humanDisplayNumber(val.value, val.ty)
|
||||
} else {
|
||||
processedMemory[key] = val.value
|
||||
}
|
||||
}
|
||||
return processedMemory
|
||||
|
@ -31,28 +31,48 @@ import type {
|
||||
VariableDeclaration,
|
||||
VariableDeclarator,
|
||||
} from '@src/lang/wasm'
|
||||
import { formatNumber } from '@src/lang/wasm'
|
||||
import { formatNumberLiteral } from '@src/lang/wasm'
|
||||
import { err } from '@src/lib/trap'
|
||||
|
||||
export function createLiteral(value: number | string | boolean): Node<Literal> {
|
||||
// TODO: Should we handle string escape sequences?
|
||||
return {
|
||||
type: 'Literal',
|
||||
start: 0,
|
||||
end: 0,
|
||||
moduleId: 0,
|
||||
value: typeof value === 'number' ? { value, suffix: 'None' } : value,
|
||||
raw: `${value}`,
|
||||
outerAttrs: [],
|
||||
preComments: [],
|
||||
commentStart: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This depends on WASM, but it's not async. Callers are responsible for
|
||||
* awaiting init of the WASM module.
|
||||
*/
|
||||
export function createLiteral(value: LiteralValue | number): Node<Literal> {
|
||||
if (typeof value === 'number') {
|
||||
value = { value, suffix: 'None' }
|
||||
export function createLiteralMaybeSuffix(
|
||||
value: LiteralValue
|
||||
): Node<Literal> | Error {
|
||||
if (typeof value === 'string' || typeof value === 'boolean') {
|
||||
return createLiteral(value)
|
||||
}
|
||||
|
||||
let raw: string
|
||||
if (typeof value === 'string') {
|
||||
// TODO: Should we handle escape sequences?
|
||||
raw = `${value}`
|
||||
} else if (typeof value === 'boolean') {
|
||||
raw = `${value}`
|
||||
} else if (typeof value.value === 'number' && value.suffix === 'None') {
|
||||
if (typeof value.value === 'number' && value.suffix === 'None') {
|
||||
// Fast path for numbers when there are no units.
|
||||
raw = `${value.value}`
|
||||
} else {
|
||||
raw = formatNumber(value.value, value.suffix)
|
||||
const formatted = formatNumberLiteral(value.value, value.suffix)
|
||||
if (err(formatted)) {
|
||||
return new Error(
|
||||
`Invalid number literal: value=${value.value}, suffix=${value.suffix}`,
|
||||
{ cause: formatted }
|
||||
)
|
||||
}
|
||||
raw = formatted
|
||||
}
|
||||
return {
|
||||
type: 'Literal',
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
createArrayExpression,
|
||||
createIdentifier,
|
||||
createLiteral,
|
||||
createLiteralMaybeSuffix,
|
||||
createObjectExpression,
|
||||
createPipeExpression,
|
||||
createPipeSubstitution,
|
||||
@ -35,6 +36,7 @@ import { initPromise } from '@src/lang/wasmUtils'
|
||||
import { enginelessExecutor } from '@src/lib/testHelpers'
|
||||
import { err } from '@src/lib/trap'
|
||||
import { deleteFromSelection } from '@src/lang/modifyAst/deleteFromSelection'
|
||||
import { assertNotErr } from '@src/unitTestUtils'
|
||||
|
||||
beforeAll(async () => {
|
||||
await initPromise
|
||||
@ -50,7 +52,8 @@ describe('Testing createLiteral', () => {
|
||||
})
|
||||
it('should create a literal number with units', () => {
|
||||
const lit: LiteralValue = { value: 5, suffix: 'Mm' }
|
||||
const result = createLiteral(lit)
|
||||
const result = createLiteralMaybeSuffix(lit)
|
||||
assertNotErr(result)
|
||||
expect(result.type).toBe('Literal')
|
||||
expect((result as any).value.value).toBe(5)
|
||||
expect((result as any).value.suffix).toBe('Mm')
|
||||
|
@ -3,7 +3,7 @@ import type { Program } from '@rust/kcl-lib/bindings/Program'
|
||||
|
||||
import type { ParseResult } from '@src/lang/wasm'
|
||||
import {
|
||||
formatNumber,
|
||||
formatNumberLiteral,
|
||||
parse,
|
||||
errFromErrWithOutputs,
|
||||
rustImplPathToNode,
|
||||
@ -33,12 +33,15 @@ it('can execute parsed AST', async () => {
|
||||
})
|
||||
|
||||
it('formats numbers with units', () => {
|
||||
expect(formatNumber(1, 'None')).toEqual('1')
|
||||
expect(formatNumber(1, 'Count')).toEqual('1_')
|
||||
expect(formatNumber(1, 'Mm')).toEqual('1mm')
|
||||
expect(formatNumber(1, 'Inch')).toEqual('1in')
|
||||
expect(formatNumber(0.5, 'Mm')).toEqual('0.5mm')
|
||||
expect(formatNumber(-0.5, 'Mm')).toEqual('-0.5mm')
|
||||
expect(formatNumberLiteral(1, 'None')).toEqual('1')
|
||||
expect(formatNumberLiteral(1, 'Count')).toEqual('1_')
|
||||
expect(formatNumberLiteral(1, 'Mm')).toEqual('1mm')
|
||||
expect(formatNumberLiteral(1, 'Inch')).toEqual('1in')
|
||||
expect(formatNumberLiteral(0.5, 'Mm')).toEqual('0.5mm')
|
||||
expect(formatNumberLiteral(-0.5, 'Mm')).toEqual('-0.5mm')
|
||||
expect(formatNumberLiteral(1, 'Unknown')).toEqual(
|
||||
new Error('Error formatting number literal: value=1, suffix=Unknown')
|
||||
)
|
||||
})
|
||||
|
||||
describe('test errFromErrWithOutputs', () => {
|
||||
|
@ -47,9 +47,10 @@ import {
|
||||
coredump,
|
||||
default_app_settings,
|
||||
default_project_settings,
|
||||
format_number,
|
||||
format_number_literal,
|
||||
get_kcl_version,
|
||||
get_tangential_arc_to_info,
|
||||
human_display_number,
|
||||
is_kcl_empty_or_only_settings,
|
||||
is_points_ccw,
|
||||
kcl_lint,
|
||||
@ -67,6 +68,7 @@ import {
|
||||
LABELED_ARG_FIELD,
|
||||
UNLABELED_ARG,
|
||||
} from '@src/lang/queryAstConstants'
|
||||
import type { NumericType } from '@rust/kcl-lib/bindings/NumericType'
|
||||
|
||||
export type { ArrayExpression } from '@rust/kcl-lib/bindings/ArrayExpression'
|
||||
export type {
|
||||
@ -440,8 +442,35 @@ export const recast = (ast: Program): string | Error => {
|
||||
/**
|
||||
* Format a number with suffix as KCL.
|
||||
*/
|
||||
export function formatNumber(value: number, suffix: NumericSuffix): string {
|
||||
return format_number(value, JSON.stringify(suffix))
|
||||
export function formatNumberLiteral(
|
||||
value: number,
|
||||
suffix: NumericSuffix
|
||||
): string | Error {
|
||||
try {
|
||||
return format_number_literal(value, JSON.stringify(suffix))
|
||||
} catch (e) {
|
||||
return new Error(
|
||||
`Error formatting number literal: value=${value}, suffix=${suffix}`,
|
||||
{ cause: e }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug display a number with suffix, for human consumption only.
|
||||
*/
|
||||
export function humanDisplayNumber(
|
||||
value: number,
|
||||
ty: NumericType
|
||||
): string | Error {
|
||||
try {
|
||||
return human_display_number(value, JSON.stringify(ty))
|
||||
} catch (e) {
|
||||
return new Error(
|
||||
`Error formatting number for human display: value=${value}, ty=${JSON.stringify(ty)}`,
|
||||
{ cause: e }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function isPointsCCW(points: Coords2d[]): number {
|
||||
|
@ -12,7 +12,8 @@ import type {
|
||||
coredump as CoreDump,
|
||||
default_app_settings as DefaultAppSettings,
|
||||
default_project_settings as DefaultProjectSettings,
|
||||
format_number as FormatNumber,
|
||||
format_number_literal as FormatNumberLiteral,
|
||||
human_display_number as HumanDisplayNumber,
|
||||
get_kcl_version as GetKclVersion,
|
||||
get_tangential_arc_to_info as GetTangentialArcToInfo,
|
||||
import_file_extensions as ImportFileExtensions,
|
||||
@ -55,8 +56,11 @@ export const parse_wasm: typeof ParseWasm = (...args) => {
|
||||
export const recast_wasm: typeof RecastWasm = (...args) => {
|
||||
return getModule().recast_wasm(...args)
|
||||
}
|
||||
export const format_number: typeof FormatNumber = (...args) => {
|
||||
return getModule().format_number(...args)
|
||||
export const format_number_literal: typeof FormatNumberLiteral = (...args) => {
|
||||
return getModule().format_number_literal(...args)
|
||||
}
|
||||
export const human_display_number: typeof HumanDisplayNumber = (...args) => {
|
||||
return getModule().human_display_number(...args)
|
||||
}
|
||||
export const kcl_lint: typeof KclLint = (...args) => {
|
||||
return getModule().kcl_lint(...args)
|
||||
|
@ -10,6 +10,16 @@ import { createArrayExpression } from '@src/lang/create'
|
||||
import { findKwArg, findKwArgAny } from '@src/lang/util'
|
||||
import type { CallExpressionKw, Expr } from '@src/lang/wasm'
|
||||
|
||||
/**
|
||||
* Throw x if it's an Error. Only use this in tests.
|
||||
*/
|
||||
export function assertNotErr<T>(x: T): asserts x is Exclude<T, Error> {
|
||||
if (x instanceof Error) {
|
||||
// eslint-disable-next-line suggest-no-throw/suggest-no-throw
|
||||
throw x
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Find the angle and some sort of length parameter from an angledLine-ish call.
|
||||
E.g. finds the (angle, length) in angledLine or the (angle, endAbsoluteX) in angledLineToX
|
||||
|
Reference in New Issue
Block a user