Refactor: move point-parsing into its own function (#1590)

This will be reused in future stdlib functions.

Also, add a field for argument number to the "invalid argument type" error message.
This commit is contained in:
Adam Chalmers
2024-02-29 17:55:34 -06:00
committed by GitHub
parent 0ebb4e2cad
commit 95c0ded8cf
3 changed files with 59 additions and 37 deletions

View File

@ -45,11 +45,12 @@ pub enum CompileError {
NoReturnStmt,
#[error("You used the %, which means \"substitute this argument for the value to the left in this |> pipeline\". But there is no such value, because you're not calling a pipeline.")]
NotInPipeline,
#[error("The function '{fn_name}' expects a parameter of type {expected} but you supplied {actual}")]
#[error("The function '{fn_name}' expects a parameter of type {expected} as argument number {arg_number} but you supplied {actual}")]
ArgWrongType {
fn_name: &'static str,
expected: &'static str,
actual: String,
arg_number: usize,
},
}

View File

@ -35,23 +35,31 @@ pub fn stack_api_call<const N: usize>(
}))
}
pub fn single_binding(b: EpBinding, fn_name: &'static str, expected: &'static str) -> Result<Address, CompileError> {
pub fn single_binding(
b: EpBinding,
fn_name: &'static str,
expected: &'static str,
arg_number: usize,
) -> Result<Address, CompileError> {
match b {
EpBinding::Single(a) => Ok(a),
EpBinding::Sequence { .. } => Err(CompileError::ArgWrongType {
fn_name,
expected,
actual: "array".to_owned(),
arg_number,
}),
EpBinding::Map { .. } => Err(CompileError::ArgWrongType {
fn_name,
expected,
actual: "object".to_owned(),
arg_number,
}),
EpBinding::Function(_) => Err(CompileError::ArgWrongType {
fn_name,
expected,
actual: "function".to_owned(),
arg_number,
}),
}
}
@ -60,6 +68,7 @@ pub fn sequence_binding(
b: EpBinding,
fn_name: &'static str,
expected: &'static str,
arg_number: usize,
) -> Result<Vec<EpBinding>, CompileError> {
match b {
EpBinding::Sequence { elements, .. } => Ok(elements),
@ -67,16 +76,60 @@ pub fn sequence_binding(
fn_name,
expected,
actual: "single".to_owned(),
arg_number,
}),
EpBinding::Map { .. } => Err(CompileError::ArgWrongType {
fn_name,
expected,
actual: "object".to_owned(),
arg_number,
}),
EpBinding::Function(_) => Err(CompileError::ArgWrongType {
fn_name,
expected,
actual: "function".to_owned(),
arg_number,
}),
}
}
/// Extract a 2D point from an argument to a Cabble.
pub fn arg_point2d(
arg: EpBinding,
fn_name: &'static str,
instructions: &mut Vec<Instruction>,
next_addr: &mut Address,
arg_number: usize,
) -> Result<Address, CompileError> {
let expected = "2D point (array with length 2)";
let elements = sequence_binding(arg, "startSketchAt", "an array of length 2", arg_number)?;
if elements.len() != 2 {
return Err(CompileError::ArgWrongType {
fn_name,
expected,
actual: format!("array of length {}", elements.len()),
arg_number: 0,
});
}
// KCL stores points as an array.
// KC API stores them as Rust objects laid flat out in memory.
let start = next_addr.offset_by(2);
let start_x = start;
let start_y = start + 1;
let start_z = start + 2;
instructions.extend([
Instruction::Copy {
source: single_binding(elements[0].clone(), "startSketchAt", "number", arg_number)?,
destination: start_x,
},
Instruction::Copy {
source: single_binding(elements[1].clone(), "startSketchAt", "number", arg_number)?,
destination: start_y,
},
Instruction::SetPrimitive {
address: start_z,
value: 0.0.into(),
},
]);
Ok(start)
}

View File

@ -7,7 +7,7 @@ use kittycad_modeling_cmds::{
use uuid::Uuid;
use super::{
helpers::{no_arg_api_call, sequence_binding, single_binding, stack_api_call},
helpers::{arg_point2d, no_arg_api_call, single_binding, stack_api_call},
types::{Axes, BasePath, Plane, SketchGroup},
};
use crate::{binding_scope::EpBinding, error::CompileError, native_functions::Callable, EvalPlan};
@ -28,42 +28,10 @@ impl Callable for StartSketchAt {
actual: 0,
});
};
let start_point = {
let expected = "2D point (array with length 2)";
let fn_name = "startSketchAt";
let elements = sequence_binding(start, "startSketchAt", "an array of length 2")?;
if elements.len() != 2 {
return Err(CompileError::ArgWrongType {
fn_name,
expected,
actual: format!("array of length {}", elements.len()),
});
}
// KCL stores points as an array.
// KC API stores them as Rust objects laid flat out in memory.
let start = next_addr.offset_by(2);
let start_x = start;
let start_y = start + 1;
let start_z = start + 2;
instructions.extend([
Instruction::Copy {
source: single_binding(elements[0].clone(), "startSketchAt (first parameter, elem 0)", "number")?,
destination: start_x,
},
Instruction::Copy {
source: single_binding(elements[1].clone(), "startSketchAt (first parameter, elem 1)", "number")?,
destination: start_y,
},
Instruction::SetPrimitive {
address: start_z,
value: 0.0.into(),
},
]);
start
};
let start_point = arg_point2d(start, "startSketchAt", &mut instructions, next_addr, 0)?;
let tag = match args_iter.next() {
None => None,
Some(b) => Some(single_binding(b, "startSketchAt", "a single string")?),
Some(b) => Some(single_binding(b, "startSketchAt", "a single string", 1)?),
};
// Define some constants: