Address review comments

This commit is contained in:
Arthur Baars
2020-10-26 19:10:44 +01:00
parent 1d36b5085a
commit 0f576fe29a

View File

@@ -26,8 +26,8 @@ impl Extractor {
.expect("Failed to parse file");
let mut visitor = Visitor {
source: &source,
program: vec![Fact::Comment(format!(
"Auto-generated FACT file for {}, generated by the cool kids",
trap_output: vec![TrapEntry::Comment(format!(
"Auto-generated TRAP file for {}",
path.display()
))],
counter: -1,
@@ -40,7 +40,7 @@ impl Extractor {
traverse(&tree, &mut visitor);
&self.parser.reset();
Ok(Program(visitor.program))
Ok(Program(visitor.trap_output))
}
}
@@ -65,13 +65,24 @@ fn build_union_type_lookup<'a>(schema: &'a Vec<Entry>) -> Map<&'a TypeName, &'a
}
struct Visitor<'a> {
source: &'a Vec<u8>,
program: Vec<Fact>,
counter: i32,
/// The file path of the source code (as string)
path: String,
stack: Vec<Vec<(Option<&'static str>, Id, TypeName)>>,
/// The source code as a UTF-8 byte array
source: &'a Vec<u8>,
/// The accumulated trap entries
trap_output: Vec<TrapEntry>,
/// A counter for generating fresh labels
counter: i32,
/// A lookup table from type name to dbscheme table entries
tables: Map<&'a TypeName, &'a Entry>,
/// A lookup table for union types mapping a type name to its direct members
union_types: Map<&'a TypeName, &'a Set<TypeName>>,
/// A stack for gathering information from hild nodes. Whenever a node is entered
/// an empty list is pushed. All children append their data (field name, label, type) to
/// the the list. When the visitor leaves a node the list containing the child data is popped
/// from the stack and matched against the dbscheme for the node. If the expectations are met
/// the corresponding row definitions are added to the trap_output.
stack: Vec<Vec<(Option<&'static str>, Label, TypeName)>>,
}
impl Visitor<'_> {
@@ -113,11 +124,11 @@ impl Visitor<'_> {
});
if let Some(Entry::Table { fields, .. }) = table {
self.counter += 1;
let id = Id(self.counter);
let loc = Loc(self.counter);
self.program.push(Fact::New(Arg::IdArg(id)));
self.program.push(Fact::New(Arg::LocArg(loc)));
self.program.push(location_for(&self.path, loc, node));
let id = Label::Normal(self.counter);
let loc = Label::Location(self.counter);
self.trap_output.push(TrapEntry::New(id));
self.trap_output.push(TrapEntry::New(loc));
self.trap_output.push(location_for(&self.path, loc, node));
let table_name = node_type_name(node.kind(), node.is_named());
let args: Option<Vec<Arg>>;
if fields.is_empty() {
@@ -126,8 +137,8 @@ impl Visitor<'_> {
args = self.complex_node(&node, fields, child_nodes, id);
}
if let Some(args) = args {
self.program
.push(Fact::Definition(table_name, id, args, loc));
self.trap_output
.push(TrapEntry::Definition(table_name, id, args, loc));
}
if let Some(parent) = self.stack.last_mut() {
parent.push((
@@ -152,10 +163,10 @@ impl Visitor<'_> {
&mut self,
node: &Node,
fields: &Vec<Field>,
child_nodes: Vec<(Option<&str>, Id, TypeName)>,
parent_id: Id,
child_nodes: Vec<(Option<&str>, Label, TypeName)>,
parent_id: Label,
) -> Option<Vec<Arg>> {
let mut map: Map<&Option<String>, (&Field, Vec<Id>)> = std::collections::BTreeMap::new();
let mut map: Map<&Option<String>, (&Field, Vec<Label>)> = std::collections::BTreeMap::new();
for field in fields {
map.insert(&field.name, (field, Vec::new()));
}
@@ -195,7 +206,7 @@ impl Visitor<'_> {
match &field.storage {
Storage::Column => {
if child_ids.len() == 1 {
args.push(Arg::IdArg(*child_ids.first().unwrap()));
args.push(Arg::Label(*child_ids.first().unwrap()));
} else {
is_valid = false;
println!(
@@ -217,7 +228,7 @@ impl Visitor<'_> {
}
Storage::Table { parent, index } => {
for child_id in child_ids {
self.program.push(Fact::ChildOf(
self.trap_output.push(TrapEntry::ChildOf(
node_type_name(&parent.kind, parent.named),
parent_id,
match &field.name {
@@ -255,24 +266,24 @@ impl Visitor<'_> {
// Emit a slice of a source file as an Arg.
fn sliced_source_arg(source: &Vec<u8>, n: Node) -> Arg {
let range = n.byte_range();
Arg::StringArg(String::from(
Arg::String(String::from(
std::str::from_utf8(&source[range.start..range.end]).expect("Failed to decode string"),
))
}
// Emit a 'Located' fact for the provided node, appropriately calibrated.
fn location_for<'a>(fp: &String, ident: Loc, n: Node) -> Fact {
// Emit a 'Located' TrapEntry for the provided node, appropriately calibrated.
fn location_for<'a>(fp: &String, label: Label, n: Node) -> TrapEntry {
let start_line = n.start_position().row;
let start_col = n.start_position().column;
let end_line = n.end_position().row;
let end_col = n.end_position().column;
Fact::Located(vec![
Arg::LocArg(ident),
Arg::StringArg(fp.to_owned()),
Arg::IntArg(start_line),
Arg::IntArg(start_col),
Arg::IntArg(end_line),
Arg::IntArg(end_col),
TrapEntry::Located(vec![
Arg::Label(label),
Arg::String(fp.to_owned()),
Arg::Int(start_line),
Arg::Int(start_col),
Arg::Int(end_line),
Arg::Int(end_col),
])
}
@@ -296,34 +307,35 @@ fn traverse(tree: &Tree, visitor: &mut Visitor) {
}
}
}
pub struct Program(Vec<Fact>);
pub struct Program(Vec<TrapEntry>);
impl fmt::Display for Program {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut text = String::new();
for fact in &self.0 {
text.push_str(&format!("{}\n", fact));
for trap_entry in &self.0 {
text.push_str(&format!("{}\n", trap_entry));
}
write!(f, "{}", text)
}
}
#[derive(Debug)]
enum Fact {
enum TrapEntry {
// @id = *@
New(Arg),
New(Label),
// @node_def(self, arg?, location)@
Definition(String, Id, Vec<Arg>, Loc),
Definition(String, Label, Vec<Arg>, Label),
// @node_child(self, index, parent)@
ChildOf(String, Id, String, Index, Id),
ChildOf(String, Label, String, Index, Label),
// @location(loc, path, r1, c1, r2, c2)
Located(Vec<Arg>),
Comment(String),
}
impl fmt::Display for Fact {
impl fmt::Display for TrapEntry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Fact::New(id) => write!(f, "{} = *", id),
Fact::Definition(n, id, args, loc) => {
TrapEntry::New(id) => write!(f, "{} = *", id),
TrapEntry::Definition(n, id, args, loc) => {
let mut args_str = String::new();
for arg in args {
args_str.push_str(&format!("{}, ", arg));
@@ -337,7 +349,7 @@ impl fmt::Display for Fact {
loc
)
}
Fact::ChildOf(pname, id, fname, idx, p) => write!(
TrapEntry::ChildOf(pname, id, fname, idx, p) => write!(
f,
"{}({}, {}, {})",
escape_name(&format!("{}_{}", &pname, &fname)),
@@ -345,7 +357,7 @@ impl fmt::Display for Fact {
idx,
p
),
Fact::Located(args) => write!(
TrapEntry::Located(args) => write!(
f,
"location({}, {}, {}, {}, {}, {})",
args.get(0).unwrap(),
@@ -355,28 +367,28 @@ impl fmt::Display for Fact {
args.get(4).unwrap(),
args.get(5).unwrap(),
),
Fact::Comment(line) => write!(f, "// {}", line),
TrapEntry::Comment(line) => write!(f, "// {}", line),
}
}
}
// Identifiers of the form #0, #1...
#[derive(Debug, Copy, Clone)]
struct Id(i32);
impl fmt::Display for Id {
#[derive(Debug, Copy, Clone)]
enum Label {
// Identifiers of the form #0, #1...
Normal(i32), // #0, #1, etc.
// Location identifiers of the form #0_loc, #1_loc...
Location(i32), // #0_loc, #1_loc, etc.
}
impl fmt::Display for Label {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "#{}", self.0)
match self {
Label::Normal(x) => write!(f, "#{}", x),
Label::Location(x) => write!(f, "#{}_loc", x),
}
}
}
// Locative identifiers of the form #0_loc, #1_loc...
#[derive(Debug, Copy, Clone)]
struct Loc(i32);
impl fmt::Display for Loc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "#{}_loc", self.0)
}
}
// Numeric indices.
#[derive(Debug, Copy, Clone)]
struct Index(usize);
@@ -387,22 +399,20 @@ impl fmt::Display for Index {
}
}
// Some untyped argument to a fact.
// Some untyped argument to a TrapEntry.
#[derive(Debug)]
enum Arg {
IntArg(usize),
StringArg(String),
IdArg(Id),
LocArg(Loc),
Label(Label),
Int(usize),
String(String),
}
impl fmt::Display for Arg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Arg::IntArg(x) => write!(f, "{}", x),
Arg::StringArg(x) => write!(f, "\"{}\"", x.replace("\"", "\"\"")),
Arg::IdArg(x) => write!(f, "{}", x),
Arg::LocArg(x) => write!(f, "{}", x),
Arg::Label(x) => write!(f, "{}", x),
Arg::Int(x) => write!(f, "{}", x),
Arg::String(x) => write!(f, "\"{}\"", x.replace("\"", "\"\"")),
}
}
}