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::Builtin(_)
| Type::Native(_)
| Type::Function { .. }
| Type::Model
| Type::Signal
| 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)]
pub enum OperatorClass {
ComparisonOp,
@ -147,6 +163,9 @@ pub enum Expression {
/// Reference to the signal <name> in the <element>
PropertyReference(NamedReference),
/// Reference to a function built into the run-time, implemented natively
BuiltinFunctionReference(BuiltinFunction),
/// Reference to the index variable of a repeater
///
/// 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 }) => {
element.upgrade().unwrap().borrow().lookup_property(name)
}
Expression::BuiltinFunctionReference(funcref) => funcref.ty(),
Expression::RepeaterIndexReference { .. } => Type::Int32,
Expression::RepeaterModelReference { element } => {
if let Expression::Cast { from, .. } = element
@ -345,6 +365,7 @@ impl Expression {
Expression::BoolLiteral(_) => {}
Expression::SignalReference { .. } => {}
Expression::PropertyReference { .. } => {}
Expression::BuiltinFunctionReference { .. } => {}
Expression::ObjectAccess { base, .. } => visitor(&**base),
Expression::RepeaterIndexReference { .. } => {}
Expression::RepeaterModelReference { .. } => {}
@ -402,6 +423,7 @@ impl Expression {
Expression::BoolLiteral(_) => {}
Expression::SignalReference { .. } => {}
Expression::PropertyReference { .. } => {}
Expression::BuiltinFunctionReference { .. } => {}
Expression::ObjectAccess { base, .. } => visitor(&mut **base),
Expression::RepeaterIndexReference { .. } => {}
Expression::RepeaterModelReference { .. } => {}
@ -459,6 +481,7 @@ impl Expression {
Expression::BoolLiteral(_) => true,
Expression::SignalReference { .. } => false,
Expression::PropertyReference { .. } => false,
Expression::BuiltinFunctionReference { .. } => false,
Expression::RepeaterIndexReference { .. } => false,
Expression::RepeaterModelReference { .. } => false,
Expression::ObjectAccess { base, .. } => base.is_constant(),
@ -500,7 +523,28 @@ impl Expression {
if ty == target_type {
self
} 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 {
self
} else {
@ -517,6 +561,7 @@ impl Expression {
| Type::Builtin(_)
| Type::Native(_)
| Type::Signal
| Type::Function { .. }
| Type::Void => Expression::Invalid,
Type::Float32 => 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::expression_tree::{EasingCurve, Expression, ExpressionSpanned};
use crate::expression_tree::{BuiltinFunction, EasingCurve, Expression, ExpressionSpanned};
use crate::layout::{GridLayout, Layout, LayoutItem, PathLayout};
use crate::object_tree::{Component, Element, ElementRc, RepeatedElementInfo};
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");
format!(r#"{}.emit()"#, access)
}
Expression::BuiltinFunctionReference(funcref) => match funcref {
BuiltinFunction::GetWindowScaleFactor => window_scale_factor_expression(component),
},
Expression::RepeaterIndexReference { element } => {
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
"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::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,
}
}
@ -898,7 +895,7 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
format!("[&]{{ {} }}()", x.join(";"))
}
Expression::FunctionCall { function } => {
if matches!(function.ty(), Type::Signal) {
if matches!(function.ty(), Type::Signal | Type::Function{..}) {
compile_expression(&*function, component)
} else {
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::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::{
layout::{GridLayout, Layout, LayoutItem, PathLayout},
@ -607,14 +609,6 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
(Type::Float32, Type::Color) => {
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,
}
}
@ -623,6 +617,9 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
access_member(&element.upgrade().unwrap(), name.as_str(), component, quote!(_self));
quote!(#access.get())
}
Expression::BuiltinFunctionReference(funcref) => match funcref {
BuiltinFunction::GetWindowScaleFactor => window_scale_factor_expression(component),
},
Expression::RepeaterIndexReference { element } => {
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
let component_id = component_id(&component);
@ -661,7 +658,7 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
quote!(#access.emit(()))
}
Expression::FunctionCall { function } => {
if matches!(function.ty(), Type::Signal) {
if matches!(function.ty(), Type::Signal | Type::Function{..}) {
compile_expression(function, &component)
} else {
let error = format!("the function {:?} is not a signal", e);

View file

@ -12,6 +12,10 @@ pub enum Type {
Native(Rc<NativeClass>),
Signal,
Function {
return_type: Box<Type>,
args: Vec<Type>,
},
// Other property types:
Float32,
@ -40,6 +44,10 @@ impl core::cmp::PartialEq for Type {
(Type::Builtin(a), Type::Builtin(b)) => Rc::ptr_eq(a, b),
(Type::Native(a), Type::Native(b)) => Rc::ptr_eq(a, b),
(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::Int32, Type::Int32) => 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::Native(b) => b.class_name.fmt(f),
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::Int32 => write!(f, "int"),
Type::String => write!(f, "string"),

View file

@ -1,7 +1,7 @@
use core::convert::{TryFrom, TryInto};
use core::pin::Pin;
use sixtyfps_compilerlib::expression_tree::{
EasingCurve, Expression, ExpressionSpanned, NamedReference, Path as ExprPath,
BuiltinFunction, EasingCurve, Expression, ExpressionSpanned, NamedReference, Path as ExprPath,
PathElement as ExprPathElement,
};
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::BoolLiteral(b) => Value::Bool(*b),
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 }) => {
let element = element.upgrade().unwrap();
let (component_mem, component_type, _) =
@ -197,12 +200,6 @@ pub fn eval_expression(
Value::String(SharedString::from(format!("{}", n).as_str()))
}
(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,
}
}
@ -238,6 +235,12 @@ pub fn eval_expression(
};
signal.emit(());
Value::Void
} else if let Expression::BuiltinFunctionReference(funcref) = &**function {
match funcref {
BuiltinFunction::GetWindowScaleFactor => {
Value::Number(window_scale_factor(component_type, component_ref))
}
}
} else {
panic!("call of something not a signal")
}