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

feat: Allow macros to refer to symbols in scope at the expansion site #896

Merged
merged 1 commit into from
Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,17 @@ factorial 10
// * Only the following operators/functions are allowed: multiplication, division, addition, subtraction
// * Division should use floating point or rational arithmetic, etc, to preserve remainders.
// * Brackets are allowed, if using an infix expression evaluator.
// * Forming multiple digit numbers from the supplied digits is disallowed. (So an answer of 12+12 - when given 1, 2, 2, and 1 - is wrong).
// * The order of the digits, when given, does not have to be preserved.
// * Forming multiple digit numbers from the supplied digits is disallowed. (So an answer of 12+12 when given 1, 2, 2, and 1 is wrong).
// * The order of the digits when given does not have to be preserved.
//
//
// ## Notes
//
// The type of expression evaluator used is not mandated. An RPN evaluator is equally acceptable for example.
// The task is not for the program to generate the expression or test whether an expression is even possible.
// The task is not for the program to generate the expression, or test whether an expression is even possible.


// The `import!` macro is used to load and refer to other modules.
// The `import!` macro are used to load and refer to other modules.
// It gets replaced by the value returned by evaluating that module (cached of course, so that
// multiple `import!`s to the same module only evaluates the module once)
let io @ { ? } = import! std.io
Expand All @@ -83,7 +83,7 @@ let list @ { List, ? } = import! std.list
let random = import! std.random
let string = import! std.string

// Since imports in gluon return regular values we can load specific parts of a module using pattern matches.
// Since imports in gluon returns regular values we can load specific parts of a module using pattern matches.
let char @ { ? } = import! std.char

let { (<>) } = import! std.semigroup
Expand Down
5 changes: 3 additions & 2 deletions src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::base::{
ast::{self, expr_to_path, Expr, Literal, SpannedExpr},
filename_to_module, pos,
source::FileId,
symbol::Symbol,
symbol::{Symbol, Symbols},
types::ArcType,
};

Expand Down Expand Up @@ -477,9 +477,10 @@ where
}
}

fn expand<'r, 'a: 'r, 'b: 'r, 'ast: 'r>(
fn expand<'r, 'a: 'r, 'b: 'r, 'c: 'r, 'ast: 'r>(
&self,
macros: &'b mut MacroExpander<'a>,
_symbols: &'c mut Symbols,
_arena: &'b mut ast::OwnedArena<'ast, Symbol>,
args: &'b mut [SpannedExpr<'ast, Symbol>],
) -> MacroFuture<'r, 'ast> {
Expand Down
3 changes: 2 additions & 1 deletion src/lift_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ use {
pub(crate) struct LiftIo;

impl Macro for LiftIo {
fn expand<'r, 'a: 'r, 'b: 'r, 'ast: 'r>(
fn expand<'r, 'a: 'r, 'b: 'r, 'c: 'r, 'ast: 'r>(
&self,
env: &'b mut MacroExpander<'a>,
_symbols: &'c mut Symbols,
arena: &'b mut ast::OwnedArena<'ast, Symbol>,
args: &'b mut [SpannedExpr<'ast, Symbol>],
) -> MacroFuture<'r, 'ast> {
Expand Down
23 changes: 15 additions & 8 deletions vm/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,13 @@ pub trait Macro: Trace + DowncastArc + Send + Sync {
None
}

fn expand<'r, 'a: 'r, 'b: 'r, 'ast: 'r>(
/// Creating a symbol in `symbols` will put it in the same scope as the code surrounding the
/// expansion. If you want to create a unique symbol then call `Symbol::from` or create a new
/// `Symbols` table
fn expand<'r, 'a: 'r, 'b: 'r, 'c: 'r, 'ast: 'r>(
&self,
env: &'b mut MacroExpander<'a>,
symbols: &'c mut Symbols,
arena: &'b mut ast::OwnedArena<'ast, Symbol>,
args: &'b mut [SpannedExpr<'ast, Symbol>],
) -> MacroFuture<'r, 'ast>;
Expand Down Expand Up @@ -283,13 +287,14 @@ where
(**self).get_capability_impl(thread, arc_self, id)
}

fn expand<'r, 'a: 'r, 'b: 'r, 'ast: 'r>(
fn expand<'r, 'a: 'r, 'b: 'r, 'c: 'r, 'ast: 'r>(
&self,
env: &'b mut MacroExpander<'a>,
symbols: &'c mut Symbols,
arena: &'b mut ast::OwnedArena<'ast, Symbol>,
args: &'b mut [SpannedExpr<'ast, Symbol>],
) -> MacroFuture<'r, 'ast> {
(**self).expand(env, arena, args)
(**self).expand(env, symbols, arena, args)
}
}

Expand All @@ -307,13 +312,14 @@ where
(**self).get_capability_impl(thread, arc_self, id)
}

fn expand<'r, 'a: 'r, 'b: 'r, 'ast: 'r>(
fn expand<'r, 'a: 'r, 'b: 'r, 'c: 'r, 'ast: 'r>(
&self,
env: &'b mut MacroExpander<'a>,
symbols: &'c mut Symbols,
arena: &'b mut ast::OwnedArena<'ast, Symbol>,
args: &'b mut [SpannedExpr<'ast, Symbol>],
) -> MacroFuture<'r, 'ast> {
(**self).expand(env, arena, args)
(**self).expand(env, symbols, arena, args)
}
}

Expand Down Expand Up @@ -457,19 +463,20 @@ impl<'a> MacroExpander<'a> {
exprs: Vec::new(),
};
visitor.visit_expr(expr);
let MacroVisitor { exprs, .. } = visitor;
self.expand(arena, exprs).await
let MacroVisitor { exprs, symbols, .. } = visitor;
self.expand(symbols, arena, exprs).await
}

async fn expand<'ast>(
&mut self,
symbols: &mut Symbols,
arena: &mut ast::OwnedArena<'ast, Symbol>,
mut exprs: Vec<(&'_ mut SpannedExpr<'ast, Symbol>, Arc<dyn Macro>)>,
) {
let mut futures = Vec::with_capacity(exprs.len());
for (expr, mac) in exprs.drain(..) {
let result = match &mut expr.value {
Expr::App { args, .. } => mac.expand(self, arena, args).await,
Expr::App { args, .. } => mac.expand(self, symbols, arena, args).await,
_ => unreachable!("{:?}", expr),
};
match result {
Expand Down