Generate AST
This commit is contained in:
parent
36bd28633b
commit
d8b2a5efc0
@ -3,7 +3,7 @@ extern crate libsyntax2;
|
||||
mod extend_selection;
|
||||
|
||||
use libsyntax2::{
|
||||
SyntaxNodeRef,
|
||||
SyntaxNodeRef, AstNode,
|
||||
algo::walk,
|
||||
SyntaxKind::*,
|
||||
};
|
||||
|
54
src/ast/generated.rs
Normal file
54
src/ast/generated.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use std::sync::Arc;
|
||||
use {
|
||||
SyntaxNode, SyntaxRoot, TreeRoot, AstNode,
|
||||
SyntaxKind::*,
|
||||
};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct File<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||
syntax: SyntaxNode<R>,
|
||||
}
|
||||
|
||||
impl<R: TreeRoot> AstNode<R> for File<R> {
|
||||
fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
|
||||
match syntax.kind() {
|
||||
FILE => Some(File { syntax }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnItem<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||
syntax: SyntaxNode<R>,
|
||||
}
|
||||
|
||||
impl<R: TreeRoot> AstNode<R> for FnItem<R> {
|
||||
fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
|
||||
match syntax.kind() {
|
||||
FN_ITEM => Some(FnItem { syntax }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Name<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||
syntax: SyntaxNode<R>,
|
||||
}
|
||||
|
||||
impl<R: TreeRoot> AstNode<R> for Name<R> {
|
||||
fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
|
||||
match syntax.kind() {
|
||||
NAME => Some(Name { syntax }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
|
||||
}
|
||||
|
22
src/ast/generated.rs.tera
Normal file
22
src/ast/generated.rs.tera
Normal file
@ -0,0 +1,22 @@
|
||||
use std::sync::Arc;
|
||||
use {
|
||||
SyntaxNode, SyntaxRoot, TreeRoot, AstNode,
|
||||
SyntaxKind::*,
|
||||
};
|
||||
{% for node in ast %}
|
||||
{% set Name = node.kind | camel %}
|
||||
#[derive(Debug)]
|
||||
pub struct {{ Name }}<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||
syntax: SyntaxNode<R>,
|
||||
}
|
||||
|
||||
impl<R: TreeRoot> AstNode<R> for {{ Name }}<R> {
|
||||
fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
|
||||
match syntax.kind() {
|
||||
{{ node.kind }} => Some({{ Name }} { syntax }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
|
||||
}
|
||||
{% endfor %}
|
@ -1,57 +1,41 @@
|
||||
mod generated;
|
||||
|
||||
use std::sync::Arc;
|
||||
use {
|
||||
SyntaxNode, SyntaxRoot, TreeRoot,
|
||||
SyntaxKind::*,
|
||||
};
|
||||
pub use self::generated::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct File<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||
syntax: SyntaxNode<R>,
|
||||
pub trait AstNode<R: TreeRoot>: Sized {
|
||||
fn cast(syntax: SyntaxNode<R>) -> Option<Self>;
|
||||
fn syntax(&self) -> &SyntaxNode<R>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Function<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||
syntax: SyntaxNode<R>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Name<R: TreeRoot = Arc<SyntaxRoot>> {
|
||||
syntax: SyntaxNode<R>,
|
||||
}
|
||||
|
||||
|
||||
impl File<Arc<SyntaxRoot>> {
|
||||
pub fn parse(text: &str) -> Self {
|
||||
File {
|
||||
syntax: ::parse(text),
|
||||
}
|
||||
File::cast(::parse(text)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: TreeRoot> File<R> {
|
||||
pub fn functions<'a>(&'a self) -> impl Iterator<Item = Function<R>> + 'a {
|
||||
self.syntax
|
||||
pub fn functions<'a>(&'a self) -> impl Iterator<Item = FnItem<R>> + 'a {
|
||||
self.syntax()
|
||||
.children()
|
||||
.filter(|node| node.kind() == FN_ITEM)
|
||||
.map(|node| Function { syntax: node })
|
||||
.filter_map(FnItem::cast)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: TreeRoot> Function<R> {
|
||||
pub fn syntax(&self) -> SyntaxNode<R> {
|
||||
self.syntax.clone()
|
||||
}
|
||||
|
||||
impl<R: TreeRoot> FnItem<R> {
|
||||
pub fn name(&self) -> Option<Name<R>> {
|
||||
self.syntax
|
||||
self.syntax()
|
||||
.children()
|
||||
.filter(|node| node.kind() == NAME)
|
||||
.map(|node| Name { syntax: node })
|
||||
.filter_map(Name::cast)
|
||||
.next()
|
||||
}
|
||||
|
||||
pub fn has_atom_attr(&self, atom: &str) -> bool {
|
||||
self.syntax
|
||||
self.syntax()
|
||||
.children()
|
||||
.filter(|node| node.kind() == ATTR)
|
||||
.any(|attr| {
|
||||
@ -81,14 +65,6 @@ impl<R: TreeRoot> Function<R> {
|
||||
|
||||
impl<R: TreeRoot> Name<R> {
|
||||
pub fn text(&self) -> String {
|
||||
self.syntax.text()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl<R: TreeRoot> File<R> {
|
||||
pub fn syntax(&self) -> SyntaxNode<R> {
|
||||
self.syntax.clone()
|
||||
self.syntax().text()
|
||||
}
|
||||
}
|
@ -212,5 +212,16 @@ Grammar(
|
||||
"PARAM",
|
||||
"SELF_PARAM",
|
||||
"ARG_LIST",
|
||||
],
|
||||
ast: [
|
||||
(
|
||||
kind: "FILE"
|
||||
),
|
||||
(
|
||||
kind: "FN_ITEM"
|
||||
),
|
||||
(
|
||||
kind: "NAME"
|
||||
),
|
||||
]
|
||||
)
|
||||
|
@ -41,7 +41,7 @@ mod yellow;
|
||||
pub mod utils;
|
||||
|
||||
pub use {
|
||||
ast::File,
|
||||
ast::{AstNode, File},
|
||||
lexer::{tokenize, Token},
|
||||
syntax_kinds::SyntaxKind,
|
||||
text_unit::{TextRange, TextUnit},
|
||||
|
@ -23,6 +23,8 @@ const INLINE_TESTS_DIR: &str = "tests/data/parser/inline";
|
||||
const GRAMMAR: &str = "./src/grammar.ron";
|
||||
const SYNTAX_KINDS: &str = "./src/syntax_kinds/generated.rs";
|
||||
const SYNTAX_KINDS_TEMPLATE: &str = "./src/syntax_kinds/generated.rs.tera";
|
||||
const AST: &str = "./src/ast/generated.rs";
|
||||
const AST_TEMPLATE: &str = "./src/ast/generated.rs.tera";
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let matches = App::new("tasks")
|
||||
@ -47,10 +49,16 @@ fn main() -> Result<()> {
|
||||
|
||||
fn run_gen_command(name: &str, verify: bool) -> Result<()> {
|
||||
match name {
|
||||
"gen-kinds" => update(Path::new(SYNTAX_KINDS), &get_kinds()?, verify),
|
||||
"gen-tests" => gen_tests(verify),
|
||||
"gen-kinds" => {
|
||||
update(Path::new(SYNTAX_KINDS), &render_template(SYNTAX_KINDS_TEMPLATE)?, verify)?;
|
||||
update(Path::new(AST), &render_template(AST_TEMPLATE)?, verify)?;
|
||||
},
|
||||
"gen-tests" => {
|
||||
gen_tests(verify)?
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update(path: &Path, contents: &str, verify: bool) -> Result<()> {
|
||||
@ -68,13 +76,30 @@ fn update(path: &Path, contents: &str, verify: bool) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_kinds() -> Result<String> {
|
||||
let grammar = grammar()?;
|
||||
let template = fs::read_to_string(SYNTAX_KINDS_TEMPLATE)?;
|
||||
fn render_template(template: &str) -> Result<String> {
|
||||
let grammar: ron::value::Value = {
|
||||
let text = fs::read_to_string(GRAMMAR)?;
|
||||
ron::de::from_str(&text)?
|
||||
};
|
||||
let template = fs::read_to_string(template)?;
|
||||
let mut tera = tera::Tera::default();
|
||||
tera.add_raw_template("grammar", &template)
|
||||
.map_err(|e| format_err!("template error: {:?}", e))?;
|
||||
tera.register_global_function("concat", Box::new(concat));
|
||||
tera.register_filter("camel", |arg, _| {
|
||||
Ok(arg.as_str().unwrap()
|
||||
.split("_")
|
||||
.flat_map(|word| {
|
||||
word.chars()
|
||||
.next().unwrap()
|
||||
.to_uppercase()
|
||||
.chain(
|
||||
word.chars().skip(1).flat_map(|c| c.to_lowercase())
|
||||
)
|
||||
})
|
||||
.collect::<String>()
|
||||
.into())
|
||||
});
|
||||
let ret = tera
|
||||
.render("grammar", &grammar)
|
||||
.map_err(|e| format_err!("template error: {:?}", e))?;
|
||||
@ -94,12 +119,6 @@ fn get_kinds() -> Result<String> {
|
||||
}
|
||||
}
|
||||
|
||||
fn grammar() -> Result<ron::value::Value> {
|
||||
let text = fs::read_to_string(GRAMMAR)?;
|
||||
let ret = ron::de::from_str(&text)?;
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn gen_tests(verify: bool) -> Result<()> {
|
||||
let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user