KCL: Keyword function calls for stdlib (#4647)
Part of https://github.com/KittyCAD/modeling-app/issues/4600 Adds support for keyword arguments to the stdlib, and calling stdlib functions with keyword arguments. So far, I've changed one function: `rem`. Previously you would have used `rem(7, 2)` but now it's `rem(7, divisor: 2)`. This is a proof-of-concept. If it's approved, we will: 1. Support closures with keyword arguments, and calling them 2. Move the rest of the stdlib to use kw arguments
This commit is contained in:
@ -23,17 +23,30 @@ use unbox::unbox;
|
||||
struct StdlibMetadata {
|
||||
/// The name of the function in the API.
|
||||
name: String,
|
||||
|
||||
/// Tags for the function.
|
||||
#[serde(default)]
|
||||
tags: Vec<String>,
|
||||
|
||||
/// Whether the function is unpublished.
|
||||
/// Then docs will not be generated.
|
||||
#[serde(default)]
|
||||
unpublished: bool,
|
||||
|
||||
/// Whether the function is deprecated.
|
||||
/// Then specific docs detailing that this is deprecated will be generated.
|
||||
#[serde(default)]
|
||||
deprecated: bool,
|
||||
|
||||
/// If true, expects keyword arguments.
|
||||
/// If false, expects positional arguments.
|
||||
#[serde(default)]
|
||||
keywords: bool,
|
||||
|
||||
/// If true, the first argument is unlabeled.
|
||||
/// If false, all arguments require labels.
|
||||
#[serde(default)]
|
||||
unlabeled_first: bool,
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
@ -225,6 +238,12 @@ fn do_stdlib_inner(
|
||||
quote! { false }
|
||||
};
|
||||
|
||||
let uses_keyword_arguments = if metadata.keywords {
|
||||
quote! { true }
|
||||
} else {
|
||||
quote! { false }
|
||||
};
|
||||
|
||||
let docs_crate = get_crate(None);
|
||||
|
||||
// When the user attaches this proc macro to a function with the wrong type
|
||||
@ -233,7 +252,7 @@ fn do_stdlib_inner(
|
||||
// of the various parameters. We do this by calling dummy functions that
|
||||
// require a type that satisfies SharedExtractor or ExclusiveExtractor.
|
||||
let mut arg_types = Vec::new();
|
||||
for arg in ast.sig.inputs.iter() {
|
||||
for (i, arg) in ast.sig.inputs.iter().enumerate() {
|
||||
// Get the name of the argument.
|
||||
let arg_name = match arg {
|
||||
syn::FnArg::Receiver(pat) => {
|
||||
@ -263,7 +282,7 @@ fn do_stdlib_inner(
|
||||
|
||||
let ty_string = rust_type_to_openapi_type(&ty_string);
|
||||
let required = !ty_ident.to_string().starts_with("Option <");
|
||||
|
||||
let label_required = !(i == 0 && metadata.unlabeled_first);
|
||||
if ty_string != "ExecState" && ty_string != "Args" {
|
||||
let schema = quote! {
|
||||
generator.root_schema_for::<#ty_ident>()
|
||||
@ -274,6 +293,7 @@ fn do_stdlib_inner(
|
||||
type_: #ty_string.to_string(),
|
||||
schema: #schema,
|
||||
required: #required,
|
||||
label_required: #label_required,
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -334,6 +354,7 @@ fn do_stdlib_inner(
|
||||
type_: #ret_ty_string.to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
@ -400,6 +421,10 @@ fn do_stdlib_inner(
|
||||
vec![#(#tags),*]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
#uses_keyword_arguments
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<#docs_crate::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
// We set this to false so we can recurse them later.
|
||||
|
||||
@ -74,6 +74,10 @@ impl crate::docs::StdLibFn for SomeFn {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -83,6 +87,7 @@ impl crate::docs::StdLibFn for SomeFn {
|
||||
type_: "Foo".to_string(),
|
||||
schema: generator.root_schema_for::<Foo>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -96,6 +101,7 @@ impl crate::docs::StdLibFn for SomeFn {
|
||||
type_: "i32".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -74,6 +74,10 @@ impl crate::docs::StdLibFn for SomeFn {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -83,6 +87,7 @@ impl crate::docs::StdLibFn for SomeFn {
|
||||
type_: "string".to_string(),
|
||||
schema: generator.root_schema_for::<str>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -96,6 +101,7 @@ impl crate::docs::StdLibFn for SomeFn {
|
||||
type_: "i32".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -108,6 +108,10 @@ impl crate::docs::StdLibFn for Show {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -117,6 +121,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
type_: "[number]".to_string(),
|
||||
schema: generator.root_schema_for::<[f64; 2usize]>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -130,6 +135,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
type_: "number".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -74,6 +74,10 @@ impl crate::docs::StdLibFn for Show {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -83,6 +87,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
type_: "number".to_string(),
|
||||
schema: generator.root_schema_for::<f64>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -96,6 +101,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
type_: "number".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -108,6 +108,10 @@ impl crate::docs::StdLibFn for MyFunc {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -117,6 +121,7 @@ impl crate::docs::StdLibFn for MyFunc {
|
||||
type_: "kittycad::types::InputFormat".to_string(),
|
||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
||||
required: false,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -130,6 +135,7 @@ impl crate::docs::StdLibFn for MyFunc {
|
||||
type_: "[Sketch]".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -108,6 +108,10 @@ impl crate::docs::StdLibFn for LineTo {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -118,12 +122,14 @@ impl crate::docs::StdLibFn for LineTo {
|
||||
type_: "LineToData".to_string(),
|
||||
schema: generator.root_schema_for::<LineToData>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
},
|
||||
crate::docs::StdLibFnArg {
|
||||
name: "sketch".to_string(),
|
||||
type_: "Sketch".to_string(),
|
||||
schema: generator.root_schema_for::<Sketch>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -138,6 +144,7 @@ impl crate::docs::StdLibFn for LineTo {
|
||||
type_: "Sketch".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -108,6 +108,10 @@ impl crate::docs::StdLibFn for Min {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -117,6 +121,7 @@ impl crate::docs::StdLibFn for Min {
|
||||
type_: "[number]".to_string(),
|
||||
schema: generator.root_schema_for::<Vec<f64>>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -130,6 +135,7 @@ impl crate::docs::StdLibFn for Min {
|
||||
type_: "number".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -74,6 +74,10 @@ impl crate::docs::StdLibFn for Show {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -83,6 +87,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
type_: "number".to_string(),
|
||||
schema: generator.root_schema_for::<Option<f64>>(),
|
||||
required: false,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -96,6 +101,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
type_: "number".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -74,6 +74,10 @@ impl crate::docs::StdLibFn for Import {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -83,6 +87,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
type_: "kittycad::types::InputFormat".to_string(),
|
||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
||||
required: false,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -96,6 +101,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
type_: "number".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -74,6 +74,10 @@ impl crate::docs::StdLibFn for Import {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -83,6 +87,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
type_: "kittycad::types::InputFormat".to_string(),
|
||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
||||
required: false,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -96,6 +101,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
type_: "[Sketch]".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -74,6 +74,10 @@ impl crate::docs::StdLibFn for Import {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -83,6 +87,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
type_: "kittycad::types::InputFormat".to_string(),
|
||||
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
|
||||
required: false,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -96,6 +101,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
type_: "[Sketch]".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -74,6 +74,10 @@ impl crate::docs::StdLibFn for Show {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -83,6 +87,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
type_: "[number]".to_string(),
|
||||
schema: generator.root_schema_for::<Vec<f64>>(),
|
||||
required: true,
|
||||
label_required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
@ -96,6 +101,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
type_: "()".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -74,6 +74,10 @@ impl crate::docs::StdLibFn for SomeFunction {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn keyword_arguments(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = inline_subschemas;
|
||||
@ -91,6 +95,7 @@ impl crate::docs::StdLibFn for SomeFunction {
|
||||
type_: "i32".to_string(),
|
||||
schema,
|
||||
required: true,
|
||||
label_required: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user