Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using variables from surrounding scope in macro expansion #895

Closed
bch29 opened this issue Dec 14, 2020 · 6 comments · Fixed by #896
Closed

Using variables from surrounding scope in macro expansion #895

bch29 opened this issue Dec 14, 2020 · 6 comments · Fixed by #896

Comments

@bch29
Copy link

bch29 commented Dec 14, 2020

I am trying to write a format! macro as a type implementing the Macro trait. I would like to be able to invoke it like this

let x = 1
let y = 2
format! "x'={1+x}, y={y}"

where the above would expand to

let x = 1
let y = 2
"x'=" ++ show (1 + x) ++ ", y=" ++ show y

I have written the code to produce this expansion, but when I try to use it I get errors telling me that (++), show, x and y are undefined. I have tried using let symbols = Symbols::new(); and

let mut compiler_db = env.vm.get_database();
let mut compiler = env.vm.module_compiler(&mut compiler_db);
let symbols = compiler.mut_symbols();

for symbol lookup (passed to parse_expr to parse subexpressions, and for getting the show and (++) identifiers).

I could make this work by having the user pass symbols in like this

let fmt = { show, (++) }
let x = 1
let y = 2
format! fmt "x'={x'}, y={y}" {x' = 1+x, y}

where the last line would expand to something like

let args = {x' = 1 + x, y}
in "x'=" ++ fmt.show args.'x ++ ", y=" ++ fmt.show args.y

but I believe this is less pleasant to use. Is it possible to achieve my desired syntax with a macro?

@Marwes
Copy link
Member

Marwes commented Dec 14, 2020

I think if you create the symbols on the Symbols map passed in to expand after #896 it should work as you expect.

@bch29
Copy link
Author

bch29 commented Dec 14, 2020

Thanks for the fast response to this! I have tried that branch and still can't quite get it to work. Passing that symbols map to parse_expr lets it pick up locals from subexpressions correctly, but I am still getting errors on show and (++). Am I doing something wrong by creating a show expression like this?

ast::Expr::Ident(ast::TypedIdent::new(symbols.from_str("show")))

@bch29
Copy link
Author

bch29 commented Dec 14, 2020

I have opened a PR including my format! implementation at #897 since you have an open issue to add such a macro. This implementation exhibits the issue where show and (++) cannot be found.

@Marwes
Copy link
Member

Marwes commented Dec 14, 2020

I don't think you should rely on show and ++ to be in scope for the macro. Instead expand it to be let { show } = import! std.show in let { (++) } = import! std.string in ...

bors bot added a commit that referenced this issue Dec 15, 2020
896: feat: Allow macros to refer to symbols in scope at the expansion site r=Marwes a=Marwes

Fixes #895

Co-authored-by: Markus Westerlind <[email protected]>
@bch29
Copy link
Author

bch29 commented Dec 15, 2020

I wasn't sure if it was possible to put macro invocations in the AST, so I have had it look up the import macro in the MacroEnv then expanded it. This works nicely.

@bch29 bch29 closed this as completed Dec 15, 2020
@Marwes
Copy link
Member

Marwes commented Dec 15, 2020

Ah, right. The expansion should work iteratively on the output of an expansion as well.

Marwes added a commit to Marwes/gluon that referenced this issue Oct 3, 2021
<a name="v0.18.0"></a>
## v0.18.0 (2021-10-03)

#### Bug Fixes

*   Don't use the empty span in derive macros ([d05f1ca](gluon-lang@d05f1ca))
*   Provide the type of imported modules with errors ([d3bfc59](gluon-lang@d3bfc59))
*   Don't refine already refined skolems ([f39b396](gluon-lang@f39b396), closes [gluon-lang#842](gluon-lang#842))
*   Recognize raw string literals without any `#` ([4d66fbb](gluon-lang@4d66fbb), closes [gluon-lang#885](gluon-lang#885))
*   Prevent zero-argument functions from being created in Rust ([e91ea06](gluon-lang@e91ea06), closes [gluon-lang#873](gluon-lang#873))
*   Give tuple fields a span ([2a1c2c7](gluon-lang@2a1c2c7))
*   xor_shift_new inconsistent description ([591b64b](gluon-lang@591b64b))

#### Performance

*   Avoid recreating the vm for each formatted file ([0335733](gluon-lang@0335733))

#### Features

*   Make channels and reference require IO ([c904189](gluon-lang@c904189), breaks [#](https://github.com/gluon-lang/gluon/issues/))
*   Allow specifying type signatures in do bindings ([fac08dc](gluon-lang@fac08dc))
*   Allow macros to refer to symbols in scope at the expansion site ([1a5489c](gluon-lang@1a5489c), closes [gluon-lang#895](gluon-lang#895))
*   Allow the http module to be used without a tcp listener ([c45353d](gluon-lang@c45353d))
*   Format seq expressions without seq ([5c0cec2](gluon-lang@5c0cec2))
*   Compile block expressions as monadic sequences ([bce5973](gluon-lang@bce5973), closes [gluon-lang#884](gluon-lang#884))
* **std:**
  *  add Option assertions to std.test ([28e5053](gluon-lang@28e5053))
  *  add modulo functions to int and float ([92f188a](gluon-lang@92f188a))

#### Breaking Changes

*   Make channels and reference require IO ([c904189](gluon-lang@c904189), breaks [#](https://github.com/gluon-lang/gluon/issues/))
Marwes added a commit to Marwes/gluon that referenced this issue Oct 3, 2021
<a name="v0.18.0"></a>
## v0.18.0 (2021-10-03)

#### Performance

*   Avoid recreating the vm for each formatted file ([0335733](gluon-lang@0335733))

#### Breaking Changes

*   Make channels and reference require IO ([c904189](gluon-lang@c904189), breaks [#](https://github.com/gluon-lang/gluon/issues/))

#### Features

*   Make channels and reference require IO ([c904189](gluon-lang@c904189), breaks [#](https://github.com/gluon-lang/gluon/issues/))
*   Allow specifying type signatures in do bindings ([fac08dc](gluon-lang@fac08dc))
*   Allow macros to refer to symbols in scope at the expansion site ([1a5489c](gluon-lang@1a5489c), closes [gluon-lang#895](gluon-lang#895))
*   Allow the http module to be used without a tcp listener ([c45353d](gluon-lang@c45353d))
*   Format seq expressions without seq ([5c0cec2](gluon-lang@5c0cec2))
*   Compile block expressions as monadic sequences ([bce5973](gluon-lang@bce5973), closes [gluon-lang#884](gluon-lang#884))
* **std:**
  *  add Option assertions to std.test ([28e5053](gluon-lang@28e5053))
  *  add modulo functions to int and float ([92f188a](gluon-lang@92f188a))

#### Bug Fixes

*   Allow the repl to compile concurrently ([2118f4d](gluon-lang@2118f4d))
*   Don't use the empty span in derive macros ([d05f1ca](gluon-lang@d05f1ca))
*   Provide the type of imported modules with errors ([d3bfc59](gluon-lang@d3bfc59))
*   Don't refine already refined skolems ([f39b396](gluon-lang@f39b396), closes [gluon-lang#842](gluon-lang#842))
*   Recognize raw string literals without any `#` ([4d66fbb](gluon-lang@4d66fbb), closes [gluon-lang#885](gluon-lang#885))
*   Prevent zero-argument functions from being created in Rust ([e91ea06](gluon-lang@e91ea06), closes [gluon-lang#873](gluon-lang#873))
*   Give tuple fields a span ([2a1c2c7](gluon-lang@2a1c2c7))
*   xor_shift_new inconsistent description ([591b64b](gluon-lang@591b64b))
bors bot added a commit that referenced this issue Oct 3, 2021
915: Version 0.18.0 r=Marwes a=Marwes

<a name="v0.18.0"></a>
## v0.18.0 (2021-10-03)

#### Performance

*   Avoid recreating the vm for each formatted file ([0335733](0335733))

#### Breaking Changes

*   Make channels and reference require IO ([c904189](c904189), breaks [#](https://github.com/gluon-lang/gluon/issues/))

#### Features

*   Make channels and reference require IO ([c904189](c904189), breaks [#](https://github.com/gluon-lang/gluon/issues/))
*   Allow specifying type signatures in do bindings ([fac08dc](fac08dc))
*   Allow macros to refer to symbols in scope at the expansion site ([1a5489c](1a5489c), closes [#895](#895))
*   Allow the http module to be used without a tcp listener ([c45353d](c45353d))
*   Format seq expressions without seq ([5c0cec2](5c0cec2))
*   Compile block expressions as monadic sequences ([bce5973](bce5973), closes [#884](#884))
* **std:**
  *  add Option assertions to std.test ([28e5053](28e5053))
  *  add modulo functions to int and float ([92f188a](92f188a))

#### Bug Fixes

*   Allow the repl to compile concurrently ([2118f4d](2118f4d))
*   Don't use the empty span in derive macros ([d05f1ca](d05f1ca))
*   Provide the type of imported modules with errors ([d3bfc59](d3bfc59))
*   Don't refine already refined skolems ([f39b396](f39b396), closes [#842](#842))
*   Recognize raw string literals without any `#` ([4d66fbb](4d66fbb), closes [#885](#885))
*   Prevent zero-argument functions from being created in Rust ([e91ea06](e91ea06), closes [#873](#873))
*   Give tuple fields a span ([2a1c2c7](2a1c2c7))
*   xor_shift_new inconsistent description ([591b64b](591b64b))

Co-authored-by: Markus Westerlind <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants