diff --git a/extractor/src/extractor.rs b/extractor/src/extractor.rs index 0cb7c8073e7..999c7b75368 100644 --- a/extractor/src/extractor.rs +++ b/extractor/src/extractor.rs @@ -260,12 +260,12 @@ struct Visitor<'a> { /// A lookup table from type name to node types schema: &'a NodeTypeMap, /// A stack for gathering information from child nodes. Whenever a node is entered - /// the parent's [Label] and an empty list is pushed. All children append their data + /// the parent's [Label], child counter, and 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<(Label, Vec<(Option<&'static str>, Label, TypeName)>)>, + stack: Vec<(Label, usize, Vec<(Option<&'static str>, Label, TypeName)>)>, } impl Visitor<'_> { @@ -290,7 +290,7 @@ impl Visitor<'_> { let id = self.trap_writer.fresh_id(); - self.stack.push((id, Vec::new())); + self.stack.push((id, 0, Vec::new())); return true; } @@ -298,7 +298,7 @@ impl Visitor<'_> { if node.is_error() || node.is_missing() { return; } - let (id, child_nodes) = self.stack.pop().expect("Vistor: empty stack"); + let (id, _, child_nodes) = self.stack.pop().expect("Vistor: empty stack"); let (start_line, start_column, end_line, end_column) = location_for(&self.source, node); let loc = self.trap_writer.location( self.file_label, @@ -315,9 +315,12 @@ impl Visitor<'_> { }) .unwrap(); let mut valid = true; - let parent_id = match self.stack.last_mut() { - Some(p) if !node.is_extra() => p.0, - _ => self.file_label, + let (parent_id, parent_index) = match self.stack.last_mut() { + Some(p) if !node.is_extra() => { + p.1 += 1; + (p.0, p.1 - 1) + } + _ => (self.file_label, 0), }; match &table.kind { EntryKind::Token { kind_id, .. } => { @@ -326,6 +329,7 @@ impl Visitor<'_> { vec![ Arg::Label(id), Arg::Label(parent_id), + Arg::Int(parent_index), Arg::Int(*kind_id), Arg::Label(self.file_label), Arg::Int(self.token_counter), @@ -343,6 +347,7 @@ impl Visitor<'_> { let mut all_args = Vec::new(); all_args.push(Arg::Label(id)); all_args.push(Arg::Label(parent_id)); + all_args.push(Arg::Int(parent_index)); all_args.extend(args); all_args.push(Arg::Label(loc)); self.trap_writer.add_tuple(&table_name, all_args); @@ -362,7 +367,7 @@ impl Visitor<'_> { // Extra nodes are independent root nodes and do not belong to the parent node // Therefore we should not register them in the parent vector if let Some(parent) = self.stack.last_mut() { - parent.1.push(( + parent.2.push(( field_name, id, TypeName { diff --git a/generator/src/main.rs b/generator/src/main.rs index f2b0f071312..64a63fc2343 100644 --- a/generator/src/main.rs +++ b/generator/src/main.rs @@ -170,6 +170,13 @@ fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec( ql_type: ql::Type::AtType("ast_node_parent"), ql_type_is_ref: true, }, + dbscheme::Column { + unique: false, + db_type: dbscheme::DbColumnType::Int, + name: "parent_index", + ql_type: ql::Type::Int, + ql_type_is_ref: true, + }, dbscheme::Column { unique: false, db_type: dbscheme::DbColumnType::Int, diff --git a/generator/src/ql_gen.rs b/generator/src/ql_gen.rs index 35a1d6196ef..798f8d5d1c5 100644 --- a/generator/src/ql_gen.rs +++ b/generator/src/ql_gen.rs @@ -47,6 +47,7 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> { let get_a_field_or_child = create_none_predicate("getAFieldOrChild", false, Some(ql::Type::Normal("AstNode"))); let get_parent = create_none_predicate("getParent", false, Some(ql::Type::Normal("AstNode"))); + let get_parent_index = create_none_predicate("getParentIndex", false, Some(ql::Type::Int)); let describe_ql_class = ql::Predicate { name: "describeQlClass", overridden: false, @@ -66,6 +67,7 @@ fn create_ast_node_class<'a>() -> ql::Class<'a> { to_string, get_location, get_parent, + get_parent_index, get_a_field_or_child, describe_ql_class, ], @@ -78,54 +80,28 @@ fn create_token_class<'a>() -> ql::Class<'a> { overridden: true, return_type: Some(ql::Type::Normal("AstNode")), formal_parameters: vec![], - body: ql::Expression::Pred( - "tokeninfo", - vec![ - ql::Expression::Var("this"), - ql::Expression::Var("result"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ], - ), + body: create_get_field_expr_for_column_storage("tokeninfo", 0, 8), + }; + let get_parent_index = ql::Predicate { + name: "getParentIndex", + overridden: true, + return_type: Some(ql::Type::Int), + formal_parameters: vec![], + body: create_get_field_expr_for_column_storage("tokeninfo", 1, 8), }; let get_value = ql::Predicate { name: "getValue", overridden: false, return_type: Some(ql::Type::String), formal_parameters: vec![], - body: ql::Expression::Pred( - "tokeninfo", - vec![ - ql::Expression::Var("this"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ql::Expression::Var("result"), - ql::Expression::Var("_"), - ], - ), + body: create_get_field_expr_for_column_storage("tokeninfo", 5, 8), }; let get_location = ql::Predicate { name: "getLocation", overridden: true, return_type: Some(ql::Type::Normal("Location")), formal_parameters: vec![], - body: ql::Expression::Pred( - "tokeninfo", - vec![ - ql::Expression::Var("this"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ql::Expression::Var("_"), - ql::Expression::Var("result"), - ], - ), + body: create_get_field_expr_for_column_storage("tokeninfo", 6, 8), }; let to_string = ql::Predicate { name: "toString", @@ -146,6 +122,7 @@ fn create_token_class<'a>() -> ql::Class<'a> { characteristic_predicate: None, predicates: vec![ get_parent, + get_parent_index, get_value, get_location, to_string, @@ -434,10 +411,11 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec(nodes: &'a node_types::NodeTypeMap) -> Vec = Vec::new(); // Iterate through the fields, creating: @@ -499,6 +477,18 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec