Is it possible for sweet.js macros to define other macros? - sweet.js

I have attempted to define a sweet.js macro that allows other repeating macros to be defined more easily, but I have found a syntax error here:
SyntaxError: [patterns] Ellipses level does not match in the template
11: { $($b...)... }
This is the macro that produced this syntax error:
macro repeatingMacro{
rule{
$a {
$b...
} {
$c...
}
} => {
//the output of this macro should be another macro with repeating patterns
macro $a {
rule{
{ $($b...)... }
} => {
{ $($c...)... }
}
}
}
}
If this macro were correctly defined, then it would allow other macros to be created, like this one:
repeatingMacro cond {
$a... { $b... }
}
{
if($a...){
$b...
}
}
var x = 1;
var y = 2;
cond {
(x > y) {
alert(x);
}
(x < y) {
alert(y)
}
}
This code can be edited online here.
In other words, is it possible to define a macro that will automatically transform this macro:
macro cond {
rule {
$x... { $y... }
} => {
if($x...){
$y...
}
}
}
...into this macro?
macro cond {
rule {
{ $($x... { $y... })... }
} => {
$(if($x...){
$y...
})...
}
}

The immediate problem you are running into is that if you need to emit literal ellipses ... in the template of a macro you need to escape it by doing $[...].
But at a higher level, are you sure you need to go to the effort of macro defining macros here? Sweet.js actually has a nice declarative feature called macroclass (documented here) that makes doing things like this really simple. In fact, cond is the example we use:
// define the cond_clause pattern class
macroclass cond_clause {
pattern {
rule { $check:expr => $body:expr }
}
}
macro cond {
rule { $first:cond_clause $rest:cond_clause ... } => {
// sub-pattern variables in the custom class are
// referenced by concatenation
if ($first$check) {
$first$body
} $(else if ($rest$check) {
$rest$body
}) ...
}
}
cond
x < 3 => console.log("less than 3")
x == 3 => console.log("3")
x > 3 => console.log("greater than 3")

Related

Getting reference to shared data in async closure [duplicate]

I have something like this:
use std::sync::Arc;
fn main() {
let arc = Arc::new(42);
move || { arc.clone() };
move || { arc.clone() };
}
I am getting:
error[E0382]: capture of moved value: `arc`
--> src/main.rs:6:19
|
5 | move || { arc.clone() };
| ------- value moved (into closure) here
6 | move || { arc.clone() };
| ^^^ value captured here after move
|
= note: move occurs because `arc` has type `std::sync::Arc<i32>`, which does not implement the `Copy` trait
I understand why I am getting this: the clone isn't called before arc is passed to the closure. I can fix this by defining each closure in a function and clone the Arc before passing it to the closure, but is there another option?
There is no way around it. You should clone the Arc before it is used in a closure. The common pattern is to re-bind the cloned Arc to the same name in a nested scope:
use std::sync::Arc;
fn main() {
let arc = Arc::new(42);
{
let arc = arc.clone();
move || { /* do something with arc */ };
}
{
let arc = arc.clone();
move || { /* do something else with arc */ };
}
}
This is usually done together with thread::spawn():
use std::sync::{Arc, Mutex};
use std::thread;
const NUM_THREADS: usize = 4;
fn main() {
let arc = Arc::new(Mutex::new(42));
for _ in 0..NUM_THREADS {
let arc = arc.clone();
thread::spawn(move || {
let mut shared_data = arc.lock().unwrap();
*shared_data += 1;
});
}
}
is there another option?
Because this pattern of cloning things before defining a closure is somewhat common, some people have proposed adding something like clone || as an analog to move ||. I wouldn't hold out hope for this happening, but a number of comments there point out that macros can solve the case fairly well.
Several crates provide some form of this macro:
closet
capture
clone_all
It's likely that many projects define their own macro to do something similar. For example, the WASM example rust-todomvc defines:
macro_rules! enclose {
( ($( $x:ident ),*) $y:expr ) => {
{
$(let $x = $x.clone();)*
$y
}
};
}
Which can be used as:
fn main() {
let arc = Arc::new(42);
enclose! { (arc) move || arc };
enclose! { (arc) move || arc };
}

Nested Matchers in GTest

I would like to use some existing matchers in other matcher. I know about the MatcherInterface solution but I was wondering can I use matchers which were defined by MATCHER_P. If found this solution:
struct Foo
{
double x;
double y;
};
struct Bar
{
Foo foo;
int i;
};
MATCHER_P(EqFoo, foo, "")
{
::testing::Matcher<double> x_matcher = ::testing::DoubleNear(foo.x, 0.0001);
if (!x_matcher.MatchAndExplain(arg.x, result_listener))
{
return false;
}
::testing::Matcher<double> y_matcher = ::testing::DoubleNear(foo.y, 0.0001);
if (!y_matcher.MatchAndExplain(arg.y, result_listener))
{
return false;
}
return true;
}
MATCHER_P(EqBar, bar, "")
{
::testing::Matcher<Foo> foo_matcher = EqFooMatcherP<Foo>(bar.foo);
if (!foo_matcher.MatchAndExplain(arg.foo, result_listener))
{
return false;
}
if (bar.i != arg.i)
{
return false;
}
return true;
}
TEST_F(TestClass, BarTest)
{
Bar bar_val{{10.12, 76.43}, 78};
Bar bar_exp{{10.12, 99.99}, 78};
EXPECT_THAT(bar_val, EqBar(bar_exp));
}
I am just wondering, is there any better and nicer solution to
use my own MATCHER_P matcher in another one
use an original GTest matcher in another one.
The correct way is to use, as much as possible, the matchers from gtest/gmock. Only if there is no already provided matchers - use your own.
In your example - it is just as simple as this:
auto EqFoo(const Foo& expected)
{
return ::testing::AllOf(
::testing::Field(&Foo::x, ::testing::DoubleNear(expected.x, 0.0001)),
::testing::Field(&Foo::y, ::testing::DoubleNear(expected.y, 0.0001))
);
}
auto EqBar(const Bar& expected)
{
return ::testing::AllOf(
::testing::Field(&Bar::foo, EqFoo(expected.foo)),
::testing::Field(&Bar::i, expected.i)
);
}
More general approach is to use overloads:
auto MatchDouble(double expected)
{
return ::testing::DoubleNear(expected.x, 0.0001);
}
auto MatchFoo(::testing::Matcher<double> x, ::testing::Matcher<double> y)
{
return ::testing::AllOf(
::testing::Field(&Foo::x, x),
::testing::Field(&Foo::y, y)
);
}
auto MatchFoo(double x, double y)
{
return MatchFoo(MatchDouble(x), MatchDouble(y));
}
auto MatchBar(::testing::Matcher<Foo> foo, ::testing::Matcher<int> i)
{
return ::testing::AllOf(
::testing::Field(&Bar::foo, foo),
::testing::Field(&Bar::i, expected.i),
);
}
auto MatchBar(const Bar& expected)
{
return MatchBar(expected.foo, expected.i);
}
So your test:
TEST_F(TestClass, BarTest)
{
Bar bar_val{{10.12, 76.43}, 78};
Bar bar_exp{{10.12, 99.99}, 78};
EXPECT_THAT(bar_val, MatchBar(bar_exp));
// or - e.g. you can match only Bar::y if other things are irrelevant in your test
EXPECT_THAT(bar_val, MatchBar(MatchFoo(_, MatchDouble(2.001)), _);
}
Anyway - using MATCHER_P should be rather rare case, my own observation is that this macro is really overused.
In case your project is pre-C++14 - use ::testing::Matcher<T> instead of auto as return type for all of these functions.

Accessing different properties in a typescript union type

I'm creating a function that handles objects from the database. I have two different data structures where the same property has a different name. I can't change that, so I have to handle it in JavaScript.
The objects have other differences, but that's not important to this function.
I want to use the same function for two different types of objects. Here's sample code demonstrating my problem:
interface TypeA {
itemName: string;
}
interface TypeB {
itemTitle: string;
}
function getItemName(item: TypeA | TypeB): string {
let name = '';
if (item.hasOwnProperty('itemName')) {
name = item.itemName;
} else {
name = item.itemTitle;
}
return name;
}
Of course, this code runs. But the IDE marks both the lines name = item.itemName; and name = item.itemTitle; as errors ("Property does not exist on type"), because both types do not have both properties.
So, what's the proper typescript way to do this?
You need to create a User Defined Type Guard, then you can use an if statement and get the correct typing.
function isTypeA(value: TypeA | TypeB): value is TypeA {
return value.hasOwnProperty('itemName');
}
Then you can get the typing much cleaner:
function getItemName(item: TypeA | TypeB): string {
return isTypeA(item) ? item.itemName : item.itemTitle;
}
Check it out here. Item is correctly cast to either TypeA or TypeB.
I might be a little bit late, but you could give this a try inside your function:
if ('itemName' in item) {
name = item.itemName;
} else {
name = item.itemTitle;
}
you can make a type assertion if you don't do this too often :
if (item.hasOwnProperty('itemName')) {
name = (item as TypeA).itemName;
} else {
name = (item as TypeB).itemTitle;
}
or
if (item.hasOwnProperty('itemName')) {
name = (<TypeA>item).itemName;
} else {
name = (<TypeB>item).itemTitle;
}
if you need to make this check more than once or twice, you'd better writing a type guard as #Daryl suggests.
interface TypeA {
a: string
}
interface TypeB {
b: string
}
const testFunction = (x: TypeA | TypeB): string => {
return (x as TypeA).a || (x as TypeB).b;
}
testFunction({ a: 'Hello' }); // 'Hello'
testFunction({ b: 'World' }); // 'World'
Intellij accepts this syntax:
function getItemName(item: TypeA): string;
function getItemName(item: TypeB): string;
function getItemName(item): string {
return item.hasOwnProperty('itemName') ? item.itemName : item.itemTitle;
}
the official way according to the typescript docs is this:
https://www.typescriptlang.org/docs/handbook/functions.html
I won't complicate things. If you're really sure that your object has either the one or the other property, a name = item['itemName'] || item['itemTitle'] or name = item.hasOwnProperty('itemName') ? item['itemName'] : item['itemTitle'] would be sufficient.
Note that TypeScript usually stops complaining if you access properties using the bracket notation instead of the dot notation. I would suggest adding a comment, though.
Use typeguards:
interface TypeA {
itemName: string;
}
interface TypeB {
itemTitle: string;
}
function isTypeA(val: any): val is TypeA
{
return val.hasOwnProperty('itemName');
}
function isTypeB(val: any): val is TypeB
{
return val.hasOwnProperty('itemTitle');
}
function getItemName(item: TypeA | TypeB): string
{
let name = '';
if (isTypeA(item))
{
name = item.itemName;
}
else
{
name = item.itemTitle;
}
return name;
}

sweet.js: transforming occurrences of a repeated token

I want to define a sweet macro that transforms
{ a, b } # o
into
{ o.a, o.b }
My current attempt is
macro (#) {
case infix { { $prop:ident (,) ... } | _ $o } => {
return #{ { $prop: $o.$prop (,) ... } }
}
}
However, this give me
SyntaxError: [patterns] Ellipses level does not match in the template
I suspect I don't really understand how ... works, and may need to somehow loop over the values of $prop and build syntax objects for each and somehow concatenate them, but I'm at a loss as to how to do that.
The problem is the syntax expander thinks you're trying to expand $o.$prop instead of $prop: $o.$prop. Here's the solution:
macro (#) {
rule infix { { $prop:ident (,) ... } | $o:ident } => {
{ $($prop: $o.$prop) (,) ... }
}
}
Notice that I placed the unit of code in a $() block of its own to disambiguate the ellipse expansion.
Example: var x = { a, b } # o; becomes var x = { a: o.a, b: o.b };.

Convert sweet.js argument into string

How would you create a string from an argument to a sweet.js macro? For example:
let foo = macro {
rule {
$name
} => {
console.log('$name', $name);
}
}
var x = 42;
foo x
Will output:
console.log(x, x);
When I'd prefer it to output:
console.log('x', x);
So the first argument has quotes around it.
You can use a case macro:
let foo = macro {
case {_
$name
} => {
letstx $name_str = [makeValue(unwrapSyntax(#{$name}), #{here})];
return #{
console.log($name_str, $name);
}
}
}
var x = 42;
foo x
The basic idea is that you make a new string token (via makeValue) using the string value of the identifiers mached by $name (unwrapSyntax gives us the value of the given syntax objects, in the case of identifiers it is the identifier string). Then letstx allows us to bind our newly created syntax object for use inside the #{} template.