Skip to content

Commit

Permalink
feat: Allow macros to refer to symbols in scope at the expansion site
Browse files Browse the repository at this point in the history
  • Loading branch information
Marwes committed Dec 14, 2020
1 parent 8f43cb6 commit 1a5489c
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 16 deletions.
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

0 comments on commit 1a5489c

Please sign in to comment.