Declare pattern transform functions in KCL (#7057)
* Declare pattern transform using KCL Signed-off-by: Nick Cameron <nrc@ncameron.org> * Boolean function param defaults Signed-off-by: Nick Cameron <nrc@ncameron.org> * Parse empty record types in fn types Signed-off-by: Nick Cameron <nrc@ncameron.org> --------- Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -212,8 +212,9 @@ impl Type {
|
||||
Type::Object { properties } => {
|
||||
hasher.update(b"FnArgType::Object");
|
||||
hasher.update(properties.len().to_ne_bytes());
|
||||
for prop in properties.iter_mut() {
|
||||
hasher.update(prop.compute_digest());
|
||||
for (id, ty) in properties.iter_mut() {
|
||||
hasher.update(id.compute_digest());
|
||||
hasher.update(ty.compute_digest());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3315,7 +3315,7 @@ pub enum Type {
|
||||
},
|
||||
// An object type.
|
||||
Object {
|
||||
properties: Vec<Parameter>,
|
||||
properties: Vec<(Node<Identifier>, Node<Type>)>,
|
||||
},
|
||||
}
|
||||
|
||||
@ -3348,10 +3348,8 @@ impl fmt::Display for Type {
|
||||
} else {
|
||||
write!(f, ",")?;
|
||||
}
|
||||
write!(f, " {}:", p.identifier.name)?;
|
||||
if let Some(ty) = &p.type_ {
|
||||
write!(f, " {}", ty.inner)?;
|
||||
}
|
||||
write!(f, " {}:", p.0.name)?;
|
||||
write!(f, " {}", p.1)?;
|
||||
}
|
||||
write!(f, " }}")
|
||||
}
|
||||
@ -3988,7 +3986,7 @@ cylinder = startSketchOn(-XZ)
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_parse_type_args_object_on_functions() {
|
||||
let some_program_string = r#"fn thing(arg0: [number], arg1: {thing: number, things: [string], more?: string}, tag?: string) {
|
||||
let some_program_string = r#"fn thing(arg0: [number], arg1: {thing: number, things: [string], more: string}, tag?: string) {
|
||||
return arg0
|
||||
}"#;
|
||||
let module_id = ModuleId::default();
|
||||
@ -4015,8 +4013,8 @@ cylinder = startSketchOn(-XZ)
|
||||
params[1].type_.as_ref().unwrap().inner,
|
||||
Type::Object {
|
||||
properties: vec![
|
||||
Parameter {
|
||||
identifier: Node::new(
|
||||
(
|
||||
Node::new(
|
||||
Identifier {
|
||||
name: "thing".to_owned(),
|
||||
digest: None,
|
||||
@ -4025,18 +4023,15 @@ cylinder = startSketchOn(-XZ)
|
||||
37,
|
||||
module_id,
|
||||
),
|
||||
type_: Some(Node::new(
|
||||
Node::new(
|
||||
Type::Primitive(PrimitiveType::Number(NumericSuffix::None)),
|
||||
39,
|
||||
45,
|
||||
module_id
|
||||
)),
|
||||
default_value: None,
|
||||
labeled: true,
|
||||
digest: None,
|
||||
},
|
||||
Parameter {
|
||||
identifier: Node::new(
|
||||
),
|
||||
),
|
||||
(
|
||||
Node::new(
|
||||
Identifier {
|
||||
name: "things".to_owned(),
|
||||
digest: None,
|
||||
@ -4045,7 +4040,7 @@ cylinder = startSketchOn(-XZ)
|
||||
53,
|
||||
module_id,
|
||||
),
|
||||
type_: Some(Node::new(
|
||||
Node::new(
|
||||
Type::Array {
|
||||
ty: Box::new(Type::Primitive(PrimitiveType::String)),
|
||||
len: ArrayLen::None
|
||||
@ -4053,13 +4048,10 @@ cylinder = startSketchOn(-XZ)
|
||||
56,
|
||||
62,
|
||||
module_id
|
||||
)),
|
||||
default_value: None,
|
||||
labeled: true,
|
||||
digest: None
|
||||
},
|
||||
Parameter {
|
||||
identifier: Node::new(
|
||||
)
|
||||
),
|
||||
(
|
||||
Node::new(
|
||||
Identifier {
|
||||
name: "more".to_owned(),
|
||||
digest: None
|
||||
@ -4068,11 +4060,8 @@ cylinder = startSketchOn(-XZ)
|
||||
69,
|
||||
module_id,
|
||||
),
|
||||
type_: Some(Node::new(Type::Primitive(PrimitiveType::String), 72, 78, module_id)),
|
||||
labeled: true,
|
||||
default_value: Some(DefaultParamVal::none()),
|
||||
digest: None
|
||||
}
|
||||
Node::new(Type::Primitive(PrimitiveType::String), 71, 77, module_id),
|
||||
)
|
||||
]
|
||||
}
|
||||
);
|
||||
|
@ -436,7 +436,7 @@ fn pipe_expression(i: &mut TokenSlice) -> PResult<Node<PipeExpression>> {
|
||||
))
|
||||
}
|
||||
|
||||
fn bool_value(i: &mut TokenSlice) -> PResult<BoxNode<Literal>> {
|
||||
fn bool_value(i: &mut TokenSlice) -> PResult<Node<Literal>> {
|
||||
let (value, token) = any
|
||||
.try_map(|token: Token| match token.token_type {
|
||||
TokenType::Keyword if token.value == "true" => Ok((true, token)),
|
||||
@ -448,7 +448,7 @@ fn bool_value(i: &mut TokenSlice) -> PResult<BoxNode<Literal>> {
|
||||
})
|
||||
.context(expected("a boolean literal (either true or false)"))
|
||||
.parse_next(i)?;
|
||||
Ok(Box::new(Node::new(
|
||||
Ok(Node::new(
|
||||
Literal {
|
||||
value: LiteralValue::Bool(value),
|
||||
raw: value.to_string(),
|
||||
@ -457,11 +457,11 @@ fn bool_value(i: &mut TokenSlice) -> PResult<BoxNode<Literal>> {
|
||||
token.start,
|
||||
token.end,
|
||||
token.module_id,
|
||||
)))
|
||||
))
|
||||
}
|
||||
|
||||
fn literal(i: &mut TokenSlice) -> PResult<BoxNode<Literal>> {
|
||||
alt((string_literal, unsigned_number_literal))
|
||||
alt((string_literal, unsigned_number_literal, bool_value))
|
||||
.map(Box::new)
|
||||
.context(expected("a KCL literal, like 'myPart' or 3"))
|
||||
.parse_next(i)
|
||||
@ -2051,7 +2051,7 @@ fn unnecessarily_bracketed(i: &mut TokenSlice) -> PResult<Expr> {
|
||||
fn expr_allowed_in_pipe_expr(i: &mut TokenSlice) -> PResult<Expr> {
|
||||
alt((
|
||||
member_expression.map(Box::new).map(Expr::MemberExpression),
|
||||
bool_value.map(Expr::Literal),
|
||||
bool_value.map(Box::new).map(Expr::Literal),
|
||||
tag.map(Box::new).map(Expr::TagDeclarator),
|
||||
literal.map(Expr::Literal),
|
||||
fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),
|
||||
@ -2070,7 +2070,7 @@ fn expr_allowed_in_pipe_expr(i: &mut TokenSlice) -> PResult<Expr> {
|
||||
fn possible_operands(i: &mut TokenSlice) -> PResult<Expr> {
|
||||
let mut expr = alt((
|
||||
unary_expression.map(Box::new).map(Expr::UnaryExpression),
|
||||
bool_value.map(Expr::Literal),
|
||||
bool_value.map(Box::new).map(Expr::Literal),
|
||||
member_expression.map(Box::new).map(Expr::MemberExpression),
|
||||
literal.map(Expr::Literal),
|
||||
fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),
|
||||
@ -2780,27 +2780,31 @@ fn labeled_argument(i: &mut TokenSlice) -> PResult<LabeledArg> {
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
fn record_ty_field(i: &mut TokenSlice) -> PResult<(Node<Identifier>, Node<Type>)> {
|
||||
(identifier, colon, opt(whitespace), type_)
|
||||
.map(|(id, _, _, ty)| (id, ty))
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
/// Parse a type in various positions.
|
||||
fn type_(i: &mut TokenSlice) -> PResult<Node<Type>> {
|
||||
let type_ = alt((
|
||||
// Object types
|
||||
// TODO it is buggy to treat object fields like parameters since the parameters parser assumes a terminating `)`.
|
||||
(open_brace, parameters, close_brace).try_map(|(open, params, close)| {
|
||||
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 },
|
||||
open.start,
|
||||
close.end,
|
||||
open.module_id,
|
||||
))
|
||||
}),
|
||||
(
|
||||
open_brace,
|
||||
opt(whitespace),
|
||||
separated(0.., record_ty_field, comma_sep),
|
||||
opt(whitespace),
|
||||
close_brace,
|
||||
)
|
||||
.try_map(|(open, _, params, _, close)| {
|
||||
Ok(Node::new(
|
||||
Type::Object { properties: params },
|
||||
open.start,
|
||||
close.end,
|
||||
open.module_id,
|
||||
))
|
||||
}),
|
||||
// Array types
|
||||
array_type,
|
||||
// Primitive or union types
|
||||
@ -4866,6 +4870,15 @@ let myBox = box(p=[0,0], h=-3, l=-16, w=-10)
|
||||
|> line(%, tag = $var01)"#;
|
||||
assert_no_err(some_program_string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_param_bool_default() {
|
||||
let some_program_string = r#"fn patternTransform(
|
||||
use_original?: boolean = false,
|
||||
) {}"#;
|
||||
assert_no_err(some_program_string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_function_types() {
|
||||
let code = r#"foo = x: fn
|
||||
@ -4875,6 +4888,8 @@ fn foo(x: fn(a, b: number(mm), c: d): number(Angle)): fn { return 0 }
|
||||
type fn
|
||||
type foo = fn
|
||||
type foo = fn(a: string, b: { f: fn(): any })
|
||||
type foo = fn(a: string, b: {})
|
||||
type foo = fn(a: string, b: { })
|
||||
type foo = fn([fn])
|
||||
type foo = fn(fn, f: fn(number(_))): [fn([any]): string]
|
||||
"#;
|
||||
|
Reference in New Issue
Block a user