Represent the window scale factor conversions in the IR

That means less code in the generators and easier to extend in the
future with more built-in functions.
This commit is contained in:
Simon Hausmann 2020-08-04 09:10:24 +02:00
parent 1d0eacc87f
commit 41671e3efb
6 changed files with 87 additions and 26 deletions

View file

@ -117,6 +117,7 @@ fn to_eval_value<'cx>(
| Type::Component(_) | Type::Component(_)
| Type::Builtin(_) | Type::Builtin(_)
| Type::Native(_) | Type::Native(_)
| Type::Function { .. }
| Type::Model | Type::Model
| Type::Signal | Type::Signal
| Type::Easing | Type::Easing

View file

@ -30,6 +30,22 @@ impl Hash for NamedReference {
} }
} }
#[derive(Debug, Clone)]
/// A function built into the run-time
pub enum BuiltinFunction {
GetWindowScaleFactor,
}
impl BuiltinFunction {
fn ty(&self) -> Type {
match self {
BuiltinFunction::GetWindowScaleFactor => {
Type::Function { return_type: Box::new(Type::Float32), args: vec![] }
}
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub enum OperatorClass { pub enum OperatorClass {
ComparisonOp, ComparisonOp,
@ -147,6 +163,9 @@ pub enum Expression {
/// Reference to the signal <name> in the <element> /// Reference to the signal <name> in the <element>
PropertyReference(NamedReference), PropertyReference(NamedReference),
/// Reference to a function built into the run-time, implemented natively
BuiltinFunctionReference(BuiltinFunction),
/// Reference to the index variable of a repeater /// Reference to the index variable of a repeater
/// ///
/// Example: `idx` in `for xxx[idx] in ...`. The element is the reference to the /// Example: `idx` in `for xxx[idx] in ...`. The element is the reference to the
@ -263,6 +282,7 @@ impl Expression {
Expression::PropertyReference(NamedReference { element, name }) => { Expression::PropertyReference(NamedReference { element, name }) => {
element.upgrade().unwrap().borrow().lookup_property(name) element.upgrade().unwrap().borrow().lookup_property(name)
} }
Expression::BuiltinFunctionReference(funcref) => funcref.ty(),
Expression::RepeaterIndexReference { .. } => Type::Int32, Expression::RepeaterIndexReference { .. } => Type::Int32,
Expression::RepeaterModelReference { element } => { Expression::RepeaterModelReference { element } => {
if let Expression::Cast { from, .. } = element if let Expression::Cast { from, .. } = element
@ -345,6 +365,7 @@ impl Expression {
Expression::BoolLiteral(_) => {} Expression::BoolLiteral(_) => {}
Expression::SignalReference { .. } => {} Expression::SignalReference { .. } => {}
Expression::PropertyReference { .. } => {} Expression::PropertyReference { .. } => {}
Expression::BuiltinFunctionReference { .. } => {}
Expression::ObjectAccess { base, .. } => visitor(&**base), Expression::ObjectAccess { base, .. } => visitor(&**base),
Expression::RepeaterIndexReference { .. } => {} Expression::RepeaterIndexReference { .. } => {}
Expression::RepeaterModelReference { .. } => {} Expression::RepeaterModelReference { .. } => {}
@ -402,6 +423,7 @@ impl Expression {
Expression::BoolLiteral(_) => {} Expression::BoolLiteral(_) => {}
Expression::SignalReference { .. } => {} Expression::SignalReference { .. } => {}
Expression::PropertyReference { .. } => {} Expression::PropertyReference { .. } => {}
Expression::BuiltinFunctionReference { .. } => {}
Expression::ObjectAccess { base, .. } => visitor(&mut **base), Expression::ObjectAccess { base, .. } => visitor(&mut **base),
Expression::RepeaterIndexReference { .. } => {} Expression::RepeaterIndexReference { .. } => {}
Expression::RepeaterModelReference { .. } => {} Expression::RepeaterModelReference { .. } => {}
@ -459,6 +481,7 @@ impl Expression {
Expression::BoolLiteral(_) => true, Expression::BoolLiteral(_) => true,
Expression::SignalReference { .. } => false, Expression::SignalReference { .. } => false,
Expression::PropertyReference { .. } => false, Expression::PropertyReference { .. } => false,
Expression::BuiltinFunctionReference { .. } => false,
Expression::RepeaterIndexReference { .. } => false, Expression::RepeaterIndexReference { .. } => false,
Expression::RepeaterModelReference { .. } => false, Expression::RepeaterModelReference { .. } => false,
Expression::ObjectAccess { base, .. } => base.is_constant(), Expression::ObjectAccess { base, .. } => base.is_constant(),
@ -500,7 +523,28 @@ impl Expression {
if ty == target_type { if ty == target_type {
self self
} else if ty.can_convert(&target_type) { } else if ty.can_convert(&target_type) {
Expression::Cast { from: Box::new(self), to: target_type } let from = match (ty, &target_type) {
(Type::Length, Type::LogicalLength) => Expression::BinaryExpression {
lhs: Box::new(self),
rhs: Box::new(Expression::FunctionCall {
function: Box::new(Expression::BuiltinFunctionReference(
BuiltinFunction::GetWindowScaleFactor,
)),
}),
op: '/',
},
(Type::LogicalLength, Type::Length) => Expression::BinaryExpression {
lhs: Box::new(self),
rhs: Box::new(Expression::FunctionCall {
function: Box::new(Expression::BuiltinFunctionReference(
BuiltinFunction::GetWindowScaleFactor,
)),
}),
op: '*',
},
_ => self,
};
Expression::Cast { from: Box::new(from), to: target_type }
} else if ty == Type::Invalid || target_type == Type::Invalid { } else if ty == Type::Invalid || target_type == Type::Invalid {
self self
} else { } else {
@ -517,6 +561,7 @@ impl Expression {
| Type::Builtin(_) | Type::Builtin(_)
| Type::Native(_) | Type::Native(_)
| Type::Signal | Type::Signal
| Type::Function { .. }
| Type::Void => Expression::Invalid, | Type::Void => Expression::Invalid,
Type::Float32 => Expression::NumberLiteral(0., Unit::None), Type::Float32 => Expression::NumberLiteral(0., Unit::None),
Type::Int32 => Expression::NumberLiteral(0., Unit::None), Type::Int32 => Expression::NumberLiteral(0., Unit::None),

View file

@ -155,7 +155,7 @@ mod cpp_ast {
} }
use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, Spanned}; use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, Spanned};
use crate::expression_tree::{EasingCurve, Expression, ExpressionSpanned}; use crate::expression_tree::{BuiltinFunction, EasingCurve, Expression, ExpressionSpanned};
use crate::layout::{GridLayout, Layout, LayoutItem, PathLayout}; use crate::layout::{GridLayout, Layout, LayoutItem, PathLayout};
use crate::object_tree::{Component, Element, ElementRc, RepeatedElementInfo}; use crate::object_tree::{Component, Element, ElementRc, RepeatedElementInfo};
use crate::typeregister::Type; use crate::typeregister::Type;
@ -843,6 +843,9 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
access_member(&element.upgrade().unwrap(), name.as_str(), component, "self"); access_member(&element.upgrade().unwrap(), name.as_str(), component, "self");
format!(r#"{}.emit()"#, access) format!(r#"{}.emit()"#, access)
} }
Expression::BuiltinFunctionReference(funcref) => match funcref {
BuiltinFunction::GetWindowScaleFactor => window_scale_factor_expression(component),
},
Expression::RepeaterIndexReference { element } => { Expression::RepeaterIndexReference { element } => {
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) { if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
"self->index.get()".to_owned() "self->index.get()".to_owned()
@ -882,12 +885,6 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
} }
(Type::Array(_), Type::Model) => f, (Type::Array(_), Type::Model) => f,
(Type::Float32, Type::Color) => format!("sixtyfps::Color({})", f), (Type::Float32, Type::Color) => format!("sixtyfps::Color({})", f),
(Type::LogicalLength, Type::Length) => {
format!("({} * {})", f, window_scale_factor_expression(component))
}
(Type::Length, Type::LogicalLength) => {
format!("({} / {})", f, window_scale_factor_expression(component))
}
_ => f, _ => f,
} }
} }
@ -898,7 +895,7 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
format!("[&]{{ {} }}()", x.join(";")) format!("[&]{{ {} }}()", x.join(";"))
} }
Expression::FunctionCall { function } => { Expression::FunctionCall { function } => {
if matches!(function.ty(), Type::Signal) { if matches!(function.ty(), Type::Signal | Type::Function{..}) {
compile_expression(&*function, component) compile_expression(&*function, component)
} else { } else {
format!("\n#error the function `{:?}` is not a signal\n", function) format!("\n#error the function `{:?}` is not a signal\n", function)

View file

@ -2,7 +2,9 @@
*/ */
use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, Spanned}; use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, Spanned};
use crate::expression_tree::{EasingCurve, Expression, NamedReference, OperatorClass, Path}; use crate::expression_tree::{
BuiltinFunction, EasingCurve, Expression, NamedReference, OperatorClass, Path,
};
use crate::object_tree::{Component, ElementRc}; use crate::object_tree::{Component, ElementRc};
use crate::{ use crate::{
layout::{GridLayout, Layout, LayoutItem, PathLayout}, layout::{GridLayout, Layout, LayoutItem, PathLayout},
@ -607,14 +609,6 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
(Type::Float32, Type::Color) => { (Type::Float32, Type::Color) => {
quote!(sixtyfps::re_exports::Color::from(#f as u32)) quote!(sixtyfps::re_exports::Color::from(#f as u32))
} }
(Type::LogicalLength, Type::Length) => {
let window_scale_factor_expression = window_scale_factor_expression(component);
quote!((#f as f64) * #window_scale_factor_expression as f64)
}
(Type::Length, Type::LogicalLength) => {
let window_scale_factor_expression = window_scale_factor_expression(component);
quote!((#f as f64) / #window_scale_factor_expression as f64)
}
_ => f, _ => f,
} }
} }
@ -623,6 +617,9 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
access_member(&element.upgrade().unwrap(), name.as_str(), component, quote!(_self)); access_member(&element.upgrade().unwrap(), name.as_str(), component, quote!(_self));
quote!(#access.get()) quote!(#access.get())
} }
Expression::BuiltinFunctionReference(funcref) => match funcref {
BuiltinFunction::GetWindowScaleFactor => window_scale_factor_expression(component),
},
Expression::RepeaterIndexReference { element } => { Expression::RepeaterIndexReference { element } => {
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) { if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
let component_id = component_id(&component); let component_id = component_id(&component);
@ -661,7 +658,7 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
quote!(#access.emit(())) quote!(#access.emit(()))
} }
Expression::FunctionCall { function } => { Expression::FunctionCall { function } => {
if matches!(function.ty(), Type::Signal) { if matches!(function.ty(), Type::Signal | Type::Function{..}) {
compile_expression(function, &component) compile_expression(function, &component)
} else { } else {
let error = format!("the function {:?} is not a signal", e); let error = format!("the function {:?} is not a signal", e);

View file

@ -12,6 +12,10 @@ pub enum Type {
Native(Rc<NativeClass>), Native(Rc<NativeClass>),
Signal, Signal,
Function {
return_type: Box<Type>,
args: Vec<Type>,
},
// Other property types: // Other property types:
Float32, Float32,
@ -40,6 +44,10 @@ impl core::cmp::PartialEq for Type {
(Type::Builtin(a), Type::Builtin(b)) => Rc::ptr_eq(a, b), (Type::Builtin(a), Type::Builtin(b)) => Rc::ptr_eq(a, b),
(Type::Native(a), Type::Native(b)) => Rc::ptr_eq(a, b), (Type::Native(a), Type::Native(b)) => Rc::ptr_eq(a, b),
(Type::Signal, Type::Signal) => true, (Type::Signal, Type::Signal) => true,
(
Type::Function { return_type: lhs_rt, args: lhs_args },
Type::Function { return_type: rhs_rt, args: rhs_args },
) => lhs_rt == rhs_rt && lhs_args == rhs_args,
(Type::Float32, Type::Float32) => true, (Type::Float32, Type::Float32) => true,
(Type::Int32, Type::Int32) => true, (Type::Int32, Type::Int32) => true,
(Type::String, Type::String) => true, (Type::String, Type::String) => true,
@ -68,6 +76,16 @@ impl Display for Type {
Type::Builtin(b) => b.native_class.class_name.fmt(f), Type::Builtin(b) => b.native_class.class_name.fmt(f),
Type::Native(b) => b.class_name.fmt(f), Type::Native(b) => b.class_name.fmt(f),
Type::Signal => write!(f, "signal"), Type::Signal => write!(f, "signal"),
Type::Function { return_type, args } => {
write!(f, "function(")?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ",")?;
}
write!(f, "{}", arg)?;
}
write!(f, ") -> {}", return_type)
}
Type::Float32 => write!(f, "float"), Type::Float32 => write!(f, "float"),
Type::Int32 => write!(f, "int"), Type::Int32 => write!(f, "int"),
Type::String => write!(f, "string"), Type::String => write!(f, "string"),

View file

@ -1,7 +1,7 @@
use core::convert::{TryFrom, TryInto}; use core::convert::{TryFrom, TryInto};
use core::pin::Pin; use core::pin::Pin;
use sixtyfps_compilerlib::expression_tree::{ use sixtyfps_compilerlib::expression_tree::{
EasingCurve, Expression, ExpressionSpanned, NamedReference, Path as ExprPath, BuiltinFunction, EasingCurve, Expression, ExpressionSpanned, NamedReference, Path as ExprPath,
PathElement as ExprPathElement, PathElement as ExprPathElement,
}; };
use sixtyfps_compilerlib::{object_tree::ElementRc, typeregister::Type}; use sixtyfps_compilerlib::{object_tree::ElementRc, typeregister::Type};
@ -138,6 +138,9 @@ pub fn eval_expression(
Expression::NumberLiteral(n, unit) => Value::Number(unit.normalize(*n)), Expression::NumberLiteral(n, unit) => Value::Number(unit.normalize(*n)),
Expression::BoolLiteral(b) => Value::Bool(*b), Expression::BoolLiteral(b) => Value::Bool(*b),
Expression::SignalReference { .. } => panic!("signal in expression"), Expression::SignalReference { .. } => panic!("signal in expression"),
Expression::BuiltinFunctionReference(_) => panic!(
"naked builtin function reference not allowed, should be handled by function call"
),
Expression::PropertyReference(NamedReference { element, name }) => { Expression::PropertyReference(NamedReference { element, name }) => {
let element = element.upgrade().unwrap(); let element = element.upgrade().unwrap();
let (component_mem, component_type, _) = let (component_mem, component_type, _) =
@ -197,12 +200,6 @@ pub fn eval_expression(
Value::String(SharedString::from(format!("{}", n).as_str())) Value::String(SharedString::from(format!("{}", n).as_str()))
} }
(Value::Number(n), Type::Color) => Value::Color(Color::from(n as u32)), (Value::Number(n), Type::Color) => Value::Color(Color::from(n as u32)),
(Value::Number(n), Type::Length) => {
Value::Number(n * window_scale_factor(component_type, component_ref))
}
(Value::Number(n), Type::LogicalLength) => {
Value::Number(n / window_scale_factor(component_type, component_ref))
}
(v, _) => v, (v, _) => v,
} }
} }
@ -238,6 +235,12 @@ pub fn eval_expression(
}; };
signal.emit(()); signal.emit(());
Value::Void Value::Void
} else if let Expression::BuiltinFunctionReference(funcref) = &**function {
match funcref {
BuiltinFunction::GetWindowScaleFactor => {
Value::Number(window_scale_factor(component_type, component_ref))
}
}
} else { } else {
panic!("call of something not a signal") panic!("call of something not a signal")
} }