Type check and coerce arguments to user functions and return values from std Rust functions (#6958)
* Shuffle around function call code Signed-off-by: Nick Cameron <nrc@ncameron.org> * Refactor function calls to share more code Signed-off-by: Nick Cameron <nrc@ncameron.org> * Hack to leave the result of revolve as a singleton rather than array Signed-off-by: Nick Cameron <nrc@ncameron.org> --------- Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -1,7 +1,6 @@
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use anyhow::Result;
|
||||
use indexmap::IndexMap;
|
||||
use kcmc::{
|
||||
websocket::{ModelingCmdReq, OkWebSocketResponseData},
|
||||
ModelingCmd,
|
||||
@ -15,8 +14,8 @@ use crate::{
|
||||
execution::{
|
||||
kcl_value::FunctionSource,
|
||||
types::{NumericType, PrimitiveType, RuntimeType, UnitAngle, UnitLen, UnitType},
|
||||
ExecState, ExecutorContext, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, PlaneInfo, Sketch,
|
||||
SketchSurface, Solid, TagIdentifier,
|
||||
ExecState, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, PlaneInfo, Sketch, SketchSurface, Solid,
|
||||
TagIdentifier,
|
||||
},
|
||||
parsing::ast::types::TagNode,
|
||||
source_range::SourceRange,
|
||||
@ -28,56 +27,11 @@ use crate::{
|
||||
ModuleId,
|
||||
};
|
||||
|
||||
pub use crate::execution::fn_call::Args;
|
||||
|
||||
const ERROR_STRING_SKETCH_TO_SOLID_HELPER: &str =
|
||||
"You can convert a sketch (2D) into a Solid (3D) by calling a function like `extrude` or `revolve`";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Arg {
|
||||
/// The evaluated argument.
|
||||
pub value: KclValue,
|
||||
/// The source range of the unevaluated argument.
|
||||
pub source_range: SourceRange,
|
||||
}
|
||||
|
||||
impl Arg {
|
||||
pub fn new(value: KclValue, source_range: SourceRange) -> Self {
|
||||
Self { value, source_range }
|
||||
}
|
||||
|
||||
pub fn synthetic(value: KclValue) -> Self {
|
||||
Self {
|
||||
value,
|
||||
source_range: SourceRange::synthetic(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source_ranges(&self) -> Vec<SourceRange> {
|
||||
vec![self.source_range]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct KwArgs {
|
||||
/// Unlabeled keyword args. Currently only the first arg can be unlabeled.
|
||||
/// If the argument was a local variable, then the first element of the tuple is its name
|
||||
/// which may be used to treat this arg as a labelled arg.
|
||||
pub unlabeled: Option<(Option<String>, Arg)>,
|
||||
/// Labeled args.
|
||||
pub labeled: IndexMap<String, Arg>,
|
||||
pub errors: Vec<Arg>,
|
||||
}
|
||||
|
||||
impl KwArgs {
|
||||
/// How many arguments are there?
|
||||
pub fn len(&self) -> usize {
|
||||
self.labeled.len() + if self.unlabeled.is_some() { 1 } else { 0 }
|
||||
}
|
||||
/// Are there no arguments?
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.labeled.len() == 0 && self.unlabeled.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -153,41 +107,7 @@ impl JsonSchema for TyF64 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Args {
|
||||
/// Positional args.
|
||||
pub args: Vec<Arg>,
|
||||
/// Keyword arguments
|
||||
pub kw_args: KwArgs,
|
||||
pub source_range: SourceRange,
|
||||
pub ctx: ExecutorContext,
|
||||
/// If this call happens inside a pipe (|>) expression, this holds the LHS of that |>.
|
||||
/// Otherwise it's None.
|
||||
pub pipe_value: Option<Arg>,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn new(args: Vec<Arg>, source_range: SourceRange, ctx: ExecutorContext, pipe_value: Option<Arg>) -> Self {
|
||||
Self {
|
||||
args,
|
||||
kw_args: Default::default(),
|
||||
source_range,
|
||||
ctx,
|
||||
pipe_value,
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect the given keyword arguments.
|
||||
pub fn new_kw(kw_args: KwArgs, source_range: SourceRange, ctx: ExecutorContext, pipe_value: Option<Arg>) -> Self {
|
||||
Self {
|
||||
args: Default::default(),
|
||||
kw_args,
|
||||
source_range,
|
||||
ctx,
|
||||
pipe_value,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a keyword argument. If not set, returns None.
|
||||
pub(crate) fn get_kw_arg_opt<'a, T>(&'a self, label: &str) -> Result<Option<T>, KclError>
|
||||
where
|
||||
@ -339,16 +259,6 @@ impl Args {
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
/// Get the unlabeled keyword argument. If not set, returns None.
|
||||
pub(crate) fn unlabeled_kw_arg_unconverted(&self) -> Option<&Arg> {
|
||||
self.kw_args
|
||||
.unlabeled
|
||||
.as_ref()
|
||||
.map(|(_, a)| a)
|
||||
.or(self.args.first())
|
||||
.or(self.pipe_value.as_ref())
|
||||
}
|
||||
|
||||
/// Get the unlabeled keyword argument. If not set, returns Err. If it
|
||||
/// can't be converted to the given type, returns Err.
|
||||
pub(crate) fn get_unlabeled_kw_arg<'a, T>(&'a self, label: &str) -> Result<T, KclError>
|
||||
|
Reference in New Issue
Block a user