mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Rust: write generated schema into schema/ast.py
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
use std::io::Write;
|
||||||
use std::{fs, path::PathBuf};
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
pub mod codegen;
|
pub mod codegen;
|
||||||
@@ -47,7 +48,13 @@ fn to_lower_snake_case(s: &str) -> String {
|
|||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_schema(grammar: &AstSrc, super_types: BTreeMap<String, BTreeSet<String>>) {
|
fn write_schema(
|
||||||
|
grammar: &AstSrc,
|
||||||
|
super_types: BTreeMap<String, BTreeSet<String>>,
|
||||||
|
) -> std::io::Result<String> {
|
||||||
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
|
writeln!(buf, "from .prelude import *\n")?;
|
||||||
|
|
||||||
for node in &grammar.enums {
|
for node in &grammar.enums {
|
||||||
let super_classses = if let Some(cls) = super_types.get(&node.name) {
|
let super_classses = if let Some(cls) = super_types.get(&node.name) {
|
||||||
let super_classes: Vec<String> = cls.iter().map(|x| class_name(x)).collect();
|
let super_classes: Vec<String> = cls.iter().map(|x| class_name(x)).collect();
|
||||||
@@ -55,9 +62,9 @@ fn print_schema(grammar: &AstSrc, super_types: BTreeMap<String, BTreeSet<String>
|
|||||||
} else {
|
} else {
|
||||||
"AstNode".to_owned()
|
"AstNode".to_owned()
|
||||||
};
|
};
|
||||||
println!("class {}({}):", class_name(&node.name), super_classses);
|
writeln!(buf, "class {}({}):", class_name(&node.name), super_classses)?;
|
||||||
println!(" pass");
|
writeln!(buf, " pass")?;
|
||||||
println!("");
|
writeln!(buf, "")?;
|
||||||
}
|
}
|
||||||
for node in &grammar.nodes {
|
for node in &grammar.nodes {
|
||||||
let super_classses = if let Some(cls) = super_types.get(&node.name) {
|
let super_classses = if let Some(cls) = super_types.get(&node.name) {
|
||||||
@@ -66,7 +73,7 @@ fn print_schema(grammar: &AstSrc, super_types: BTreeMap<String, BTreeSet<String>
|
|||||||
} else {
|
} else {
|
||||||
"AstNode".to_owned()
|
"AstNode".to_owned()
|
||||||
};
|
};
|
||||||
println!("class {}({}):", class_name(&node.name), super_classses);
|
writeln!(buf, "class {}({}):", class_name(&node.name), super_classses)?;
|
||||||
let mut empty = true;
|
let mut empty = true;
|
||||||
for field in get_fields(node) {
|
for field in get_fields(node) {
|
||||||
if field.tp == "SyntaxToken" {
|
if field.tp == "SyntaxToken" {
|
||||||
@@ -75,10 +82,11 @@ fn print_schema(grammar: &AstSrc, super_types: BTreeMap<String, BTreeSet<String>
|
|||||||
|
|
||||||
empty = false;
|
empty = false;
|
||||||
if field.tp == "string" {
|
if field.tp == "string" {
|
||||||
println!(
|
writeln!(
|
||||||
|
buf,
|
||||||
" {}: optional[string]",
|
" {}: optional[string]",
|
||||||
property_name(&node.name, &field.name),
|
property_name(&node.name, &field.name),
|
||||||
);
|
)?;
|
||||||
} else {
|
} else {
|
||||||
let list = field.is_many;
|
let list = field.is_many;
|
||||||
let (o, c) = if list {
|
let (o, c) = if list {
|
||||||
@@ -86,20 +94,22 @@ fn print_schema(grammar: &AstSrc, super_types: BTreeMap<String, BTreeSet<String>
|
|||||||
} else {
|
} else {
|
||||||
("optional[", "]")
|
("optional[", "]")
|
||||||
};
|
};
|
||||||
println!(
|
writeln!(
|
||||||
|
buf,
|
||||||
" {}: {}\"{}\"{} | child",
|
" {}: {}\"{}\"{} | child",
|
||||||
property_name(&node.name, &field.name),
|
property_name(&node.name, &field.name),
|
||||||
o,
|
o,
|
||||||
class_name(&field.tp),
|
class_name(&field.tp),
|
||||||
c
|
c
|
||||||
);
|
)?;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if empty {
|
if empty {
|
||||||
println!(" pass");
|
writeln!(buf, " pass")?;
|
||||||
}
|
}
|
||||||
println!("");
|
writeln!(buf, "")?;
|
||||||
}
|
}
|
||||||
|
Ok(String::from_utf8_lossy(&buf).to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FieldInfo {
|
struct FieldInfo {
|
||||||
@@ -390,40 +400,45 @@ fn get_fields(node: &AstNodeSrc) -> Vec<FieldInfo> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_extractor(grammar: &AstSrc) {
|
fn write_extractor(grammar: &AstSrc) -> std::io::Result<String> {
|
||||||
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
for node in &grammar.enums {
|
for node in &grammar.enums {
|
||||||
let type_name = &node.name;
|
let type_name = &node.name;
|
||||||
let class_name = class_name(&node.name);
|
let class_name = class_name(&node.name);
|
||||||
|
|
||||||
println!(
|
writeln!(
|
||||||
|
buf,
|
||||||
" fn emit_{}(&mut self, node: ast::{}) -> Label<generated::{}> {{",
|
" fn emit_{}(&mut self, node: ast::{}) -> Label<generated::{}> {{",
|
||||||
to_lower_snake_case(type_name),
|
to_lower_snake_case(type_name),
|
||||||
type_name,
|
type_name,
|
||||||
class_name
|
class_name
|
||||||
);
|
)?;
|
||||||
println!(" match node {{");
|
writeln!(buf, " match node {{")?;
|
||||||
for variant in &node.variants {
|
for variant in &node.variants {
|
||||||
println!(
|
writeln!(
|
||||||
|
buf,
|
||||||
" ast::{}::{}(inner) => self.emit_{}(inner).into(),",
|
" ast::{}::{}(inner) => self.emit_{}(inner).into(),",
|
||||||
type_name,
|
type_name,
|
||||||
variant,
|
variant,
|
||||||
to_lower_snake_case(variant)
|
to_lower_snake_case(variant)
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
println!(" }}");
|
writeln!(buf, " }}")?;
|
||||||
println!(" }}\n");
|
writeln!(buf, " }}\n")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for node in &grammar.nodes {
|
for node in &grammar.nodes {
|
||||||
let type_name = &node.name;
|
let type_name = &node.name;
|
||||||
let class_name = class_name(&node.name);
|
let class_name = class_name(&node.name);
|
||||||
|
|
||||||
println!(
|
writeln!(
|
||||||
|
buf,
|
||||||
" fn emit_{}(&mut self, node: ast::{}) -> Label<generated::{}> {{",
|
" fn emit_{}(&mut self, node: ast::{}) -> Label<generated::{}> {{",
|
||||||
to_lower_snake_case(type_name),
|
to_lower_snake_case(type_name),
|
||||||
type_name,
|
type_name,
|
||||||
class_name
|
class_name
|
||||||
);
|
)?;
|
||||||
for field in get_fields(&node) {
|
for field in get_fields(&node) {
|
||||||
if &field.tp == "SyntaxToken" {
|
if &field.tp == "SyntaxToken" {
|
||||||
continue;
|
continue;
|
||||||
@@ -433,45 +448,53 @@ fn print_extractor(grammar: &AstSrc) {
|
|||||||
let struct_field_name = &field.name;
|
let struct_field_name = &field.name;
|
||||||
let class_field_name = property_name(&node.name, &field.name);
|
let class_field_name = property_name(&node.name, &field.name);
|
||||||
if field.tp == "string" {
|
if field.tp == "string" {
|
||||||
println!(" let {} = node.try_get_text();", class_field_name,);
|
writeln!(
|
||||||
|
buf,
|
||||||
|
" let {} = node.try_get_text();",
|
||||||
|
class_field_name,
|
||||||
|
)?;
|
||||||
} else if field.is_many {
|
} else if field.is_many {
|
||||||
println!(
|
writeln!(
|
||||||
|
buf,
|
||||||
" let {} = node.{}().map(|x| self.emit_{}(x)).collect();",
|
" let {} = node.{}().map(|x| self.emit_{}(x)).collect();",
|
||||||
class_field_name,
|
class_field_name,
|
||||||
struct_field_name,
|
struct_field_name,
|
||||||
to_lower_snake_case(type_name)
|
to_lower_snake_case(type_name)
|
||||||
);
|
)?;
|
||||||
} else {
|
} else {
|
||||||
println!(
|
writeln!(
|
||||||
|
buf,
|
||||||
" let {} = node.{}().map(|x| self.emit_{}(x));",
|
" let {} = node.{}().map(|x| self.emit_{}(x));",
|
||||||
class_field_name,
|
class_field_name,
|
||||||
struct_field_name,
|
struct_field_name,
|
||||||
to_lower_snake_case(type_name)
|
to_lower_snake_case(type_name)
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!(
|
writeln!(
|
||||||
|
buf,
|
||||||
" let label = self.trap.emit(generated::{} {{",
|
" let label = self.trap.emit(generated::{} {{",
|
||||||
class_name
|
class_name
|
||||||
);
|
)?;
|
||||||
println!(" id: TrapId::Star,");
|
writeln!(buf, " id: TrapId::Star,")?;
|
||||||
for field in get_fields(&node) {
|
for field in get_fields(&node) {
|
||||||
if field.tp == "SyntaxToken" {
|
if field.tp == "SyntaxToken" {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let class_field_name: String = property_name(&node.name, &field.name);
|
let class_field_name: String = property_name(&node.name, &field.name);
|
||||||
println!(" {},", class_field_name);
|
writeln!(buf, " {},", class_field_name)?;
|
||||||
}
|
}
|
||||||
println!(" }});");
|
writeln!(buf, " }});")?;
|
||||||
println!(" self.emit_location(label, node);");
|
writeln!(buf, " self.emit_location(label, node);")?;
|
||||||
println!(" label");
|
writeln!(buf, " label")?;
|
||||||
|
|
||||||
println!(" }}\n");
|
writeln!(buf, " }}\n")?;
|
||||||
}
|
}
|
||||||
|
Ok(String::from_utf8_lossy(&buf).into_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> std::io::Result<()> {
|
||||||
let grammar: Grammar = fs::read_to_string(project_root().join("generate-schema/rust.ungram"))
|
let grammar: Grammar = fs::read_to_string(project_root().join("generate-schema/rust.ungram"))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
@@ -498,6 +521,15 @@ fn main() {
|
|||||||
let super_class_y = super_types.get(&y.name).into_iter().flatten().max();
|
let super_class_y = super_types.get(&y.name).into_iter().flatten().max();
|
||||||
super_class_x.cmp(&super_class_y).then(x.name.cmp(&y.name))
|
super_class_x.cmp(&super_class_y).then(x.name.cmp(&y.name))
|
||||||
});
|
});
|
||||||
//print_schema(&grammar, super_types);
|
let schema = write_schema(&grammar, super_types)?;
|
||||||
print_extractor(&grammar);
|
let schema_path = PathBuf::from("../schema/ast.py");
|
||||||
|
let extractor = write_extractor(&grammar)?;
|
||||||
|
print!("{}", extractor);
|
||||||
|
codegen::ensure_file_contents(
|
||||||
|
crate::flags::CodegenType::Grammar,
|
||||||
|
&schema_path,
|
||||||
|
&schema,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user