diff --git a/api/sixtyfps-rs/sixtyfps-rs-macro/lib.rs b/api/sixtyfps-rs/sixtyfps-rs-macro/lib.rs index 304827c99..e797aa41d 100644 --- a/api/sixtyfps-rs/sixtyfps-rs-macro/lib.rs +++ b/api/sixtyfps-rs/sixtyfps-rs-macro/lib.rs @@ -92,6 +92,16 @@ fn fill_token_vec(stream: TokenStream, vec: &mut Vec) { } SyntaxKind::OrOr } + '%' => { + // % can only exist after number literal + if let Some(last) = vec.last_mut() { + if last.kind == SyntaxKind::NumberLiteral { + last.text = format!("{}%", last.text).into(); + continue; + } + } + SyntaxKind::Error + } _ => SyntaxKind::Error, }; prev_spacing = p.spacing(); diff --git a/docs/langref.md b/docs/langref.md index 7032d6f7e..15978b69a 100644 --- a/docs/langref.md +++ b/docs/langref.md @@ -109,6 +109,7 @@ If one change the `my_property`, the width will be updated automatically. - FIXME: more `int32` and `float32` are the types for the numbers, they correspond to the equivalent in the target language +A number can end with '%', so for example `30%` is the same as `0.30` `string` are implicitly shared. diff --git a/sixtyfps_compiler/expression_tree.rs b/sixtyfps_compiler/expression_tree.rs index a2037b5ba..88cb8bdb4 100644 --- a/sixtyfps_compiler/expression_tree.rs +++ b/sixtyfps_compiler/expression_tree.rs @@ -78,6 +78,8 @@ macro_rules! declare_units { declare_units! { /// No unit was given None = "" -> Float32, + /// + Percent = "%" -> Float32 * 0.01, // Lenghts or Coord diff --git a/sixtyfps_compiler/parser.rs b/sixtyfps_compiler/parser.rs index 1ada411ac..15b855ff0 100644 --- a/sixtyfps_compiler/parser.rs +++ b/sixtyfps_compiler/parser.rs @@ -211,7 +211,7 @@ declare_syntax! { Whitespace -> r"\s+", Comment -> r"//.*\n|(?sU)/\*.*\*/", // FIXME: comments within comments StringLiteral -> r#""[^"]*""#, // FIXME: escapes - NumberLiteral -> r"[\d]+(\.[\d]*)?[\w]*", + NumberLiteral -> r"[\d]+(\.[\d]*)?[\w]*%?", ColorLiteral -> r"#[\w]+", Identifier -> r"[\w]+", LBrace -> r"\{", diff --git a/tests/cases/percent.60 b/tests/cases/percent.60 new file mode 100644 index 000000000..41f1fed83 --- /dev/null +++ b/tests/cases/percent.60 @@ -0,0 +1,45 @@ +TestCase := Rectangle { + property p1: 100%; + property p2: 1%; + property p3: 5.5%; + property p4: 10 + 50%; +} + + +/* + +```cpp +TestCase instance; +auto fuzzy_compare = [](float a, float b) { return std::abs(a - b) < 0.00000001; }; +assert(fuzzy_compare(instance.get_p1(), 1.)); +assert(fuzzy_compare(instance.get_p2(), 0.01)); +assert(fuzzy_compare(instance.get_p3(), 0.055)); +assert(fuzzy_compare(instance.get_p4(), 10.5)); +// self_test +assert(!fuzzy_compare(instance.get_p1(), 1.001)); +``` + +```rust +let instance = TestCase::new(); +let instance = instance.as_ref(); +assert_eq!(instance.get_p1(), 1.); +assert_eq!(instance.get_p2(), 0.01); +assert_eq!(instance.get_p3(), 0.055); +assert_eq!(instance.get_p4(), 10.5); + +assert_ne!(instance.get_p3(), 0.0549); +``` + +```js +var instance = new sixtyfps.TestCase({}); +function n(a) { return Math.round(a*1000000) } +assert.equal(n(instance.p1), n(1.)); +assert.equal(n(instance.p2), n(0.01)); +assert.equal(n(instance.p3), n(0.055)); +assert.equal(n(instance.p4), n(10.5)); +// self_test +assert.notEqual(n(instance.p1), n(1.001)); + +``` + +*/ \ No newline at end of file