Backed out 14 changesets (bug 1552435) for build bustages on BinASTTokenReaderContext.h. CLOSED TREE

Backed out changeset 8448b970f048 (bug 1552435)
Backed out changeset eaaa17bd90a9 (bug 1552435)
Backed out changeset daa12d2a51ee (bug 1552435)
Backed out changeset ccb6154c8a13 (bug 1552435)
Backed out changeset 3c6703c6ca2c (bug 1552435)
Backed out changeset 0e5b05913043 (bug 1552435)
Backed out changeset 41513cb59f37 (bug 1552435)
Backed out changeset cf5514fae884 (bug 1552435)
Backed out changeset b59bf910f2e9 (bug 1552435)
Backed out changeset 80fff56c7c49 (bug 1552435)
Backed out changeset 27bf02f8977e (bug 1552435)
Backed out changeset 8e09ad83b99b (bug 1552435)
Backed out changeset 8547fb9394eb (bug 1552435)
Backed out changeset 1e4c1b283ba3 (bug 1552435)
This commit is contained in:
Brindusan Cristian 2019-06-11 17:33:06 +03:00
parent b0520cb367
commit ad63669f20
6 changed files with 314 additions and 3052 deletions

2
Cargo.lock generated
View File

@ -219,7 +219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "binast"
version = "0.2.0"
version = "0.1.1"
dependencies = [
"Inflector 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"binjs_meta 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -37,196 +37,6 @@ namespace frontend {
class ErrorReporter;
// The format treats several distinct models as the same.
//
// We use `NormalizedInterfaceAndField` as a proxy for `BinASTInterfaceAndField`
// to ensure that we always normalize into the canonical model.
struct NormalizedInterfaceAndField {
const BinASTInterfaceAndField identity;
explicit NormalizedInterfaceAndField(BinASTInterfaceAndField identity)
: identity(identity == BinASTInterfaceAndField::
StaticMemberAssignmentTarget__Property
? BinASTInterfaceAndField::StaticMemberExpression__Property
: identity) {}
};
// An entry in a Huffman table.
template <typename T>
struct HuffmanEntry {
HuffmanEntry(uint32_t bits, uint8_t bits_length, T&& value)
: bits(bits), bits_length(bits_length), value(value) {
MOZ_ASSERT(bits >> bits_len == 0);
}
// Together, `bits` and `bits_length` represent the prefix for this entry
// in the Huffman table.
//
// This entry matches a candidate `c` iff `c.bits_length == bits_length`
// and `c.bits << (32 - c.bits_len) == bits << (32 - bits_len)`.
//
// Invariant: the first `32 - bits_len` bits are always 0.
const uint32_t bits;
const uint8_t bits_length;
const T value;
};
// The default inline buffer length for instances of HuffmanTable.
// Specific type (e.g. booleans) will override this to provide something
// more suited to their type.
const size_t HUFFMAN_TABLE_DEFAULT_INLINE_BUFFER_LENGTH = 8;
// A flag that determines only whether a value is `null`.
// Used for optional interface.
enum class Nullable {
Null,
NonNull,
};
template <typename T, int N = HUFFMAN_TABLE_DEFAULT_INLINE_BUFFER_LENGTH>
class HuffmanTableImpl {
public:
explicit HuffmanTableImpl(JSContext* cx) : values(cx) {}
HuffmanTableImpl(HuffmanTableImpl&& other) noexcept
: values(std::move(other.values)) {}
// Initialize a Huffman table containing a single value.
JS::Result<Ok> initWithSingleValue(JSContext* cx, T&& value);
// Initialize a Huffman table containing `numberOfSymbols`.
// Symbols must be added with `addSymbol`.
JS::Result<Ok> init(JSContext* cx, size_t numberOfSymbols);
// Add a symbol to a value.
JS::Result<Ok> addSymbol(uint32_t bits, uint8_t bits_length, T&& value);
HuffmanTableImpl() = delete;
HuffmanTableImpl(HuffmanTableImpl&) = delete;
size_t length() const { return values.length(); }
const HuffmanEntry<T>* begin() const { return values.begin(); }
const HuffmanEntry<T>* end() const { return values.end(); }
private:
// The entries in this Huffman table.
// Entries are always ranked by increasing bit_length, and within
// a bitlength by increasing value of `bits`. This lets us implement
// `HuffmanTableImpl::next()` in `O(number_of_bits)` worst case time.
Vector<HuffmanEntry<T>, N> values;
friend class HuffmanPreludeReader;
};
// An empty Huffman table. Attempting to get a value from this table is an
// error. This is the default value for `HuffmanTable` and represents all states
// that may not be reached.
//
// Part of variant `HuffmanTable`.
struct HuffmanTableUnreachable {};
// --- Explicit instantiations of `HuffmanTableImpl`.
// These classes are all parts of variant `HuffmanTable`.
struct HuffmanTableExplicitSymbolsF64 {
HuffmanTableImpl<double> impl;
HuffmanTableExplicitSymbolsF64(JSContext* cx) : impl(cx) {}
};
struct HuffmanTableExplicitSymbolsU32 {
HuffmanTableImpl<uint32_t> impl;
};
struct HuffmanTableIndexedSymbolsSum {
HuffmanTableImpl<BinASTKind> impl;
HuffmanTableIndexedSymbolsSum(JSContext* cx) : impl(cx) {}
};
struct HuffmanTableIndexedSymbolsBool {
HuffmanTableImpl<bool, 2> impl;
HuffmanTableIndexedSymbolsBool(JSContext* cx) : impl(cx) {}
};
struct HuffmanTableIndexedSymbolsMaybeInterface {
HuffmanTableImpl<Nullable, 2> impl;
HuffmanTableIndexedSymbolsMaybeInterface(JSContext* cx) : impl(cx) {}
// `true` if this table only contains values for `null`.
bool isAlwaysNull() const {
MOZ_ASSERT(impl.length() > 0);
// By definition, we have either 1 or 2 values.
// By definition, if we have 2 values, one of them is not null.
if (impl.length() != 1) {
return false;
}
// Otherwise, check the single value.
return impl.begin()->value == Nullable::Null;
}
};
struct HuffmanTableIndexedSymbolsStringEnum {
HuffmanTableImpl<BinASTVariant> impl;
HuffmanTableIndexedSymbolsStringEnum(JSContext* cx) : impl(cx) {}
};
struct HuffmanTableIndexedSymbolsLiteralString {
HuffmanTableImpl<JSAtom*> impl;
HuffmanTableIndexedSymbolsLiteralString(JSContext* cx) : impl(cx) {}
};
struct HuffmanTableIndexedSymbolsOptionalLiteralString {
HuffmanTableImpl<JSAtom*> impl;
HuffmanTableIndexedSymbolsOptionalLiteralString(JSContext* cx) : impl(cx) {}
};
// A single Huffman table.
using HuffmanTable = mozilla::Variant<
HuffmanTableUnreachable, // Default value.
HuffmanTableExplicitSymbolsF64, HuffmanTableExplicitSymbolsU32,
HuffmanTableIndexedSymbolsSum, HuffmanTableIndexedSymbolsMaybeInterface,
HuffmanTableIndexedSymbolsBool, HuffmanTableIndexedSymbolsStringEnum,
HuffmanTableIndexedSymbolsLiteralString,
HuffmanTableIndexedSymbolsOptionalLiteralString>;
struct HuffmanTableExplicitSymbolsListLength {
HuffmanTableImpl<uint32_t> impl;
HuffmanTableExplicitSymbolsListLength(JSContext* cx) : impl(cx) {}
};
// A single Huffman table, specialized for list lengths.
using HuffmanTableListLength =
mozilla::Variant<HuffmanTableUnreachable, // Default value.
HuffmanTableExplicitSymbolsListLength>;
// A Huffman dictionary for the current file.
//
// A Huffman dictionary consists in a (contiguous) set of Huffman tables
// to predict field values and a second (contiguous) set of Huffman tables
// to predict list lengths.
class HuffmanDictionary {
public:
explicit HuffmanDictionary(JSContext* cx) : fields(cx), listLengths(cx) {}
HuffmanTable& tableForField(NormalizedInterfaceAndField index);
HuffmanTableListLength& tableForListLength(BinASTList list);
private:
// Huffman tables for `(Interface, Field)` pairs, used to decode the value of
// `Interface::Field`. Some tables may be `HuffmanTableUnreacheable`
// if they represent fields of interfaces that actually do not show up
// in the file.
//
// The mapping from `(Interface, Field) -> index` is extracted statically from
// the webidl specs.
Vector<HuffmanTable, BINAST_INTERFACE_AND_FIELD_LIMIT> fields;
// Huffman tables for list lengths. Some tables may be
// `HuffmanTableUnreacheable` if they represent lists that actually do not
// show up in the file.
//
// The mapping from `List -> index` is extracted statically from the webidl
// specs.
Vector<HuffmanTableListLength, BINAST_NUMBER_OF_LIST_TYPES> listLengths;
};
/**
* A token reader implementing the "context" serialization format for BinAST.
*
@ -337,15 +147,10 @@ class MOZ_STACK_CLASS BinASTTokenReaderContext : public BinASTTokenReaderBase {
MOZ_MUST_USE JS::Result<Ok> readHeader();
/**
* Read the string dictionary from the header of the file.
* Read the string dictionary of the header of the file.
*/
MOZ_MUST_USE JS::Result<Ok> readStringPrelude();
/**
* Read the huffman dictionary from the header of the file.
*/
MOZ_MUST_USE JS::Result<Ok> readHuffmanPrelude();
// --- Primitive values.
//
// Note that the underlying format allows for a `null` value for primitive
@ -475,8 +280,6 @@ class MOZ_STACK_CLASS BinASTTokenReaderContext : public BinASTTokenReaderBase {
MetadataOwnership metadataOwned_ = MetadataOwnership::Owned;
BinASTSourceMetadata* metadata_;
class HuffmanDictionary dictionary;
const uint8_t* posBeforeTree_;
BrotliDecoderState* decoder_ = nullptr;
@ -491,11 +294,6 @@ class MOZ_STACK_CLASS BinASTTokenReaderContext : public BinASTTokenReaderBase {
BinASTSourceMetadata* takeMetadata();
MOZ_MUST_USE JS::Result<Ok> initFromScriptSource(ScriptSource* scriptSource);
protected:
friend class HuffmanPreludeReader;
JSContext* cx_;
public:
// The following classes are used whenever we encounter a tuple/tagged
// tuple/list to make sure that:

View File

@ -1,6 +1,6 @@
[package]
name = "binast"
version = "0.2.0"
version = "0.1.1"
authors = ["David Teller <D.O.Teller@gmail.com>"]
autobins = false

View File

@ -15,7 +15,6 @@ mod refgraph;
use refgraph::{ ReferenceGraph };
use std::borrow::Cow;
use std::collections::{ HashMap, HashSet };
use std::fs::*;
use std::io::{ Read, Write };
@ -602,10 +601,6 @@ impl CPPExporter {
let content_node_name = syntax.get_node_name(&content_name)
.unwrap_or_else(|| panic!("While generating an array parser, could not find node name {}", content_name))
.clone();
debug!(target: "generate_spidermonkey", "CPPExporter::new adding list typedef {:?} => {:?} => {:?}",
parser_node_name,
content_name,
content_node_name);
list_parsers_to_generate.push(ListParserData {
name: parser_node_name.clone(),
supports_empty: *supports_empty,
@ -958,97 +953,6 @@ impl CPPExporter {
}
}
/// Auxiliary function: get a name for a field type.
fn get_field_type_name(typedef: Option<&str>, spec: &Spec, type_: &Type, make_optional: bool) -> Cow<'static, str> {
let optional = make_optional || type_.is_optional();
match *type_.spec() {
TypeSpec::Boolean if optional => Cow::from("PRIMITIVE(MaybeBoolean)"),
TypeSpec::Boolean => Cow::from("PRIMITIVE(Boolean)"),
TypeSpec::String if optional => Cow::from("PRIMITIVE(MaybeString)"),
TypeSpec::String => Cow::from("PRIMITIVE(String)"),
TypeSpec::Number if optional => Cow::from("PRIMITIVE(MaybeNumber)"),
TypeSpec::Number => Cow::from("PRIMITIVE(Number)"),
TypeSpec::UnsignedLong if optional => Cow::from("PRIMITIVE(MaybeUnsignedLong)"),
TypeSpec::UnsignedLong => Cow::from("PRIMITIVE(UnsignedLong)"),
TypeSpec::Offset if optional => Cow::from("PRIMITIVE(MaybeLazy)"),
TypeSpec::Offset => Cow::from("PRIMITIVE(Lazy)"),
TypeSpec::Void if optional => Cow::from("PRIMITIVE(MaybeVoid)"),
TypeSpec::Void => Cow::from("PRIMITIVE(Void)"),
TypeSpec::IdentifierName if optional => Cow::from("PRIMITIVE(MaybeIdentifierName)"),
TypeSpec::IdentifierName => Cow::from("PRIMITIVE(IdentifierName)"),
TypeSpec::PropertyKey if optional => Cow::from("PRIMITIVE(MaybePropertyKey)"),
TypeSpec::PropertyKey => Cow::from("PRIMITIVE(PropertyKey)"),
TypeSpec::Array { ref contents, .. } => Cow::from(
format!("LIST({name}, {contents})",
name = if let Some(name) = typedef {
name.to_string()
} else {
TypeName::type_(type_)
},
contents = Self::get_field_type_name(None, spec, contents, false)
)),
TypeSpec::NamedType(ref name) => {
debug!(target: "generate_spidermonkey", "get_field_type_name for named type {name} ({optional})",
name = name,
optional = if optional { "optional" } else { "required" });
match spec.get_type_by_name(name).expect("By now, all types MUST exist") {
NamedType::Typedef(alias_type) => {
if alias_type.is_optional() {
return Self::get_field_type_name(Some(name.to_str()), spec, alias_type.as_ref(), true)
}
// Keep the simple name of sums and lists if there is one.
match *alias_type.spec() {
TypeSpec::TypeSum(_) => {
if optional {
Cow::from(format!("OPTIONAL_SUM({name})", name = name.to_cpp_enum_case()))
} else {
Cow::from(format!("SUM({name})", name = name.to_cpp_enum_case()))
}
}
TypeSpec::Array { ref contents, .. } => {
debug!(target: "generate_spidermonkey", "It's an array {:?}", contents);
let contents = TypeName::type_(contents);
if optional {
Cow::from(format!("OPTIONAL_LIST({name}, {contents})",
name = name.to_cpp_enum_case(),
contents = contents))
} else {
Cow::from(format!("LIST({name}, {contents})",
name = name.to_cpp_enum_case(),
contents = contents))
}
}
_ => {
Self::get_field_type_name(Some(name.to_str()), spec, alias_type.as_ref(), optional)
}
}
}
NamedType::StringEnum(_) if type_.is_optional() => Cow::from(
format!("OPTIONAL_STRING_ENUM({name})",
name = TypeName::type_(type_))),
NamedType::StringEnum(_) => Cow::from(
format!("STRING_ENUM({name})",
name = TypeName::type_(type_))),
NamedType::Interface(ref interface) if type_.is_optional() => Cow::from(
format!("OPTIONAL_INTERFACE({name})",
name = interface.name().to_class_cases())),
NamedType::Interface(ref interface) => Cow::from(
format!("INTERFACE({name})",
name = interface.name().to_class_cases())),
}
}
TypeSpec::TypeSum(ref contents) if type_.is_optional() => {
// We need to make sure that we don't count the `optional` part twice.
// FIXME: The problem seems to only show up in this branch, but it looks like
// it might (should?) appear in other branches, too.
let non_optional_type = Type::sum(contents.types()).required();
let name = TypeName::type_(&non_optional_type);
Cow::from(format!("OPTIONAL_SUM({name})", name = name))
}
TypeSpec::TypeSum(_) => Cow::from(format!("SUM({name})", name = TypeName::type_(type_))),
}
}
/// Declaring enums for kinds and fields.
fn export_declare_kinds_and_fields_enums(&self, buffer: &mut String) {
buffer.push_str(&self.rules.hpp_tokens_header.reindent(""));
@ -1132,45 +1036,6 @@ enum class BinASTInterfaceAndField: uint16_t {
};
");
for (sum_name, sum) in self.syntax.resolved_sums_of_interfaces_by_name()
.iter()
.sorted_by_key(|a| a.0)
{
let sum_enum_name = sum_name.to_cpp_enum_case();
let sum_macro_name = sum_name.to_cpp_macro_case();
buffer.push_str(&format!("
// Iteration through the interfaces of sum {sum_enum_name}
#define FOR_EACH_BIN_INTERFACE_IN_SUM_{sum_macro_name}(F) \\
{nodes}
const size_t BINAST_SUM_{sum_macro_name}_LIMIT = {limit};
",
sum_enum_name = sum_enum_name.clone(),
sum_macro_name = sum_macro_name,
limit = sum.len(),
nodes = sum.iter()
.sorted()
.into_iter()
.enumerate()
.map(move |(i, interface_name)| {
let interface_macro_name = interface_name.to_cpp_macro_case();
let interface_enum_name = interface_name.to_cpp_enum_case();
format!(" F({sum_enum_name}, {index}, {interface_enum_name}, {interface_macro_name}, \"{sum_spec_name}::{interface_spec_name}\")",
sum_enum_name = sum_enum_name,
index = i,
interface_enum_name = interface_enum_name,
interface_macro_name = interface_macro_name,
sum_spec_name = sum_name,
interface_spec_name = interface_name,
)
})
.format(" \\\n")));
}
buffer.push_str("
// Strongly typed iterations through the fields of interfaces.
//
@ -1189,6 +1054,7 @@ const size_t BINAST_SUM_{sum_macro_name}_LIMIT = {limit};
// `typename` is the name of the string enum (e.g. no `Maybe` prefix)
");
for (interface_name, interface) in self.syntax.interfaces_by_name().iter().sorted_by_key(|a| a.0) {
use std::borrow::Cow;
let interface_enum_name = interface_name.to_cpp_enum_case();
let interface_spec_name = interface_name.clone();
let interface_macro_name = interface.name().to_cpp_macro_case();
@ -1201,7 +1067,86 @@ const size_t BINAST_SUM_{sum_macro_name}_LIMIT = {limit};
.iter()
.enumerate()
.map(|(i, field)| {
let field_type_name = Self::get_field_type_name(None, &self.syntax, field.type_(), false);
fn get_field_type_name(spec: &Spec, type_: &Type, make_optional: bool) -> Cow<'static, str> {
let optional = make_optional || type_.is_optional();
match *type_.spec() {
TypeSpec::Boolean if optional => Cow::from("PRIMITIVE(MaybeBoolean)"),
TypeSpec::Boolean => Cow::from("PRIMITIVE(Boolean)"),
TypeSpec::String if optional => Cow::from("PRIMITIVE(MaybeString)"),
TypeSpec::String => Cow::from("PRIMITIVE(String)"),
TypeSpec::Number if optional => Cow::from("PRIMITIVE(MaybeNumber)"),
TypeSpec::Number => Cow::from("PRIMITIVE(Number)"),
TypeSpec::UnsignedLong if optional => Cow::from("PRIMITIVE(MaybeUnsignedLong)"),
TypeSpec::UnsignedLong => Cow::from("PRIMITIVE(UnsignedLong)"),
TypeSpec::Offset if optional => Cow::from("PRIMITIVE(MaybeLazy)"),
TypeSpec::Offset => Cow::from("PRIMITIVE(Lazy)"),
TypeSpec::Void if optional => Cow::from("PRIMITIVE(MaybeVoid)"),
TypeSpec::Void => Cow::from("PRIMITIVE(Void)"),
TypeSpec::IdentifierName if optional => Cow::from("PRIMITIVE(MaybeIdentifierName)"),
TypeSpec::IdentifierName => Cow::from("PRIMITIVE(IdentifierName)"),
TypeSpec::PropertyKey if optional => Cow::from("PRIMITIVE(MaybePropertyKey)"),
TypeSpec::PropertyKey => Cow::from("PRIMITIVE(PropertyKey)"),
TypeSpec::Array { ref contents, .. } => Cow::from(
format!("LIST({name}, {contents})",
name = TypeName::type_(type_),
contents = TypeName::type_(contents),
)),
TypeSpec::NamedType(ref name) => match spec.get_type_by_name(name).expect("By now, all types MUST exist") {
NamedType::Typedef(alias_type) => {
if alias_type.is_optional() {
return get_field_type_name(spec, alias_type.as_ref(), true)
}
// Keep the simple name of sums and lists if there is one.
match *alias_type.spec() {
TypeSpec::TypeSum(_) => {
if optional {
Cow::from(format!("OPTIONAL_SUM({name})", name = name.to_cpp_enum_case()))
} else {
Cow::from(format!("SUM({name})", name = name.to_cpp_enum_case()))
}
}
TypeSpec::Array { ref contents, .. } => {
let contents = TypeName::type_(contents);
if optional {
Cow::from(format!("OPTIONAL_LIST({name}, {contents})",
name = name.to_cpp_enum_case(),
contents = contents))
} else {
Cow::from(format!("LIST({name}, {contents})",
name = name.to_cpp_enum_case(),
contents = contents))
}
}
_ => {
get_field_type_name(spec, alias_type.as_ref(), optional)
}
}
}
NamedType::StringEnum(_) if type_.is_optional() => Cow::from(
format!("OPTIONAL_STRING_ENUM({name})",
name = TypeName::type_(type_))),
NamedType::StringEnum(_) => Cow::from(
format!("STRING_ENUM({name})",
name = TypeName::type_(type_))),
NamedType::Interface(ref interface) if type_.is_optional() => Cow::from(
format!("OPTIONAL_INTERFACE({name})",
name = interface.name().to_class_cases())),
NamedType::Interface(ref interface) => Cow::from(
format!("INTERFACE({name})",
name = interface.name().to_class_cases())),
}
TypeSpec::TypeSum(ref contents) if type_.is_optional() => {
// We need to make sure that we don't count the `optional` part twice.
// FIXME: The problem seems to only show up in this branch, but it looks like
// it might (should?) appear in other branches, too.
let non_optional_type = Type::sum(contents.types()).required();
let name = TypeName::type_(&non_optional_type);
Cow::from(format!("OPTIONAL_SUM({name})", name = name))
}
TypeSpec::TypeSum(_) => Cow::from(format!("SUM({name})", name = TypeName::type_(type_))),
}
}
let field_type_name = get_field_type_name(&self.syntax, field.type_(), false);
format!(" F({interface_enum_name}, {field_enum_name}, {field_index}, {field_type}, \"{interface_spec_name}::{field_spec_name}\")",
interface_enum_name = interface_enum_name,
field_enum_name = field.name().to_cpp_enum_case(),
@ -1260,15 +1205,14 @@ enum class BinASTVariant: uint16_t {
.keys()
.sorted()
.into_iter()
.map(|name| format!(" F({enum_name}, \"{spec_name}\", {macro_name})",
.map(|name| format!(" F({enum_name}, \"{spec_name}\")",
enum_name = name.to_cpp_enum_case(),
spec_name = name.to_str(),
macro_name = name.to_cpp_macro_case()))
spec_name = name.to_str()))
.format(" \\\n")));
buffer.push_str("
enum class BinASTStringEnum: uint16_t {
#define EMIT_ENUM(NAME, _HUMAN_NAME, _MACRO_NAME) NAME,
#define EMIT_ENUM(name, _) name,
FOR_EACH_BIN_STRING_ENUM(EMIT_ENUM)
#undef EMIT_ENUM
};
@ -1276,69 +1220,20 @@ enum class BinASTStringEnum: uint16_t {
buffer.push_str(&format!("\n// The number of distinct values of BinASTStringEnum.\nconst size_t BINASTSTRINGENUM_LIMIT = {};\n\n\n",
self.syntax.string_enums_by_name().len()));
for (name, enum_) in self.syntax.string_enums_by_name()
.iter()
.sorted_by_key(|kv| kv.0)
.into_iter()
{
let enum_name = name.to_str().to_class_cases();
let enum_macro_name = name.to_cpp_macro_case();
buffer.push_str(&format!("\n#define FOR_EACH_BIN_VARIANT_IN_STRING_ENUM_{enum_macro_name}_BY_STRING_ORDER(F) \\\n {variants}\n",
enum_macro_name = enum_macro_name,
variants = enum_.strings()
.iter()
.sorted()
.into_iter()
.map(|variant_string| {
format!(" F({enum_name}, {variant_name}, \"{variant_string}\")",
enum_name = enum_name,
variant_name = self.variants_by_symbol.get(variant_string).unwrap(),
variant_string = variant_string
)
})
.format("\\\n")
));
buffer.push_str(&format!("\nconst size_t BIN_AST_STRING_ENUM_{enum_macro_name}_LIMIT = {len};\n\n\n",
enum_macro_name = enum_macro_name,
len = enum_.strings().len(),
));
}
buffer.push_str(&format!("
// This macro accepts the following arguments:
// - F: callback
// - PRIMITIVE: wrapper for primitive type names - called as `PRIMITIVE(typename)`
// - INTERFACE: wrapper for non-optional interface type names - called as `INTERFACE(typename)`
// - OPTIONAL_INTERFACE: wrapper for optional interface type names - called as `OPTIONAL_INTERFACE(typename)` where
// `typename` is the name of the interface (e.g. no `Maybe` prefix)
// - LIST: wrapper for list types - called as `LIST(list_typename, element_typename)`
// - SUM: wrapper for non-optional type names - called as `SUM(typename)`
// - OPTIONAL_SUM: wrapper for optional sum type names - called as `OPTIONAL_SUM(typename)` where
// `typename` is the name of the sum (e.g. no `Maybe` prefix)
// - STRING_ENUM: wrapper for non-optional string enum types - called as `STRING_ENUNM(typename)`
// - OPTIONAL_STRING_ENUM: wrapper for optional string enum type names - called as `OPTIONAL_STRING_ENUM(typename)` where
// `typename` is the name of the string enum (e.g. no `Maybe` prefix)
#define FOR_EACH_BIN_LIST(F, PRIMITIVE, INTERFACE, OPTIONAL_INTERFACE, LIST, SUM, OPTIONAL_SUM, STRING_ENUM, OPTIONAL_STRING_ENUM) \\\n{nodes}\n",
buffer.push_str(&format!("\n#define FOR_EACH_BIN_LIST(F) \\\n{nodes}\n",
nodes = self.list_parsers_to_generate.iter()
.sorted_by_key(|data| &data.name)
.into_iter()
.map(|data| {
debug!(target: "generate_spidermonkey", "Generating FOR_EACH_BIN_LIST case {list_name}", list_name = data.name);
format!(" F({list_name}, {content_name}, \"{spec_name}\", {type_name})",
list_name = data.name.to_cpp_enum_case(),
content_name = data.elements.to_cpp_enum_case(),
spec_name = data.name.to_str(),
type_name = Self::get_field_type_name(Some(data.name.to_str()), &self.syntax, self.syntax.typedefs_by_name().get(&data.name).unwrap(), false))
})
.map(|data| format!(" F({list_name}, {content_name}, \"{spec_name}\")",
list_name = data.name.to_cpp_enum_case(),
content_name = data.elements.to_cpp_enum_case(),
spec_name = data.name.to_str()))
.format(" \\\n")));
buffer.push_str("
enum class BinASTList: uint16_t {
#define NOTHING(_)
#define EMIT_ENUM(name, _content, _user, _type_name) name,
FOR_EACH_BIN_LIST(EMIT_ENUM, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING, NOTHING)
#define EMIT_ENUM(name, _content, _user) name,
FOR_EACH_BIN_LIST(EMIT_ENUM)
#undef EMIT_ENUM
#undef NOTHING
};
");
buffer.push_str(&format!("\n// The number of distinct list types in the grammar. Used typically to maintain a probability table per list type.\nconst size_t BINAST_NUMBER_OF_LIST_TYPES = {};\n\n\n", self.list_parsers_to_generate.len()));
@ -1346,27 +1241,22 @@ enum class BinASTList: uint16_t {
buffer.push_str(&format!("\n#define FOR_EACH_BIN_SUM(F) \\\n{nodes}\n",
nodes = self.syntax.resolved_sums_of_interfaces_by_name()
.iter()
.sorted_by_key(|a| a.0)
.sorted_by(|a, b| a.0.cmp(&b.0))
.into_iter()
.map(|(name, _)| format!(" F({name}, \"{spec_name}\", {macro_name}, {type_name})",
.map(|(name, _)| format!(" F({name}, \"{spec_name}\")",
name = name.to_cpp_enum_case(),
spec_name = name.to_str(),
macro_name = name.to_cpp_macro_case(),
type_name = Self::get_field_type_name(Some(name.to_str()), &self.syntax, self.syntax.typedefs_by_name().get(name).unwrap(), false)))
spec_name = name.to_str()))
.format(" \\\n")));
buffer.push_str("
enum class BinASTSum: uint16_t {
#define EMIT_ENUM(name, _user, _macro, _type) name,
#define EMIT_ENUM(name, _user) name,
FOR_EACH_BIN_SUM(EMIT_ENUM)
#undef EMIT_ENUM
};
");
buffer.push_str(&format!("\n// The number of distinct sum types in the grammar. Used typically to maintain a probability table per sum type.\nconst size_t BINAST_NUMBER_OF_SUM_TYPES = {};\n\n\n",
self.syntax.resolved_sums_of_interfaces_by_name().len()));
buffer.push_str(&self.rules.hpp_tokens_footer.reindent(""));
buffer.push_str("\n");
}
/// Declare string enums