Skip to content

Commit

Permalink
Merge pull request #921 from hash-org/parse-macs
Browse files Browse the repository at this point in the history
parser: support parsing new AST macro syntax, and temporarily remove directive handling code
  • Loading branch information
feds01 authored Aug 23, 2023
2 parents 7d4ca02 + ea996aa commit ec58306
Show file tree
Hide file tree
Showing 45 changed files with 1,385 additions and 901 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions compiler/hash-ast-desugaring/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ hash-pipeline = { path = "../hash-pipeline" }
hash-reporting = { path = "../hash-reporting" }
hash-source = { path = "../hash-source" }
hash-tree-def = { path = "../hash-tree-def" }
hash-utils = { path = "../hash-utils" }
331 changes: 185 additions & 146 deletions compiler/hash-ast-desugaring/src/desugaring.rs

Large diffs are not rendered by default.

187 changes: 118 additions & 69 deletions compiler/hash-ast-expand/src/visitor.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
//! This defines the Hash AST expansion pass. This pass is responsible for
//! dealing with all macro invocations, and performing various transformations
//! on the AST based on the kind of macro that was invoked. Specifically, this
//! pass will:
//!
//! - Deal with all `#[attr(...)]` invocations which set attributes on their
//! subjects. The attributes are registered in the `ATTRIBUTE_MAP` which can
//! then be later accessed by various other passes which need to know about
//! the attributes. Dealing with attributes also means that the pass will
//! check that all applied attributes exist (if not a warning is emitted) and
//! that they are applied to the correct kind of AST item. However, this pass
//! is not responsible for checking that a specific kind of attribute has a
//! sane or valid value, this is up to the pass that is responsible or cares
//! about the attribute to check.
//!
//! - @@Future: Perform expansions on macro invocations. Depending on whether
//! this is an AST level macro or a token level macro, the expansion will be
//! different.
#![allow(unused)]

use std::convert::Infallible;

use hash_ast::{
ast::{AstNode, Name},
ast_visitor_mut_self_default_impl,
ast, ast_visitor_mut_self_default_impl,
tree::AstTreeGenerator,
visitor::{walk_mut_self, AstVisitor, AstVisitorMutSelf},
};
Expand Down Expand Up @@ -44,76 +63,106 @@ impl<'s> AstExpander<'s> {
impl<'s> AstVisitorMutSelf for AstExpander<'s> {
type Error = Infallible;

ast_visitor_mut_self_default_impl!(hiding: DirectiveExpr);
ast_visitor_mut_self_default_impl!(hiding: ExprMacroInvocation, TyMacroInvocation, PatMacroInvocation);

type ExprMacroInvocationRet = ();

fn visit_expr_macro_invocation(
&mut self,
_node: ast::AstNodeRef<ast::ExprMacroInvocation>,
) -> Result<Self::ExprMacroInvocationRet, Self::Error> {
Ok(())
}

type TyMacroInvocationRet = ();

type DirectiveExprRet = ();
fn visit_directive_expr(
fn visit_ty_macro_invocation(
&mut self,
node: hash_ast::ast::AstNodeRef<hash_ast::ast::DirectiveExpr>,
) -> Result<Self::DirectiveExprRet, Self::Error> {
let _ = walk_mut_self::walk_directive_expr(self, node);

let mut write_tree = |index| {
let ast_settings = self.settings.ast_settings();

// We want to get the total span of the subject, so we must
// include the span of the directives that come after the `dump_ast` directive.
let directive_span = if let Some(directive) = node.directives.get(index + 1) {
let directive: &AstNode<Name> = directive; // @@RustBug: for some reason it can't infer the type here, maybe `smallvec`
// related?
directive.span().join(node.subject.span())
} else {
node.subject.span()
};

stream_writeln!(
self.stdout,
"AST dump for {}",
self.source_map.fmt_location(directive_span)
);

match ast_settings.dump_mode {
AstDumpMode::Pretty => {
let mut printer = AstPrinter::new(&mut self.stdout);
printer.visit_expr(node.subject.ast_ref()).unwrap();

// @@Hack: terminate the line with a newline.
stream_writeln!(self.stdout, "");
}
AstDumpMode::Tree => {
let mut tree = AstTreeGenerator.visit_expr(node.subject.ast_ref()).unwrap();

// Since this might be a non-singular directive, we also might
// need to wrap the tree in a any of the directives that were specified
// after the `dump_ast` directive.
for directive in node.directives.iter().skip(index + 1).rev() {
tree = TreeNode::branch(
format!("directive \"{}\"", directive.ident),
vec![tree],
);
}

stream_writeln!(
self.stdout,
"{}",
TreeWriter::new_with_config(
&tree,
TreeWriterConfig::from_character_set(self.settings.character_set)
)
);
}
}
};

// for the `dump_ast` directive, we essentially "dump" the generated tree
// that the parser created. We emit this tree regardless of whether or not
// there will be errors later on in the compilation stage.
for (index, directive) in node.directives.iter().enumerate() {
if directive.is(IDENTS.dump_ast) {
write_tree(index)
}
}
_node: ast::AstNodeRef<ast::TyMacroInvocation>,
) -> Result<Self::TyMacroInvocationRet, Self::Error> {
Ok(())
}

type PatMacroInvocationRet = ();

fn visit_pat_macro_invocation(
&mut self,
_node: ast::AstNodeRef<ast::PatMacroInvocation>,
) -> Result<Self::PatMacroInvocationRet, Self::Error> {
Ok(())
}

// type DirectiveExprRet = ();
// fn visit_directive_expr(
// &mut self,
// node: hash_ast::ast::AstNodeRef<hash_ast::ast::DirectiveExpr>,
// ) -> Result<Self::DirectiveExprRet, Self::Error> { let _ =
// walk_mut_self::walk_directive_expr(self, node);

// let mut write_tree = |index| {
// let ast_settings = self.settings.ast_settings();

// // We want to get the total span of the subject, so we must
// // include the span of the directives that come after the `dump_ast`
// directive. let directive_span = if let Some(directive) =
// node.directives.get(index + 1) { let directive:
// &AstNode<Name> = directive; // @@RustBug: for some reason it can't infer the
// type here, maybe `smallvec`
// // related? directive.span().join(node.subject.span())
// } else {
// node.subject.span()
// };

// stream_writeln!(
// self.stdout,
// "AST dump for {}",
// self.source_map.fmt_location(directive_span)
// );

// match ast_settings.dump_mode {
// AstDumpMode::Pretty => {
// let mut printer = AstPrinter::new(&mut self.stdout);
// printer.visit_expr(node.subject.ast_ref()).unwrap();

// // @@Hack: terminate the line with a newline.
// stream_writeln!(self.stdout, "");
// }
// AstDumpMode::Tree => {
// let mut tree =
// AstTreeGenerator.visit_expr(node.subject.ast_ref()).unwrap();

// // Since this might be a non-singular directive, we also
// might // need to wrap the tree in a any of the directives
// that were specified // after the `dump_ast` directive.
// for directive in node.directives.iter().skip(index + 1).rev()
// { tree = TreeNode::branch(
// format!("directive \"{}\"", directive.ident),
// vec![tree],
// );
// }

// stream_writeln!(
// self.stdout,
// "{}",
// TreeWriter::new_with_config(
// &tree,
//
// TreeWriterConfig::from_character_set(self.settings.character_set)
// )
// );
// }
// }
// };

// // for the `dump_ast` directive, we essentially "dump" the generated tree
// // that the parser created. We emit this tree regardless of whether or
// not // there will be errors later on in the compilation stage.
// for (index, directive) in node.directives.iter().enumerate() {
// if directive.is(IDENTS.dump_ast) {
// write_tree(index)
// }
// }

// Ok(())
// }
}
Loading

0 comments on commit ec58306

Please sign in to comment.