Skip to content

Commit df1dd3b

Browse files
milianwogoffart
authored andcommitted
Use one central thread_local for builtin function types
Instead of occupying multiple TLS slots, introduce a single type that stores all the builtin function types in members. Use a macro to define this struct then, which allows us to use a nice DSL to define these function types, reducing the boiler plate significantly. The downside is that we no longer have the ability to easily share semantically equivalent function types (e.g. for `Round`, `Ceil` and `Floor` etc.). Doing so would require us to introdue a separate name for these types, and then use external matching to map the BuiltinFunctions to the reduced list of types. The performance impact is minimal though, so this is not done to KISS.
1 parent 6ff8abf commit df1dd3b

File tree

1 file changed

+120
-211
lines changed

1 file changed

+120
-211
lines changed

internal/compiler/expression_tree.rs

Lines changed: 120 additions & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -107,221 +107,130 @@ pub enum BuiltinMacroFunction {
107107
Debug,
108108
}
109109

110-
impl BuiltinFunction {
111-
pub fn ty(&self) -> Type {
112-
macro_rules! interned_type {
113-
( $x:expr ) => {{
114-
thread_local! {
115-
static TYPE: Type = Type::Function(Rc::new($x));
116-
}
117-
TYPE.with(|t| t.clone())
118-
}};
110+
macro_rules! declare_builtin_function_types {
111+
($( $Name:ident $(($Pattern:tt))? : ($( $Arg:expr ),*) -> $ReturnType:expr $(,)? )*) => {
112+
#[allow(non_snake_case)]
113+
pub struct BuiltinFunctionTypes {
114+
$(pub $Name : Type),*
119115
}
120-
121-
match self {
122-
BuiltinFunction::GetWindowScaleFactor => interned_type!(Function {
123-
return_type: Type::UnitProduct(vec![(Unit::Phx, 1), (Unit::Px, -1)]),
124-
args: vec![],
125-
}),
126-
BuiltinFunction::GetWindowDefaultFontSize => {
127-
interned_type!(Function { return_type: Type::LogicalLength, args: vec![] })
128-
}
129-
BuiltinFunction::AnimationTick => {
130-
interned_type!(Function { return_type: Type::Duration.into(), args: vec![] })
131-
}
132-
BuiltinFunction::Debug => {
133-
interned_type!(Function { return_type: Type::Void, args: vec![Type::String] })
134-
}
135-
BuiltinFunction::Mod => {
136-
interned_type!(Function {
137-
return_type: Type::Int32,
138-
args: vec![Type::Int32, Type::Int32]
139-
})
140-
}
141-
BuiltinFunction::Round | BuiltinFunction::Ceil | BuiltinFunction::Floor => {
142-
interned_type!(Function { return_type: Type::Int32, args: vec![Type::Float32] })
143-
}
144-
BuiltinFunction::Sqrt | BuiltinFunction::Abs => {
145-
interned_type!(Function { return_type: Type::Float32, args: vec![Type::Float32] })
146-
}
147-
BuiltinFunction::Cos | BuiltinFunction::Sin | BuiltinFunction::Tan => {
148-
interned_type!(Function { return_type: Type::Float32, args: vec![Type::Angle] })
149-
}
150-
BuiltinFunction::ACos | BuiltinFunction::ASin | BuiltinFunction::ATan => {
151-
interned_type!(Function { return_type: Type::Angle, args: vec![Type::Float32] })
152-
}
153-
BuiltinFunction::ATan2 => {
154-
interned_type!(Function {
155-
return_type: Type::Angle,
156-
args: vec![Type::Float32, Type::Float32]
157-
})
158-
}
159-
BuiltinFunction::Log | BuiltinFunction::Pow => {
160-
interned_type!(Function {
161-
return_type: Type::Float32,
162-
args: vec![Type::Float32, Type::Float32]
163-
})
164-
}
165-
BuiltinFunction::SetFocusItem
166-
| BuiltinFunction::ClearFocusItem
167-
| BuiltinFunction::ShowPopupWindow
168-
| BuiltinFunction::ClosePopupWindow
169-
| BuiltinFunction::ItemMemberFunction(..) => {
170-
interned_type!(Function {
171-
return_type: Type::Void,
172-
args: vec![Type::ElementReference]
173-
})
174-
}
175-
BuiltinFunction::SetSelectionOffsets => interned_type!(Function {
176-
return_type: Type::Void,
177-
args: vec![Type::ElementReference, Type::Int32, Type::Int32],
178-
}),
179-
BuiltinFunction::ItemFontMetrics => interned_type!(Function {
180-
return_type: crate::typeregister::font_metrics_type(),
181-
args: vec![Type::ElementReference],
182-
}),
183-
BuiltinFunction::StringToFloat => {
184-
interned_type!(Function { return_type: Type::Float32, args: vec![Type::String] })
185-
}
186-
BuiltinFunction::StringIsFloat => {
187-
interned_type!(Function { return_type: Type::Bool, args: vec![Type::String] })
188-
}
189-
BuiltinFunction::ImplicitLayoutInfo(_) => interned_type!(Function {
190-
return_type: crate::layout::layout_info_type(),
191-
args: vec![Type::ElementReference],
192-
}),
193-
BuiltinFunction::ColorRgbaStruct => interned_type!(Function {
194-
return_type: Type::Struct(Rc::new(Struct {
195-
fields: IntoIterator::into_iter([
196-
(SmolStr::new_static("red"), Type::Int32),
197-
(SmolStr::new_static("green"), Type::Int32),
198-
(SmolStr::new_static("blue"), Type::Int32),
199-
(SmolStr::new_static("alpha"), Type::Int32),
200-
])
201-
.collect(),
202-
name: Some("Color".into()),
203-
node: None,
204-
rust_attributes: None,
205-
})),
206-
args: vec![Type::Color],
207-
}),
208-
BuiltinFunction::ColorHsvaStruct => interned_type!(Function {
209-
return_type: Type::Struct(Rc::new(Struct {
210-
fields: IntoIterator::into_iter([
211-
(SmolStr::new_static("hue"), Type::Float32),
212-
(SmolStr::new_static("saturation"), Type::Float32),
213-
(SmolStr::new_static("value"), Type::Float32),
214-
(SmolStr::new_static("alpha"), Type::Float32),
215-
])
216-
.collect(),
217-
name: Some("Color".into()),
218-
node: None,
219-
rust_attributes: None,
220-
})),
221-
args: vec![Type::Color],
222-
}),
223-
BuiltinFunction::ColorBrighter
224-
| BuiltinFunction::ColorDarker
225-
| BuiltinFunction::ColorTransparentize
226-
| BuiltinFunction::ColorWithAlpha => {
227-
interned_type!(Function {
228-
return_type: Type::Brush,
229-
args: vec![Type::Brush, Type::Float32]
230-
})
231-
}
232-
BuiltinFunction::ColorMix => interned_type!(Function {
233-
return_type: Type::Color,
234-
args: vec![Type::Color, Type::Color, Type::Float32],
235-
}),
236-
BuiltinFunction::ImageSize => interned_type!(Function {
237-
return_type: Type::Struct(Rc::new(Struct {
238-
fields: IntoIterator::into_iter([
239-
(SmolStr::new_static("width"), Type::Int32),
240-
(SmolStr::new_static("height"), Type::Int32),
241-
])
242-
.collect(),
243-
name: Some("Size".into()),
244-
node: None,
245-
rust_attributes: None,
246-
})),
247-
args: vec![Type::Image],
248-
}),
249-
BuiltinFunction::ArrayLength => {
250-
interned_type!(Function { return_type: Type::Int32, args: vec![Type::Model] })
251-
}
252-
BuiltinFunction::Rgb => interned_type!(Function {
253-
return_type: Type::Color,
254-
args: vec![Type::Int32, Type::Int32, Type::Int32, Type::Float32],
255-
}),
256-
BuiltinFunction::Hsv => interned_type!(Function {
257-
return_type: Type::Color,
258-
args: vec![Type::Float32, Type::Float32, Type::Float32, Type::Float32],
259-
}),
260-
BuiltinFunction::ColorScheme => interned_type!(Function {
261-
return_type: Type::Enumeration(
262-
crate::typeregister::BUILTIN.with(|e| e.enums.ColorScheme.clone()),
263-
),
264-
args: vec![],
265-
}),
266-
BuiltinFunction::MonthDayCount | BuiltinFunction::MonthOffset => {
267-
interned_type!(Function {
268-
return_type: Type::Int32,
269-
args: vec![Type::Int32, Type::Int32]
270-
})
271-
}
272-
BuiltinFunction::FormatDate => interned_type!(Function {
273-
return_type: Type::String,
274-
args: vec![Type::String, Type::Int32, Type::Int32, Type::Int32],
275-
}),
276-
BuiltinFunction::TextInputFocused => {
277-
interned_type!(Function { return_type: Type::Bool, args: vec![] })
278-
}
279-
BuiltinFunction::DateNow => {
280-
interned_type!(Function {
281-
return_type: Type::Array(Rc::new(Type::Int32)),
282-
args: vec![]
283-
})
284-
}
285-
BuiltinFunction::ValidDate => {
286-
interned_type!(Function {
287-
return_type: Type::Bool,
288-
args: vec![Type::String, Type::String]
289-
})
290-
}
291-
BuiltinFunction::ParseDate => interned_type!(Function {
292-
return_type: Type::Array(Rc::new(Type::Int32)),
293-
args: vec![Type::String, Type::String],
294-
}),
295-
BuiltinFunction::SetTextInputFocused => {
296-
interned_type!(Function { return_type: Type::Void, args: vec![Type::Bool] })
297-
}
298-
BuiltinFunction::ItemAbsolutePosition => interned_type!(Function {
299-
return_type: crate::typeregister::logical_point_type(),
300-
args: vec![Type::ElementReference],
301-
}),
302-
BuiltinFunction::RegisterCustomFontByPath => {
303-
interned_type!(Function { return_type: Type::Void, args: vec![Type::String] })
304-
}
305-
BuiltinFunction::RegisterCustomFontByMemory | BuiltinFunction::RegisterBitmapFont => {
306-
interned_type!(Function { return_type: Type::Void, args: vec![Type::Int32] })
307-
}
308-
BuiltinFunction::Translate => interned_type!(Function {
309-
return_type: Type::String,
310-
// original, context, domain, args
311-
args: vec![
312-
Type::String,
313-
Type::String,
314-
Type::String,
315-
Type::Array(Type::String.into()),
316-
],
317-
}),
318-
BuiltinFunction::Use24HourFormat => {
319-
interned_type!(Function { return_type: Type::Bool, args: vec![] })
116+
impl BuiltinFunctionTypes {
117+
pub fn new() -> Self {
118+
Self {
119+
$($Name : Type::Function(Rc::new(Function{
120+
args: vec![$($Arg),*],
121+
return_type: $ReturnType,
122+
}))),*
123+
}
320124
}
321-
BuiltinFunction::UpdateTimers => {
322-
interned_type!(Function { return_type: Type::Void, args: vec![] })
125+
126+
pub fn ty(&self, function: &BuiltinFunction) -> Type {
127+
match function {
128+
$(BuiltinFunction::$Name $(($Pattern))? => self.$Name.clone()),*
129+
}
323130
}
324131
}
132+
};
133+
}
134+
135+
declare_builtin_function_types!(
136+
GetWindowScaleFactor: () -> Type::UnitProduct(vec![(Unit::Phx, 1), (Unit::Px, -1)]),
137+
GetWindowDefaultFontSize: () -> Type::LogicalLength,
138+
AnimationTick: () -> Type::Duration,
139+
Debug: (Type::String) -> Type::Void,
140+
Mod: (Type::Int32, Type::Int32) -> Type::Int32,
141+
Round: (Type::Float32) -> Type::Int32,
142+
Ceil: (Type::Float32) -> Type::Int32,
143+
Floor: (Type::Float32) -> Type::Int32,
144+
Sqrt: (Type::Float32) -> Type::Float32,
145+
Abs: (Type::Float32) -> Type::Float32,
146+
Cos: (Type::Angle) -> Type::Float32,
147+
Sin: (Type::Angle) -> Type::Float32,
148+
Tan: (Type::Angle) -> Type::Float32,
149+
ACos: (Type::Float32) -> Type::Angle,
150+
ASin: (Type::Float32) -> Type::Angle,
151+
ATan: (Type::Float32) -> Type::Angle,
152+
ATan2: (Type::Float32, Type::Float32) -> Type::Angle,
153+
Log: (Type::Float32, Type::Float32) -> Type::Float32,
154+
Pow: (Type::Float32, Type::Float32) -> Type::Float32,
155+
SetFocusItem: (Type::ElementReference) -> Type::Void,
156+
ClearFocusItem: (Type::ElementReference) -> Type::Void,
157+
ShowPopupWindow: (Type::ElementReference) -> Type::Void,
158+
ClosePopupWindow: (Type::ElementReference) -> Type::Void,
159+
ItemMemberFunction(..): (Type::ElementReference) -> Type::Void,
160+
SetSelectionOffsets: (Type::ElementReference, Type::Int32, Type::Int32) -> Type::Void,
161+
ItemFontMetrics: (Type::ElementReference) -> crate::typeregister::font_metrics_type(),
162+
StringToFloat: (Type::String) -> Type::Float32,
163+
StringIsFloat: (Type::String) -> Type::Bool,
164+
ImplicitLayoutInfo(..): (Type::ElementReference) -> crate::layout::layout_info_type(),
165+
ColorRgbaStruct: (Type::Color) -> Type::Struct(Rc::new(Struct {
166+
fields: IntoIterator::into_iter([
167+
(SmolStr::new_static("red"), Type::Int32),
168+
(SmolStr::new_static("green"), Type::Int32),
169+
(SmolStr::new_static("blue"), Type::Int32),
170+
(SmolStr::new_static("alpha"), Type::Int32),
171+
])
172+
.collect(),
173+
name: Some("Color".into()),
174+
node: None,
175+
rust_attributes: None,
176+
})),
177+
ColorHsvaStruct: (Type::Color) -> Type::Struct(Rc::new(Struct {
178+
fields: IntoIterator::into_iter([
179+
(SmolStr::new_static("hue"), Type::Float32),
180+
(SmolStr::new_static("saturation"), Type::Float32),
181+
(SmolStr::new_static("value"), Type::Float32),
182+
(SmolStr::new_static("alpha"), Type::Float32),
183+
])
184+
.collect(),
185+
name: Some("Color".into()),
186+
node: None,
187+
rust_attributes: None,
188+
})),
189+
ColorBrighter: (Type::Brush, Type::Float32) -> Type::Brush,
190+
ColorDarker: (Type::Brush, Type::Float32) -> Type::Brush,
191+
ColorTransparentize: (Type::Brush, Type::Float32) -> Type::Brush,
192+
ColorWithAlpha: (Type::Brush, Type::Float32) -> Type::Brush,
193+
ColorMix: (Type::Color, Type::Color, Type::Float32) -> Type::Color,
194+
ImageSize: (Type::Image) -> Type::Struct(Rc::new(Struct {
195+
fields: IntoIterator::into_iter([
196+
(SmolStr::new_static("width"), Type::Int32),
197+
(SmolStr::new_static("height"), Type::Int32),
198+
])
199+
.collect(),
200+
name: Some("Size".into()),
201+
node: None,
202+
rust_attributes: None,
203+
})),
204+
ArrayLength: (Type::Model) -> Type::Int32,
205+
Rgb: (Type::Int32, Type::Int32, Type::Int32, Type::Float32) -> Type::Color,
206+
Hsv: (Type::Float32, Type::Float32, Type::Float32, Type::Float32) -> Type::Color,
207+
ColorScheme: () -> Type::Enumeration(
208+
crate::typeregister::BUILTIN.with(|e| e.enums.ColorScheme.clone()),
209+
),
210+
MonthDayCount: (Type::Int32, Type::Int32) -> Type::Int32,
211+
MonthOffset: (Type::Int32, Type::Int32) -> Type::Int32,
212+
FormatDate: (Type::String, Type::Int32, Type::Int32, Type::Int32) -> Type::String,
213+
TextInputFocused: () -> Type::Bool,
214+
DateNow: () -> Type::Array(Rc::new(Type::Int32)),
215+
ValidDate: (Type::String, Type::String) -> Type::Bool,
216+
ParseDate: (Type::String, Type::String) -> Type::Array(Rc::new(Type::Int32)),
217+
SetTextInputFocused: (Type::Bool) -> Type::Void,
218+
ItemAbsolutePosition: (Type::ElementReference) -> crate::typeregister::logical_point_type(),
219+
RegisterCustomFontByPath: (Type::String) -> Type::Void,
220+
RegisterCustomFontByMemory: (Type::Int32) -> Type::Void,
221+
RegisterBitmapFont: (Type::Int32) -> Type::Void,
222+
// original, context, domain, args
223+
Translate: (Type::String, Type::String, Type::String, Type::Array(Type::String.into())) -> Type::String,
224+
Use24HourFormat: () -> Type::Bool,
225+
UpdateTimers: () -> Type::Void,
226+
);
227+
228+
impl BuiltinFunction {
229+
pub fn ty(&self) -> Type {
230+
thread_local! {
231+
static TYPES: BuiltinFunctionTypes = BuiltinFunctionTypes::new();
232+
}
233+
TYPES.with(|types| types.ty(&self))
325234
}
326235

327236
/// It is const if the return value only depends on its argument and has no side effect

0 commit comments

Comments
 (0)