microcad_lang/builtin/
workpiece.rs1use custom_debug::Debug;
7use microcad_core::{Geometry2D, Geometry3D};
8use strum::Display;
9
10use crate::{
11 eval::*, model::*, render::RenderResult, resolve::Symbol, src_ref::SrcRef, syntax::*, value::*,
12};
13
14pub type BuiltinFn =
16 dyn Fn(Option<&ParameterValueList>, &ArgumentValueList, &mut Context) -> EvalResult<Value>;
17
18#[derive(Clone)]
20pub struct Builtin {
21 pub id: Identifier,
23
24 pub parameters: Option<ParameterValueList>,
26
27 pub f: &'static BuiltinFn,
29}
30
31impl std::fmt::Debug for Builtin {
32 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
33 write!(f, "__builtin::{}", &self.id)
34 }
35}
36
37impl Builtin {
38 pub fn id(&self) -> Identifier {
40 self.id.clone()
41 }
42}
43
44impl CallTrait for Builtin {
45 fn call(&self, args: &ArgumentValueList, context: &mut Context) -> EvalResult<Value> {
50 (self.f)(self.parameters.as_ref(), args, context)
51 }
52}
53
54#[derive(Debug, Clone, Display)]
56pub enum BuiltinWorkbenchKind {
57 Primitive2D,
59 Primitive3D,
61 Transform,
63 Operation,
65}
66
67pub enum BuiltinWorkpieceOutput {
69 Primitive2D(Geometry2D),
71 Primitive3D(Geometry3D),
73 Transform(AffineTransform),
75 Operation(Box<dyn Operation>),
77}
78
79pub type BuiltinWorkpieceFn = dyn Fn(&Tuple) -> RenderResult<BuiltinWorkpieceOutput>;
81
82#[derive(Clone, Debug)]
84pub struct BuiltinWorkpiece {
85 pub kind: BuiltinWorkbenchKind,
87 pub output_type: OutputType,
89 pub creator: Creator,
91 #[debug(skip)]
93 pub f: &'static BuiltinWorkpieceFn,
94}
95
96impl BuiltinWorkpiece {
97 pub fn call(&self) -> RenderResult<BuiltinWorkpieceOutput> {
99 (self.f)(&self.creator.arguments)
100 }
101}
102
103impl std::fmt::Display for BuiltinWorkpiece {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 writeln!(
106 f,
107 "{kind} {creator}",
108 kind = self.kind,
109 creator = self.creator,
110 )
111 }
112}
113
114pub trait BuiltinWorkbenchDefinition {
116 fn id() -> &'static str;
118
119 fn kind() -> BuiltinWorkbenchKind;
121
122 fn output_type() -> OutputType {
124 OutputType::NotDetermined
125 }
126
127 fn workpiece_function() -> &'static BuiltinWorkpieceFn;
129
130 fn workpiece(creator: Creator) -> BuiltinWorkpiece {
132 BuiltinWorkpiece {
133 kind: Self::kind(),
134 output_type: Self::output_type(),
135 creator,
136 f: Self::workpiece_function(),
137 }
138 }
139
140 fn model(creator: Creator) -> Model {
142 ModelBuilder::new(
143 Element::BuiltinWorkpiece(Self::workpiece(creator)),
144 SrcRef(None),
145 )
146 .build()
147 }
148
149 fn function() -> &'static BuiltinFn {
151 &|params, args, context| {
152 log::trace!(
153 "Built-in workbench {call} {id:?}({args})",
154 call = crate::mark!(CALL),
155 id = Self::id()
156 );
157 Ok(Value::Model(
158 ArgumentMatch::find_multi_match(
159 args,
160 params.expect("A built-in part must have a parameter list"),
161 )?
162 .iter()
163 .map(|tuple| Self::model(Creator::new(context.current_symbol(), tuple.clone())))
164 .collect::<Models>()
165 .to_multiplicity(SrcRef(None)),
166 ))
167 }
168 }
169
170 fn parameters() -> ParameterValueList {
172 ParameterValueList::default()
173 }
174
175 fn symbol() -> Symbol {
177 Symbol::new_builtin(
178 Identifier::no_ref(Self::id()),
179 Some(Self::parameters()),
180 Self::function(),
181 )
182 }
183}