Turn on units of measure (BREAKING CHANGE) (#6343)

* Turn on uom checks

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Convert all lengths to mm for engine calls

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
Nick Cameron
2025-04-23 10:58:35 +12:00
committed by GitHub
parent 3d22f6cd66
commit b7385d5f25
339 changed files with 35471 additions and 17237 deletions

View File

@ -1,7 +1,7 @@
use sha2::{Digest as DigestTrait, Sha256};
use crate::parsing::ast::types::{
Annotation, ArrayExpression, ArrayRangeExpression, Ascription, BinaryExpression, BinaryPart, BodyItem,
Annotation, ArrayExpression, ArrayRangeExpression, AscribedExpression, BinaryExpression, BinaryPart, BodyItem,
CallExpression, CallExpressionKw, DefaultParamVal, ElseIf, Expr, ExpressionStatement, FunctionExpression,
Identifier, IfExpression, ImportItem, ImportSelector, ImportStatement, ItemVisibility, KclNone, LabelledExpression,
Literal, LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Name, ObjectExpression, ObjectProperty,
@ -464,7 +464,7 @@ impl LabelledExpression {
});
}
impl Ascription {
impl AscribedExpression {
compute_digest!(|slf, hasher| {
hasher.update(slf.expr.compute_digest());
hasher.update(slf.ty.compute_digest());

View File

@ -819,7 +819,7 @@ pub enum Expr {
UnaryExpression(BoxNode<UnaryExpression>),
IfExpression(BoxNode<IfExpression>),
LabelledExpression(BoxNode<LabelledExpression>),
AscribedExpression(BoxNode<Ascription>),
AscribedExpression(BoxNode<AscribedExpression>),
None(Node<KclNone>),
}
@ -1092,7 +1092,7 @@ impl LabelledExpression {
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
pub struct Ascription {
pub struct AscribedExpression {
pub expr: Expr,
pub ty: Node<Type>,
@ -1101,12 +1101,12 @@ pub struct Ascription {
pub digest: Option<Digest>,
}
impl Ascription {
pub(crate) fn new(expr: Expr, ty: Node<Type>) -> Node<Ascription> {
impl AscribedExpression {
pub(crate) fn new(expr: Expr, ty: Node<Type>) -> Node<AscribedExpression> {
let start = expr.start();
let end = ty.end;
let module_id = expr.module_id();
Node::new(Ascription { expr, ty, digest: None }, start, end, module_id)
Node::new(AscribedExpression { expr, ty, digest: None }, start, end, module_id)
}
}
@ -3080,7 +3080,7 @@ impl PipeExpression {
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
#[serde(tag = "p_type")]
pub enum PrimitiveType {
/// A string type.
String,

View File

@ -14,7 +14,7 @@ use winnow::{
};
use super::{
ast::types::{Ascription, ImportPath, LabelledExpression},
ast::types::{AscribedExpression, ImportPath, LabelledExpression},
token::{NumericSuffix, RESERVED_WORDS},
DeprecationKind,
};
@ -530,13 +530,6 @@ pub(crate) fn unsigned_number_literal(i: &mut TokenSlice) -> PResult<Node<Litera
CompilationError::fatal(token.as_source_range(), format!("Invalid float: {}", token.value))
})?;
if token.numeric_suffix().is_some() {
ParseContext::warn(CompilationError::err(
(&token).into(),
"Unit of Measure suffixes are experimental and currently do nothing.",
));
}
Ok((
LiteralValue::Number {
value,
@ -2021,9 +2014,7 @@ fn expression_but_not_pipe(i: &mut TokenSlice) -> PResult<Expr> {
let ty = opt((colon, opt(whitespace), argument_type)).parse_next(i)?;
if let Some((_, _, ty)) = ty {
ParseContext::warn(CompilationError::err((&ty).into(), "Type ascription is experimental."));
expr = Expr::AscribedExpression(Box::new(Ascription::new(expr, ty)))
expr = Expr::AscribedExpression(Box::new(AscribedExpression::new(expr, ty)))
}
let label = opt(label).parse_next(i)?;
match label {
@ -2817,13 +2808,6 @@ fn primitive_type(i: &mut TokenSlice) -> PResult<Node<PrimitiveType>> {
let mut result = Node::new(PrimitiveType::Boolean, ident.start, ident.end, ident.module_id);
result.inner = PrimitiveType::primitive_from_str(&ident.name, suffix).unwrap_or(PrimitiveType::Named(ident));
if suffix.is_some() {
ParseContext::warn(CompilationError::err(
result.as_source_range(),
"Unit of Measure types are experimental and currently do nothing.",
));
}
Ok(result)
}
@ -4547,19 +4531,19 @@ export fn cos(num: number(rad)): number(_) {}"#;
fn fn_decl_uom_ty() {
let some_program_string = r#"fn foo(x: number(mm)): number(_) { return 1 }"#;
let (_, errs) = assert_no_fatal(some_program_string);
assert_eq!(errs.len(), 2);
assert!(errs.is_empty(), "Expected no errors, found: {errs:?}");
}
#[test]
fn error_underscore() {
let (_, errs) = assert_no_fatal("_foo(_blah, _)");
assert_eq!(errs.len(), 3, "found: {:#?}", errs);
assert_eq!(errs.len(), 3, "found: {errs:#?}");
}
#[test]
fn error_type_ascription() {
let (_, errs) = assert_no_fatal("a + b: number");
assert_eq!(errs.len(), 1, "found: {:#?}", errs);
assert!(errs.is_empty());
}
#[test]