Merge pull request #71 from github/kinds

Create disjoint db types for different operators
This commit is contained in:
Arthur Baars
2020-12-17 09:58:52 +01:00
committed by GitHub
8 changed files with 9446 additions and 7987 deletions

View File

@@ -246,6 +246,12 @@ fn full_id_for_folder(path: &Path) -> String {
format!("{};folder", normalize_path(path))
}
struct ChildNode {
field_name: Option<&'static str>,
label: Label,
type_name: TypeName,
}
struct Visitor<'a> {
/// The file path of the source code (as string)
path: String,
@@ -262,13 +268,13 @@ struct Visitor<'a> {
toplevel_child_counter: usize,
/// 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], 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, usize, Vec<(Option<&'static str>, Label, TypeName)>)>,
/// A stack for gathering information from child nodes. Whenever a node is
/// entered the parent's [Label], child counter, and an empty list is pushed.
/// All children append their data 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, usize, Vec<ChildNode>)>,
}
impl Visitor<'_> {
@@ -349,7 +355,7 @@ impl Visitor<'_> {
fields,
name: table_name,
} => {
if let Some(args) = self.complex_node(&node, fields, child_nodes, id) {
if let Some(args) = self.complex_node(&node, fields, &child_nodes, id) {
let mut all_args = Vec::new();
all_args.push(Arg::Label(id));
all_args.push(Arg::Label(parent_id));
@@ -373,14 +379,14 @@ 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.2.push((
parent.2.push(ChildNode {
field_name,
id,
TypeName {
label: id,
type_name: TypeName {
kind: node.kind().to_owned(),
named: node.is_named(),
},
))
});
};
}
}
@@ -389,38 +395,47 @@ impl Visitor<'_> {
&mut self,
node: &Node,
fields: &Vec<Field>,
child_nodes: Vec<(Option<&str>, Label, TypeName)>,
child_nodes: &Vec<ChildNode>,
parent_id: Label,
) -> Option<Vec<Arg>> {
let mut map: Map<&Option<String>, (&Field, Vec<Label>)> = std::collections::BTreeMap::new();
let mut map: Map<&Option<String>, (&Field, Vec<Arg>)> = Map::new();
for field in fields {
map.insert(&field.name, (field, Vec::new()));
}
for (child_field, child_id, child_type) in child_nodes {
if let Some((field, values)) = map.get_mut(&child_field.map(|x| x.to_owned())) {
for child_node in child_nodes {
if let Some((field, values)) = map.get_mut(&child_node.field_name.map(|x| x.to_owned()))
{
//TODO: handle error and missing nodes
if self.type_matches(&child_type, &field.type_info) {
values.push(child_id);
if self.type_matches(&child_node.type_name, &field.type_info) {
if let node_types::FieldTypeInfo::ReservedWordInt(int_mapping) =
&field.type_info
{
// We can safely unwrap because type_matches checks the key is in the map.
let (int_value, _) = int_mapping.get(&child_node.type_name.kind).unwrap();
values.push(Arg::Int(*int_value));
} else {
values.push(Arg::Label(child_node.label));
}
} else if field.name.is_some() {
error!(
"{}:{}: type mismatch for field {}::{} with type {:?} != {:?}",
&self.path,
node.start_position().row + 1,
node.kind(),
child_field.unwrap_or("child"),
child_type,
child_node.field_name.unwrap_or("child"),
child_node.type_name,
field.type_info
)
}
} else {
if child_field.is_some() || child_type.named {
if child_node.field_name.is_some() || child_node.type_name.named {
error!(
"{}:{}: value for unknown field: {}::{} and type {:?}",
&self.path,
node.start_position().row + 1,
node.kind(),
&child_field.unwrap_or("child"),
&child_type
&child_node.field_name.unwrap_or("child"),
&child_node.type_name
);
}
}
@@ -428,18 +443,18 @@ impl Visitor<'_> {
let mut args = Vec::new();
let mut is_valid = true;
for field in fields {
let child_ids = &map.get(&field.name).unwrap().1;
let child_values = &map.get(&field.name).unwrap().1;
match &field.storage {
Storage::Column { name: column_name } => {
if child_ids.len() == 1 {
args.push(Arg::Label(*child_ids.first().unwrap()));
if child_values.len() == 1 {
args.push(child_values.first().unwrap().clone());
} else {
is_valid = false;
error!(
"{}:{}: {} for field: {}::{}",
&self.path,
node.start_position().row + 1,
if child_ids.is_empty() {
if child_values.is_empty() {
"missing value"
} else {
"too many values"
@@ -453,7 +468,7 @@ impl Visitor<'_> {
name: table_name,
has_index,
} => {
for (index, child_id) in child_ids.iter().enumerate() {
for (index, child_value) in child_values.iter().enumerate() {
if !*has_index && index > 0 {
error!(
"{}:{}: too many values for field: {}::{}",
@@ -469,7 +484,7 @@ impl Visitor<'_> {
if *has_index {
args.push(Arg::Int(index))
}
args.push(Arg::Label(*child_id));
args.push(child_value.clone());
self.trap_writer.add_tuple(&table_name, args);
}
}
@@ -500,6 +515,10 @@ impl Visitor<'_> {
node_types::FieldTypeInfo::Multiple { types, .. } => {
return self.type_matches_set(tp, types);
}
node_types::FieldTypeInfo::ReservedWordInt(int_mapping) => {
return !tp.named && int_mapping.contains_key(&tp.kind)
}
}
false
}
@@ -658,7 +677,7 @@ impl fmt::Display for Index {
}
// Some untyped argument to a TrapEntry.
#[derive(Debug)]
#[derive(Debug, Clone)]
enum Arg {
Label(Label),
Int(usize),

View File

@@ -12,13 +12,13 @@ use std::path::PathBuf;
use tracing::{error, info};
/// Given the name of the parent node, and its field information, returns a pair,
/// the first of which is the name of the field's type. The second is an optional
/// dbscheme entry that should be added, representing a union of all the possible
/// types the field can take.
/// the first of which is the field's type. The second is an optional dbscheme
/// entry that should be added.
fn make_field_type<'a>(
parent_name: &'a str,
field: &'a node_types::Field,
nodes: &'a node_types::NodeTypeMap,
) -> (&'a str, Option<dbscheme::Entry<'a>>) {
) -> (ql::Type<'a>, Option<dbscheme::Entry<'a>>) {
match &field.type_info {
node_types::FieldTypeInfo::Multiple {
types,
@@ -32,14 +32,34 @@ fn make_field_type<'a>(
.map(|t| nodes.get(t).unwrap().dbscheme_name.as_str())
.collect();
(
&dbscheme_union,
ql::Type::AtType(&dbscheme_union),
Some(dbscheme::Entry::Union(dbscheme::Union {
name: dbscheme_union,
members,
})),
)
}
node_types::FieldTypeInfo::Single(t) => (&nodes.get(&t).unwrap().dbscheme_name, None),
node_types::FieldTypeInfo::Single(t) => {
let dbscheme_name = &nodes.get(&t).unwrap().dbscheme_name;
(ql::Type::AtType(dbscheme_name), None)
}
node_types::FieldTypeInfo::ReservedWordInt(int_mapping) => {
// The field will be an `int` in the db, and we add a case split to
// create other db types for each integer value.
let mut branches: Vec<(usize, &'a str)> = Vec::new();
for (_, (value, name)) in int_mapping {
branches.push((*value, name));
}
let case = dbscheme::Entry::Case(dbscheme::Case {
name: parent_name,
column: match &field.storage {
node_types::Storage::Column { name } => name,
node_types::Storage::Table { name, .. } => name,
},
branches,
});
(ql::Type::Int, Some(case))
}
}
}
@@ -52,7 +72,7 @@ fn add_field_for_table_storage<'a>(
let parent_name = &nodes.get(&field.parent).unwrap().dbscheme_name;
// This field can appear zero or multiple times, so put
// it in an auxiliary table.
let (field_type_name, field_type_entry) = make_field_type(&field, nodes);
let (field_ql_type, field_type_entry) = make_field_type(parent_name, &field, nodes);
let parent_column = dbscheme::Column {
unique: !has_index,
db_type: dbscheme::DbColumnType::Int,
@@ -70,8 +90,11 @@ fn add_field_for_table_storage<'a>(
let field_column = dbscheme::Column {
unique: true,
db_type: dbscheme::DbColumnType::Int,
name: field_type_name,
ql_type: ql::Type::AtType(field_type_name),
name: match &field.name {
None => "child",
Some(name) => name,
},
ql_type: field_ql_type,
ql_type_is_ref: true,
};
let field_table = dbscheme::Table {
@@ -93,19 +116,20 @@ fn add_field_for_table_storage<'a>(
}
fn add_field_for_column_storage<'a>(
parent_name: &'a str,
field: &'a node_types::Field,
column_name: &'a str,
nodes: &'a node_types::NodeTypeMap,
) -> (dbscheme::Column<'a>, Option<dbscheme::Entry<'a>>) {
// This field must appear exactly once, so we add it as
// a column to the main table for the node type.
let (field_type_name, field_type_entry) = make_field_type(&field, nodes);
let (field_ql_type, field_type_entry) = make_field_type(parent_name, &field, nodes);
(
dbscheme::Column {
unique: false,
db_type: dbscheme::DbColumnType::Int,
name: column_name,
ql_type: ql::Type::AtType(field_type_name),
ql_type: field_ql_type,
ql_type_is_ref: true,
},
field_type_entry,
@@ -185,9 +209,13 @@ fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<dbscheme::Entry<
// auxiliary tables or columns in the defining table for them.
for field in fields {
match &field.storage {
node_types::Storage::Column { name } => {
let (field_column, field_type_entry) =
add_field_for_column_storage(field, name, nodes);
node_types::Storage::Column { name: column_name } => {
let (field_column, field_type_entry) = add_field_for_column_storage(
&node.dbscheme_name,
field,
column_name,
nodes,
);
if let Some(field_type_entry) = field_type_entry {
entries.push(field_type_entry);
}

View File

@@ -93,7 +93,9 @@ impl<'a> fmt::Display for Type<'a> {
pub enum Expression<'a> {
Var(&'a str),
String(&'a str),
Integer(usize),
Pred(&'a str, Vec<Expression<'a>>),
And(Vec<Expression<'a>>),
Or(Vec<Expression<'a>>),
Equals(Box<Expression<'a>>, Box<Expression<'a>>),
Dot(Box<Expression<'a>>, &'a str, Vec<Expression<'a>>),
@@ -110,6 +112,7 @@ impl<'a> fmt::Display for Expression<'a> {
match self {
Expression::Var(x) => write!(f, "{}", x),
Expression::String(s) => write!(f, "\"{}\"", s),
Expression::Integer(n) => write!(f, "{}", n),
Expression::Pred(n, args) => {
write!(f, "{}(", n)?;
for (index, arg) in args.iter().enumerate() {
@@ -120,6 +123,19 @@ impl<'a> fmt::Display for Expression<'a> {
}
write!(f, ")")
}
Expression::And(conjuncts) => {
if conjuncts.is_empty() {
write!(f, "any()")
} else {
for (index, conjunct) in conjuncts.iter().enumerate() {
if index > 0 {
write!(f, " and ")?;
}
write!(f, "({})", conjunct)?;
}
Ok(())
}
}
Expression::Or(disjuncts) => {
if disjuncts.is_empty() {
write!(f, "none()")

View File

@@ -80,28 +80,28 @@ fn create_token_class<'a>() -> ql::Class<'a> {
overridden: true,
return_type: Some(ql::Type::Normal("AstNode")),
formal_parameters: vec![],
body: create_get_field_expr_for_column_storage("tokeninfo", 0, 8),
body: create_get_field_expr_for_column_storage("result", "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),
body: create_get_field_expr_for_column_storage("result", "tokeninfo", 1, 8),
};
let get_value = ql::Predicate {
name: "getValue",
overridden: false,
return_type: Some(ql::Type::String),
formal_parameters: vec![],
body: create_get_field_expr_for_column_storage("tokeninfo", 5, 8),
body: create_get_field_expr_for_column_storage("result", "tokeninfo", 5, 8),
};
let get_location = ql::Predicate {
name: "getLocation",
overridden: true,
return_type: Some(ql::Type::Normal("Location")),
formal_parameters: vec![],
body: create_get_field_expr_for_column_storage("tokeninfo", 6, 8),
body: create_get_field_expr_for_column_storage("result", "tokeninfo", 6, 8),
};
let to_string = ql::Predicate {
name: "toString",
@@ -228,10 +228,12 @@ fn create_get_text_predicate<'a>(def_table: &'a str) -> ql::Predicate<'a> {
///
/// # Arguments
///
/// * `result_var_name` - the name of the variable to which the resulting value should be bound
/// * `table_name` - the name of parent's defining table
/// * `column_index` - the index in that table that defines the field
/// * `arity` - the total number of columns in the table
fn create_get_field_expr_for_column_storage<'a>(
result_var_name: &'a str,
table_name: &'a str,
column_index: usize,
arity: usize,
@@ -243,7 +245,7 @@ fn create_get_field_expr_for_column_storage<'a>(
[
vec![ql::Expression::Var("this")],
vec![ql::Expression::Var("_"); num_underscores_before],
vec![ql::Expression::Var("result")],
vec![ql::Expression::Var(result_var_name)],
vec![ql::Expression::Var("_"); num_underscores_after],
]
.concat(),
@@ -254,6 +256,7 @@ fn create_get_field_expr_for_column_storage<'a>(
/// auxiliary table. The index name can be "_" so the expression will hold for
/// all indices.
fn create_get_field_expr_for_table_storage<'a>(
result_var_name: &'a str,
table_name: &'a str,
index_var_name: Option<&'a str>,
) -> ql::Expression<'a> {
@@ -263,7 +266,7 @@ fn create_get_field_expr_for_table_storage<'a>(
Some(index_var_name) => vec![
ql::Expression::Var("this"),
ql::Expression::Var(index_var_name),
ql::Expression::Var("result"),
ql::Expression::Var(result_var_name),
],
None => vec![ql::Expression::Var("this"), ql::Expression::Var("result")],
},
@@ -271,9 +274,9 @@ fn create_get_field_expr_for_table_storage<'a>(
}
/// Creates a pair consisting of a predicate to get the given field, and an
/// expression that will get the same field. When the field can occur multiple
/// times, the predicate will take an index argument, while the expression will
/// use the "don't care" expression to hold for all occurrences.
/// optional expression that will get the same field. When the field can occur
/// multiple times, the predicate will take an index argument, while the
/// expression will use the "don't care" expression to hold for all occurrences.
///
/// # Arguments
///
@@ -291,65 +294,128 @@ fn create_field_getters<'a>(
main_table_column_index: &mut usize,
field: &'a node_types::Field,
nodes: &'a node_types::NodeTypeMap,
) -> (ql::Predicate<'a>, ql::Expression<'a>) {
let return_type = Some(ql::Type::Normal(match &field.type_info {
node_types::FieldTypeInfo::Single(t) => &nodes.get(&t).unwrap().ql_class_name,
) -> (ql::Predicate<'a>, Option<ql::Expression<'a>>) {
let return_type = match &field.type_info {
node_types::FieldTypeInfo::Single(t) => {
Some(ql::Type::Normal(&nodes.get(&t).unwrap().ql_class_name))
}
node_types::FieldTypeInfo::Multiple {
types: _,
dbscheme_union: _,
ql_class,
} => &ql_class,
}));
match &field.storage {
} => Some(ql::Type::Normal(&ql_class)),
node_types::FieldTypeInfo::ReservedWordInt(_) => Some(ql::Type::String),
};
let formal_parameters = match &field.storage {
node_types::Storage::Column { .. } => vec![],
node_types::Storage::Table { has_index, .. } => {
if *has_index {
vec![ql::FormalParameter {
name: "i",
param_type: ql::Type::Int,
}]
} else {
vec![]
}
}
};
// For the expression to get a value, what variable name should the result
// be bound to?
let get_value_result_var_name = match &field.type_info {
node_types::FieldTypeInfo::ReservedWordInt(_) => "value",
node_types::FieldTypeInfo::Single(_) => "result",
node_types::FieldTypeInfo::Multiple { .. } => "result",
};
// Two expressions for getting the value. One that's suitable use in the
// getter predicate (where there may be a specific index), and another for
// use in `getAFieldOrChild` (where we use a "don't care" expression to
// match any index).
let (get_value, get_value_any_index) = match &field.storage {
node_types::Storage::Column { name: _ } => {
let result = (
ql::Predicate {
name: &field.getter_name,
overridden: false,
return_type,
formal_parameters: vec![],
body: create_get_field_expr_for_column_storage(
&main_table_name,
*main_table_column_index,
main_table_arity,
),
},
let column_index = *main_table_column_index;
*main_table_column_index += 1;
(
create_get_field_expr_for_column_storage(
get_value_result_var_name,
&main_table_name,
*main_table_column_index,
column_index,
main_table_arity,
),
);
*main_table_column_index += 1;
result
create_get_field_expr_for_column_storage(
get_value_result_var_name,
&main_table_name,
column_index,
main_table_arity,
),
)
}
node_types::Storage::Table {
name: field_table_name,
has_index,
} => (
ql::Predicate {
name: &field.getter_name,
overridden: false,
return_type,
formal_parameters: if *has_index {
vec![ql::FormalParameter {
name: "i",
param_type: ql::Type::Int,
}]
} else {
vec![]
},
body: create_get_field_expr_for_table_storage(
&field_table_name,
if *has_index { Some("i") } else { None },
),
},
create_get_field_expr_for_table_storage(
get_value_result_var_name,
&field_table_name,
if *has_index { Some("i") } else { None },
),
create_get_field_expr_for_table_storage(
get_value_result_var_name,
&field_table_name,
if *has_index { Some("_") } else { None },
),
),
}
};
let (body, optional_expr) = match &field.type_info {
node_types::FieldTypeInfo::ReservedWordInt(int_mapping) => {
// Create an expression that binds the corresponding string to `result` for each `value`, e.g.:
// result = "foo" and value = 0 or
// result = "bar" and value = 1 or
// result = "baz" and value = 2
let disjuncts = int_mapping
.iter()
.map(|(token_str, (value, _))| {
ql::Expression::And(vec![
ql::Expression::Equals(
Box::new(ql::Expression::Var("result")),
Box::new(ql::Expression::String(token_str)),
),
ql::Expression::Equals(
Box::new(ql::Expression::Var("value")),
Box::new(ql::Expression::Integer(*value)),
),
])
})
.collect();
(
ql::Expression::Aggregate(
"exists",
vec![ql::FormalParameter {
name: "value",
param_type: ql::Type::Int,
}],
Box::new(get_value),
Box::new(ql::Expression::Or(disjuncts)),
),
// Since the getter returns a string and not an AstNode, it won't be part of getAFieldOrChild:
None,
)
}
node_types::FieldTypeInfo::Single(_) | node_types::FieldTypeInfo::Multiple { .. } => {
(get_value, Some(get_value_any_index))
}
};
(
ql::Predicate {
name: &field.getter_name,
overridden: false,
return_type,
formal_parameters,
body,
},
optional_expr,
)
}
/// Converts the given node types into CodeQL classes wrapping the dbscheme.
@@ -462,7 +528,9 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
nodes,
);
main_class.predicates.push(get_pred);
get_child_exprs.push(get_child_expr);
if let Some(get_child_expr) = get_child_expr {
get_child_exprs.push(get_child_expr)
}
}
main_class.predicates.push(ql::Predicate {
@@ -471,6 +539,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
return_type: Some(ql::Type::Normal("AstNode")),
formal_parameters: vec![],
body: create_get_field_expr_for_column_storage(
"result",
&main_table_name,
0,
main_table_arity,
@@ -483,6 +552,7 @@ pub fn convert_nodes<'a>(nodes: &'a node_types::NodeTypeMap) -> Vec<ql::TopLevel
return_type: Some(ql::Type::Int),
formal_parameters: vec![],
body: create_get_field_expr_for_column_storage(
"result",
&main_table_name,
1,
main_table_arity,

View File

@@ -41,6 +41,10 @@ pub enum FieldTypeInfo {
dbscheme_union: String,
ql_class: String,
},
/// The field can be one of several tokens, so the db type will be an `int`
/// with a `case @foo.kind` for each possiblity.
ReservedWordInt(BTreeMap<String, (usize, String)>),
}
#[derive(Debug)]
@@ -74,12 +78,12 @@ pub enum Storage {
pub fn read_node_types(node_types_path: &Path) -> std::io::Result<NodeTypeMap> {
let file = fs::File::open(node_types_path)?;
let node_types = serde_json::from_reader(file)?;
Ok(convert_nodes(node_types))
Ok(convert_nodes(&node_types))
}
pub fn read_node_types_str(node_types_json: &str) -> std::io::Result<NodeTypeMap> {
let node_types = serde_json::from_str(node_types_json)?;
Ok(convert_nodes(node_types))
Ok(convert_nodes(&node_types))
}
fn convert_type(node_type: &NodeType) -> TypeName {
@@ -94,9 +98,23 @@ fn convert_types(node_types: &Vec<NodeType>) -> Set<TypeName> {
std::collections::BTreeSet::from(iter)
}
pub fn convert_nodes(nodes: Vec<NodeInfo>) -> NodeTypeMap {
pub fn convert_nodes(nodes: &Vec<NodeInfo>) -> NodeTypeMap {
let mut entries = NodeTypeMap::new();
let mut token_kinds = Set::new();
// First, find all the token kinds
for node in nodes {
if node.subtypes.is_none() {
if node.fields.as_ref().map_or(0, |x| x.len()) == 0 && node.children.is_none() {
let type_name = TypeName {
kind: node.kind.clone(),
named: node.named,
};
token_kinds.insert(type_name);
}
}
}
for node in nodes {
let flattened_name = &node_type_name(&node.kind, node.named);
let dbscheme_name = escape_name(&flattened_name);
@@ -106,7 +124,7 @@ pub fn convert_nodes(nodes: Vec<NodeInfo>) -> NodeTypeMap {
// type.
entries.insert(
TypeName {
kind: node.kind,
kind: node.kind.clone(),
named: node.named,
},
Entry {
@@ -118,15 +136,11 @@ pub fn convert_nodes(nodes: Vec<NodeInfo>) -> NodeTypeMap {
},
);
} else if node.fields.as_ref().map_or(0, |x| x.len()) == 0 && node.children.is_none() {
let type_name = TypeName {
kind: node.kind,
named: node.named,
};
token_kinds.insert(type_name);
// Token kind, handled above.
} else {
// It's a product type, defined by a table.
let type_name = TypeName {
kind: node.kind,
kind: node.kind.clone(),
named: node.named,
};
let table_name = escape_name(&(format!("{}_def", &flattened_name)));
@@ -141,12 +155,13 @@ pub fn convert_nodes(nodes: Vec<NodeInfo>) -> NodeTypeMap {
Some(field_name.to_string()),
field_info,
&mut fields,
&token_kinds,
);
}
}
if let Some(children) = &node.children {
// Treat children as if they were a field called 'child'.
add_field(&type_name, None, children, &mut fields);
add_field(&type_name, None, children, &mut fields, &token_kinds);
}
entries.insert(
type_name,
@@ -188,6 +203,7 @@ fn add_field(
field_name: Option<String>,
field_info: &FieldInfo,
fields: &mut Vec<Field>,
token_kinds: &Set<TypeName>,
) {
let parent_flattened_name = node_type_name(&parent_type_name.kind, parent_type_name.named);
let storage = if !field_info.multiple && field_info.required {
@@ -209,12 +225,30 @@ fn add_field(
name: field_table_name,
}
};
let type_info = if field_info.types.len() == 1 {
FieldTypeInfo::Single(convert_type(field_info.types.iter().next().unwrap()))
let converted_types = convert_types(&field_info.types);
let type_info = if field_info
.types
.iter()
.all(|t| !t.named && token_kinds.contains(&convert_type(t)))
{
// All possible types for this field are reserved words. The db
// representation will be an `int` with a `case @foo.field = ...` to
// enumerate the possible values.
let mut counter = 0;
let mut field_token_ints: BTreeMap<String, (usize, String)> = BTreeMap::new();
for t in converted_types {
let dbscheme_variant_name =
escape_name(&format!("{}_{}", parent_flattened_name, t.kind));
field_token_ints.insert(t.kind.to_owned(), (counter, dbscheme_variant_name));
counter += 1;
}
FieldTypeInfo::ReservedWordInt(field_token_ints)
} else if field_info.types.len() == 1 {
FieldTypeInfo::Single(converted_types.into_iter().next().unwrap())
} else {
// The dbscheme type for this field will be a union. In QL, it'll just be AstNode.
FieldTypeInfo::Multiple {
types: convert_types(&field_info.types),
types: converted_types,
dbscheme_union: format!(
"{}_{}_type",
&parent_flattened_name,

View File

@@ -178,7 +178,59 @@ module Generated {
AstNode getLeft() { binary_def(this, _, _, result, _, _, _) }
AstNode getOperator() { binary_def(this, _, _, _, result, _, _) }
string getOperator() {
exists(int value | binary_def(this, _, _, _, value, _, _) |
result = "!=" and value = 0
or
result = "!~" and value = 1
or
result = "%" and value = 2
or
result = "&" and value = 3
or
result = "&&" and value = 4
or
result = "*" and value = 5
or
result = "**" and value = 6
or
result = "+" and value = 7
or
result = "-" and value = 8
or
result = "/" and value = 9
or
result = "<" and value = 10
or
result = "<<" and value = 11
or
result = "<=" and value = 12
or
result = "<=>" and value = 13
or
result = "==" and value = 14
or
result = "===" and value = 15
or
result = "=~" and value = 16
or
result = ">" and value = 17
or
result = ">=" and value = 18
or
result = ">>" and value = 19
or
result = "^" and value = 20
or
result = "and" and value = 21
or
result = "or" and value = 22
or
result = "|" and value = 23
or
result = "||" and value = 24
)
}
AstNode getRight() { binary_def(this, _, _, _, _, result, _) }
@@ -187,9 +239,7 @@ module Generated {
override int getParentIndex() { binary_def(this, _, result, _, _, _, _) }
override AstNode getAFieldOrChild() {
binary_def(this, _, _, result, _, _, _) or
binary_def(this, _, _, _, result, _, _) or
binary_def(this, _, _, _, _, result, _)
binary_def(this, _, _, result, _, _, _) or binary_def(this, _, _, _, _, result, _)
}
}
@@ -887,7 +937,35 @@ module Generated {
UnderscoreLhs getLeft() { operator_assignment_def(this, _, _, result, _, _, _) }
AstNode getOperator() { operator_assignment_def(this, _, _, _, result, _, _) }
string getOperator() {
exists(int value | operator_assignment_def(this, _, _, _, value, _, _) |
result = "%=" and value = 0
or
result = "&&=" and value = 1
or
result = "&=" and value = 2
or
result = "**=" and value = 3
or
result = "*=" and value = 4
or
result = "+=" and value = 5
or
result = "-=" and value = 6
or
result = "/=" and value = 7
or
result = "<<=" and value = 8
or
result = ">>=" and value = 9
or
result = "^=" and value = 10
or
result = "|=" and value = 11
or
result = "||=" and value = 12
)
}
AstNode getRight() { operator_assignment_def(this, _, _, _, _, result, _) }
@@ -897,7 +975,6 @@ module Generated {
override AstNode getAFieldOrChild() {
operator_assignment_def(this, _, _, result, _, _, _) or
operator_assignment_def(this, _, _, _, result, _, _) or
operator_assignment_def(this, _, _, _, _, result, _)
}
}
@@ -1355,15 +1432,27 @@ module Generated {
AstNode getOperand() { unary_def(this, _, _, result, _, _) }
AstNode getOperator() { unary_def(this, _, _, _, result, _) }
string getOperator() {
exists(int value | unary_def(this, _, _, _, value, _) |
result = "!" and value = 0
or
result = "+" and value = 1
or
result = "-" and value = 2
or
result = "defined?" and value = 3
or
result = "not" and value = 4
or
result = "~" and value = 5
)
}
override AstNode getParent() { unary_def(this, result, _, _, _, _) }
override int getParentIndex() { unary_def(this, _, result, _, _, _) }
override AstNode getAFieldOrChild() {
unary_def(this, _, _, result, _, _) or unary_def(this, _, _, _, result, _)
}
override AstNode getAFieldOrChild() { unary_def(this, _, _, result, _, _) }
}
class Undef extends @undef, AstNode {

View File

@@ -74,7 +74,7 @@ alias_def(
argument_list_child(
int argument_list: @argument_list ref,
int index: int ref,
unique int argument_list_child_type: @argument_list_child_type ref
unique int child: @argument_list_child_type ref
);
#keyset[parent, parent_index]
@@ -91,7 +91,7 @@ argument_list_def(
array_child(
int array: @array ref,
int index: int ref,
unique int array_child_type: @array_child_type ref
unique int child: @array_child_type ref
);
#keyset[parent, parent_index]
@@ -122,7 +122,7 @@ assignment_def(
bare_string_child(
int bare_string: @bare_string ref,
int index: int ref,
unique int bare_string_child_type: @bare_string_child_type ref
unique int child: @bare_string_child_type ref
);
#keyset[parent, parent_index]
@@ -139,7 +139,7 @@ bare_string_def(
bare_symbol_child(
int bare_symbol: @bare_symbol ref,
int index: int ref,
unique int bare_symbol_child_type: @bare_symbol_child_type ref
unique int child: @bare_symbol_child_type ref
);
#keyset[parent, parent_index]
@@ -156,7 +156,7 @@ bare_symbol_def(
begin_child(
int begin: @begin ref,
int index: int ref,
unique int begin_child_type: @begin_child_type ref
unique int child: @begin_child_type ref
);
#keyset[parent, parent_index]
@@ -173,7 +173,7 @@ begin_def(
begin_block_child(
int begin_block: @begin_block ref,
int index: int ref,
unique int begin_block_child_type: @begin_block_child_type ref
unique int child: @begin_block_child_type ref
);
#keyset[parent, parent_index]
@@ -186,7 +186,34 @@ begin_block_def(
@binary_left_type = @break | @call | @next | @return | @underscore_arg | @yield
@binary_operator_type = @reserved_word
case @binary.operator of
0 = @binary_bangequal
| 1 = @binary_bangtilde
| 2 = @binary_percent
| 3 = @binary_ampersand
| 4 = @binary_ampersandampersand
| 5 = @binary_star
| 6 = @binary_starstar
| 7 = @binary_plus
| 8 = @binary_minus
| 9 = @binary_slash
| 10 = @binary_langle
| 11 = @binary_langlelangle
| 12 = @binary_langleequal
| 13 = @binary_langleequalrangle
| 14 = @binary_equalequal
| 15 = @binary_equalequalequal
| 16 = @binary_equaltilde
| 17 = @binary_rangle
| 18 = @binary_rangleequal
| 19 = @binary_ranglerangle
| 20 = @binary_caret
| 21 = @binary_and
| 22 = @binary_or
| 23 = @binary_pipe
| 24 = @binary_pipepipe
;
@binary_right_type = @break | @call | @next | @return | @underscore_arg | @yield
@@ -196,14 +223,14 @@ binary_def(
int parent: @ast_node_parent ref,
int parent_index: int ref,
int left: @binary_left_type ref,
int operator: @binary_operator_type ref,
int operator: int ref,
int right: @binary_right_type ref,
int loc: @location ref
);
block_parameters(
unique int block: @block ref,
unique int block_parameters: @block_parameters ref
unique int parameters: @block_parameters ref
);
@block_child_type = @token_empty_statement | @underscore_statement
@@ -212,7 +239,7 @@ block_parameters(
block_child(
int block: @block ref,
int index: int ref,
unique int block_child_type: @block_child_type ref
unique int child: @block_child_type ref
);
#keyset[parent, parent_index]
@@ -247,7 +274,7 @@ block_parameter_def(
block_parameters_child(
int block_parameters: @block_parameters ref,
int index: int ref,
unique int block_parameters_child_type: @block_parameters_child_type ref
unique int child: @block_parameters_child_type ref
);
#keyset[parent, parent_index]
@@ -260,7 +287,7 @@ block_parameters_def(
break_child(
unique int break: @break ref,
unique int argument_list: @argument_list ref
unique int child: @argument_list ref
);
#keyset[parent, parent_index]
@@ -273,14 +300,14 @@ break_def(
call_arguments(
unique int call: @call ref,
unique int argument_list: @argument_list ref
unique int arguments: @argument_list ref
);
@call_block_type = @block | @do_block
call_block(
unique int call: @call ref,
unique int call_block_type: @call_block_type ref
unique int block: @call_block_type ref
);
@call_method_type = @argument_list | @scope_resolution | @token_operator | @underscore_variable
@@ -289,7 +316,7 @@ call_block(
call_receiver(
unique int call: @call ref,
unique int call_receiver_type: @call_receiver_type ref
unique int receiver: @call_receiver_type ref
);
#keyset[parent, parent_index]
@@ -303,7 +330,7 @@ call_def(
case_value(
unique int case__: @case__ ref,
unique int underscore_statement: @underscore_statement ref
unique int value: @underscore_statement ref
);
@case_child_type = @else | @when
@@ -312,7 +339,7 @@ case_value(
case_child(
int case__: @case__ ref,
int index: int ref,
unique int case_child_type: @case_child_type ref
unique int child: @case_child_type ref
);
#keyset[parent, parent_index]
@@ -327,7 +354,7 @@ case_def(
chained_string_child(
int chained_string: @chained_string ref,
int index: int ref,
unique int string__: @string__ ref
unique int child: @string__ ref
);
#keyset[parent, parent_index]
@@ -346,7 +373,7 @@ chained_string_def(
class_child(
int class: @class ref,
int index: int ref,
unique int class_child_type: @class_child_type ref
unique int child: @class_child_type ref
);
#keyset[parent, parent_index]
@@ -375,7 +402,7 @@ conditional_def(
destructured_left_assignment_child(
int destructured_left_assignment: @destructured_left_assignment ref,
int index: int ref,
unique int destructured_left_assignment_child_type: @destructured_left_assignment_child_type ref
unique int child: @destructured_left_assignment_child_type ref
);
#keyset[parent, parent_index]
@@ -392,7 +419,7 @@ destructured_left_assignment_def(
destructured_parameter_child(
int destructured_parameter: @destructured_parameter ref,
int index: int ref,
unique int destructured_parameter_child_type: @destructured_parameter_child_type ref
unique int child: @destructured_parameter_child_type ref
);
#keyset[parent, parent_index]
@@ -409,7 +436,7 @@ destructured_parameter_def(
do_child(
int do: @do ref,
int index: int ref,
unique int do_child_type: @do_child_type ref
unique int child: @do_child_type ref
);
#keyset[parent, parent_index]
@@ -422,7 +449,7 @@ do_def(
do_block_parameters(
unique int do_block: @do_block ref,
unique int block_parameters: @block_parameters ref
unique int parameters: @block_parameters ref
);
@do_block_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement
@@ -431,7 +458,7 @@ do_block_parameters(
do_block_child(
int do_block: @do_block ref,
int index: int ref,
unique int do_block_child_type: @do_block_child_type ref
unique int child: @do_block_child_type ref
);
#keyset[parent, parent_index]
@@ -448,7 +475,7 @@ do_block_def(
element_reference_child(
int element_reference: @element_reference ref,
int index: int ref,
unique int element_reference_child_type: @element_reference_child_type ref
unique int child: @element_reference_child_type ref
);
#keyset[parent, parent_index]
@@ -466,7 +493,7 @@ element_reference_def(
else_child(
int else: @else ref,
int index: int ref,
unique int else_child_type: @else_child_type ref
unique int child: @else_child_type ref
);
#keyset[parent, parent_index]
@@ -481,12 +508,12 @@ else_def(
elsif_alternative(
unique int elsif: @elsif ref,
unique int elsif_alternative_type: @elsif_alternative_type ref
unique int alternative: @elsif_alternative_type ref
);
elsif_consequence(
unique int elsif: @elsif ref,
unique int then: @then ref
unique int consequence: @then ref
);
#keyset[parent, parent_index]
@@ -504,7 +531,7 @@ elsif_def(
end_block_child(
int end_block: @end_block ref,
int index: int ref,
unique int end_block_child_type: @end_block_child_type ref
unique int child: @end_block_child_type ref
);
#keyset[parent, parent_index]
@@ -521,7 +548,7 @@ end_block_def(
ensure_child(
int ensure: @ensure ref,
int index: int ref,
unique int ensure_child_type: @ensure_child_type ref
unique int child: @ensure_child_type ref
);
#keyset[parent, parent_index]
@@ -547,7 +574,7 @@ exception_variable_def(
exceptions_child(
int exceptions: @exceptions ref,
int index: int ref,
unique int exceptions_child_type: @exceptions_child_type ref
unique int child: @exceptions_child_type ref
);
#keyset[parent, parent_index]
@@ -564,7 +591,7 @@ exceptions_def(
for_pattern(
int for: @for ref,
int index: int ref,
unique int for_pattern_type: @for_pattern_type ref
unique int pattern: @for_pattern_type ref
);
#keyset[parent, parent_index]
@@ -583,7 +610,7 @@ for_def(
hash_child(
int hash: @hash ref,
int index: int ref,
unique int hash_child_type: @hash_child_type ref
unique int child: @hash_child_type ref
);
#keyset[parent, parent_index]
@@ -605,7 +632,7 @@ hash_splat_argument_def(
hash_splat_parameter_name(
unique int hash_splat_parameter: @hash_splat_parameter ref,
unique int token_identifier: @token_identifier ref
unique int name: @token_identifier ref
);
#keyset[parent, parent_index]
@@ -622,7 +649,7 @@ hash_splat_parameter_def(
heredoc_body_child(
int heredoc_body: @heredoc_body ref,
int index: int ref,
unique int heredoc_body_child_type: @heredoc_body_child_type ref
unique int child: @heredoc_body_child_type ref
);
#keyset[parent, parent_index]
@@ -637,12 +664,12 @@ heredoc_body_def(
if_alternative(
unique int if: @if ref,
unique int if_alternative_type: @if_alternative_type ref
unique int alternative: @if_alternative_type ref
);
if_consequence(
unique int if: @if ref,
unique int then: @then ref
unique int consequence: @then ref
);
#keyset[parent, parent_index]
@@ -686,7 +713,7 @@ interpolation_def(
keyword_parameter_value(
unique int keyword_parameter: @keyword_parameter ref,
unique int underscore_arg: @underscore_arg ref
unique int value: @underscore_arg ref
);
#keyset[parent, parent_index]
@@ -702,7 +729,7 @@ keyword_parameter_def(
lambda_parameters(
unique int lambda: @lambda ref,
unique int lambda_parameters: @lambda_parameters ref
unique int parameters: @lambda_parameters ref
);
#keyset[parent, parent_index]
@@ -720,7 +747,7 @@ lambda_def(
lambda_parameters_child(
int lambda_parameters: @lambda_parameters ref,
int index: int ref,
unique int lambda_parameters_child_type: @lambda_parameters_child_type ref
unique int child: @lambda_parameters_child_type ref
);
#keyset[parent, parent_index]
@@ -737,7 +764,7 @@ lambda_parameters_def(
left_assignment_list_child(
int left_assignment_list: @left_assignment_list ref,
int index: int ref,
unique int left_assignment_list_child_type: @left_assignment_list_child_type ref
unique int child: @left_assignment_list_child_type ref
);
#keyset[parent, parent_index]
@@ -750,7 +777,7 @@ left_assignment_list_def(
method_parameters(
unique int method: @method ref,
unique int method_parameters: @method_parameters ref
unique int parameters: @method_parameters ref
);
@method_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement
@@ -759,7 +786,7 @@ method_parameters(
method_child(
int method: @method ref,
int index: int ref,
unique int method_child_type: @method_child_type ref
unique int child: @method_child_type ref
);
#keyset[parent, parent_index]
@@ -777,7 +804,7 @@ method_def(
method_parameters_child(
int method_parameters: @method_parameters ref,
int index: int ref,
unique int method_parameters_child_type: @method_parameters_child_type ref
unique int child: @method_parameters_child_type ref
);
#keyset[parent, parent_index]
@@ -796,7 +823,7 @@ method_parameters_def(
module_child(
int module: @module ref,
int index: int ref,
unique int module_child_type: @module_child_type ref
unique int child: @module_child_type ref
);
#keyset[parent, parent_index]
@@ -810,7 +837,7 @@ module_def(
next_child(
unique int next: @next ref,
unique int argument_list: @argument_list ref
unique int child: @argument_list ref
);
#keyset[parent, parent_index]
@@ -821,7 +848,22 @@ next_def(
int loc: @location ref
);
@operator_assignment_operator_type = @reserved_word
case @operator_assignment.operator of
0 = @operator_assignment_percentequal
| 1 = @operator_assignment_ampersandampersandequal
| 2 = @operator_assignment_ampersandequal
| 3 = @operator_assignment_starstarequal
| 4 = @operator_assignment_starequal
| 5 = @operator_assignment_plusequal
| 6 = @operator_assignment_minusequal
| 7 = @operator_assignment_slashequal
| 8 = @operator_assignment_langlelangleequal
| 9 = @operator_assignment_ranglerangleequal
| 10 = @operator_assignment_caretequal
| 11 = @operator_assignment_pipeequal
| 12 = @operator_assignment_pipepipeequal
;
@operator_assignment_right_type = @break | @call | @next | @return | @underscore_arg | @yield
@@ -831,7 +873,7 @@ operator_assignment_def(
int parent: @ast_node_parent ref,
int parent_index: int ref,
int left: @underscore_lhs ref,
int operator: @operator_assignment_operator_type ref,
int operator: int ref,
int right: @operator_assignment_right_type ref,
int loc: @location ref
);
@@ -864,7 +906,7 @@ pair_def(
parenthesized_statements_child(
int parenthesized_statements: @parenthesized_statements ref,
int index: int ref,
unique int parenthesized_statements_child_type: @parenthesized_statements_child_type ref
unique int child: @parenthesized_statements_child_type ref
);
#keyset[parent, parent_index]
@@ -892,7 +934,7 @@ pattern_def(
program_child(
int program: @program ref,
int index: int ref,
unique int program_child_type: @program_child_type ref
unique int child: @program_child_type ref
);
#keyset[parent, parent_index]
@@ -907,7 +949,7 @@ program_def(
range_child(
int range: @range ref,
int index: int ref,
unique int underscore_arg: @underscore_arg ref
unique int child: @underscore_arg ref
);
#keyset[parent, parent_index]
@@ -931,7 +973,7 @@ rational_def(
redo_child(
unique int redo: @redo ref,
unique int argument_list: @argument_list ref
unique int child: @argument_list ref
);
#keyset[parent, parent_index]
@@ -948,7 +990,7 @@ redo_def(
regex_child(
int regex: @regex ref,
int index: int ref,
unique int regex_child_type: @regex_child_type ref
unique int child: @regex_child_type ref
);
#keyset[parent, parent_index]
@@ -961,7 +1003,7 @@ regex_def(
rescue_body(
unique int rescue: @rescue ref,
unique int then: @then ref
unique int body: @then ref
);
rescue_exceptions(
@@ -971,7 +1013,7 @@ rescue_exceptions(
rescue_variable(
unique int rescue: @rescue ref,
unique int exception_variable: @exception_variable ref
unique int variable: @exception_variable ref
);
#keyset[parent, parent_index]
@@ -996,7 +1038,7 @@ rescue_modifier_def(
rest_assignment_child(
unique int rest_assignment: @rest_assignment ref,
unique int underscore_lhs: @underscore_lhs ref
unique int child: @underscore_lhs ref
);
#keyset[parent, parent_index]
@@ -1009,7 +1051,7 @@ rest_assignment_def(
retry_child(
unique int retry: @retry ref,
unique int argument_list: @argument_list ref
unique int child: @argument_list ref
);
#keyset[parent, parent_index]
@@ -1022,7 +1064,7 @@ retry_def(
return_child(
unique int return: @return ref,
unique int argument_list: @argument_list ref
unique int child: @argument_list ref
);
#keyset[parent, parent_index]
@@ -1039,7 +1081,7 @@ return_def(
right_assignment_list_child(
int right_assignment_list: @right_assignment_list ref,
int index: int ref,
unique int right_assignment_list_child_type: @right_assignment_list_child_type ref
unique int child: @right_assignment_list_child_type ref
);
#keyset[parent, parent_index]
@@ -1054,7 +1096,7 @@ right_assignment_list_def(
scope_resolution_scope(
unique int scope_resolution: @scope_resolution ref,
unique int underscore_primary: @underscore_primary ref
unique int scope: @underscore_primary ref
);
#keyset[parent, parent_index]
@@ -1081,7 +1123,7 @@ setter_def(
singleton_class_child(
int singleton_class: @singleton_class ref,
int index: int ref,
unique int singleton_class_child_type: @singleton_class_child_type ref
unique int child: @singleton_class_child_type ref
);
#keyset[parent, parent_index]
@@ -1097,7 +1139,7 @@ singleton_class_def(
singleton_method_parameters(
unique int singleton_method: @singleton_method ref,
unique int method_parameters: @method_parameters ref
unique int parameters: @method_parameters ref
);
@singleton_method_child_type = @else | @ensure | @rescue | @token_empty_statement | @underscore_statement
@@ -1106,7 +1148,7 @@ singleton_method_parameters(
singleton_method_child(
int singleton_method: @singleton_method ref,
int index: int ref,
unique int singleton_method_child_type: @singleton_method_child_type ref
unique int child: @singleton_method_child_type ref
);
#keyset[parent, parent_index]
@@ -1130,7 +1172,7 @@ splat_argument_def(
splat_parameter_name(
unique int splat_parameter: @splat_parameter ref,
unique int token_identifier: @token_identifier ref
unique int name: @token_identifier ref
);
#keyset[parent, parent_index]
@@ -1147,7 +1189,7 @@ splat_parameter_def(
string_child(
int string__: @string__ ref,
int index: int ref,
unique int string_child_type: @string_child_type ref
unique int child: @string_child_type ref
);
#keyset[parent, parent_index]
@@ -1162,7 +1204,7 @@ string_def(
string_array_child(
int string_array: @string_array ref,
int index: int ref,
unique int bare_string: @bare_string ref
unique int child: @bare_string ref
);
#keyset[parent, parent_index]
@@ -1179,7 +1221,7 @@ string_array_def(
subshell_child(
int subshell: @subshell ref,
int index: int ref,
unique int subshell_child_type: @subshell_child_type ref
unique int child: @subshell_child_type ref
);
#keyset[parent, parent_index]
@@ -1207,7 +1249,7 @@ superclass_def(
symbol_child(
int symbol: @symbol ref,
int index: int ref,
unique int symbol_child_type: @symbol_child_type ref
unique int child: @symbol_child_type ref
);
#keyset[parent, parent_index]
@@ -1222,7 +1264,7 @@ symbol_def(
symbol_array_child(
int symbol_array: @symbol_array ref,
int index: int ref,
unique int bare_symbol: @bare_symbol ref
unique int child: @bare_symbol ref
);
#keyset[parent, parent_index]
@@ -1239,7 +1281,7 @@ symbol_array_def(
then_child(
int then: @then ref,
int index: int ref,
unique int then_child_type: @then_child_type ref
unique int child: @then_child_type ref
);
#keyset[parent, parent_index]
@@ -1252,7 +1294,15 @@ then_def(
@unary_operand_type = @break | @call | @next | @parenthesized_statements | @return | @token_float | @token_integer | @underscore_arg | @yield
@unary_operator_type = @reserved_word
case @unary.operator of
0 = @unary_bang
| 1 = @unary_plus
| 2 = @unary_minus
| 3 = @unary_definedquestion
| 4 = @unary_not
| 5 = @unary_tilde
;
#keyset[parent, parent_index]
unary_def(
@@ -1260,7 +1310,7 @@ unary_def(
int parent: @ast_node_parent ref,
int parent_index: int ref,
int operand: @unary_operand_type ref,
int operator: @unary_operator_type ref,
int operator: int ref,
int loc: @location ref
);
@@ -1268,7 +1318,7 @@ unary_def(
undef_child(
int undef: @undef ref,
int index: int ref,
unique int underscore_method_name: @underscore_method_name ref
unique int child: @underscore_method_name ref
);
#keyset[parent, parent_index]
@@ -1283,12 +1333,12 @@ undef_def(
unless_alternative(
unique int unless: @unless ref,
unique int unless_alternative_type: @unless_alternative_type ref
unique int alternative: @unless_alternative_type ref
);
unless_consequence(
unique int unless: @unless ref,
unique int then: @then ref
unique int consequence: @then ref
);
#keyset[parent, parent_index]
@@ -1336,7 +1386,7 @@ until_modifier_def(
when_body(
unique int when: @when ref,
unique int then: @then ref
unique int body: @then ref
);
#keyset[when, index]
@@ -1378,7 +1428,7 @@ while_modifier_def(
yield_child(
unique int yield: @yield ref,
unique int argument_list: @argument_list ref
unique int child: @argument_list ref
);
#keyset[parent, parent_index]

File diff suppressed because it is too large Load Diff