Bug 1472103 - Part 1.1: Result of mach vendor rust. r=me

This commit is contained in:
Tooru Fujisawa 2018-09-14 01:56:07 +09:00
parent 63240b4b60
commit 37c4b7c0dc
6 changed files with 119 additions and 74 deletions

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"e32d2641e2dcfeda5cd201df66d5910e5e37fb59b2bc84e82dbf14b53dcb52f1","README.md":"17e5ed3a3bd9b898e73c3056711daabe1238fe9682d24d255f8263fae4eb783d","examples/generate_spidermonkey.rs":"a831abf8d7a1ab73c5d70a9e8517b8af1df492589a2f180698145ac5d46d7102","src/export.rs":"dba92bc4864178b0265e954334303e156827edb9585ce0640ac866c0aff0c9f4","src/import.rs":"50c9e2a399286f0bd86e5fef9f1c8968564cb1db75a86a7472f2f59fd17247d3","src/lib.rs":"d4ea18ec850054a817c6b91ed52412a2f2f39639628e5918dee688d829d3ed4b","src/spec.rs":"15a22ecea4dc3473e34c6cfe121e95edb1a83cfa5e264245e10d19f68456ac72","src/util.rs":"1d934eec75d9dee44289f9a9a9e67c96dd6205367430b9bcf9fc66e730bf6eb0"},"package":"fd7ca5635f1c6f94aaef7de76cb834c5920578355ce41dbcaf731b7ebe348518"}
{"files":{".cargo_vcs_info.json":"5a666f68ab005317d058d78c58936ebf66086a242f6a4b8415230649bbce768d","Cargo.toml":"04c87832069d5462b4b87c935fa448213e00a804fcf827334a02beda1fd7f971","README.md":"17e5ed3a3bd9b898e73c3056711daabe1238fe9682d24d255f8263fae4eb783d","examples/generate_spidermonkey.rs":"a831abf8d7a1ab73c5d70a9e8517b8af1df492589a2f180698145ac5d46d7102","src/export.rs":"e889c2f45f00c1787e2270a50fc6d9628446d620c3c0d2ac6ba3f031c561197d","src/import.rs":"7a8525aa55ff0c6c266edfb69a351345ab0c36176deeb0fb91901d4a4e6bd9d6","src/lib.rs":"d4ea18ec850054a817c6b91ed52412a2f2f39639628e5918dee688d829d3ed4b","src/spec.rs":"8f442a5d218360681ad3a5b4c4740b7ae227e087eb745df38cca07a88d8484c4","src/util.rs":"1d934eec75d9dee44289f9a9a9e67c96dd6205367430b9bcf9fc66e730bf6eb0"},"package":"cc0956bac41c458cf38340699dbb54c2220c91cdbfa33be19670fe69e0a6ac9b"}

View File

@ -0,0 +1,5 @@
{
"git": {
"sha1": "4c24254cdcfba7a929573f34e5ac12686a86bb60"
}
}

View File

@ -12,7 +12,7 @@
[package]
name = "binjs_meta"
version = "0.3.8"
version = "0.3.10"
authors = ["David Teller <D.O.Teller@gmail.com>"]
description = "Part of binjs-ref. Tools for manipulating grammars. You probably do not want to use this crate directly unless you're writing an encoder, decoder or parser generator for binjs."
homepage = "https://binast.github.io/ecmascript-binary-ast/"

View File

@ -77,13 +77,21 @@ impl TypeDeanonymizer {
builder: SpecBuilder::new(),
supersums_of: HashMap::new(),
};
let mut skip_name_map: HashMap<&FieldName, FieldName> = HashMap::new();
// Copy field names
for (_, name) in spec.field_names() {
result.builder.import_field_name(name)
}
// We may need to introduce name `_skip`, we'll see.
let mut field_skip = None;
for (_, interface) in spec.interfaces_by_name() {
for field in interface.contents().fields() {
if field.is_lazy() {
let skip_name = result.builder.field_name(format!("{}_skip", field.name().to_str()).to_str());
skip_name_map.insert(field.name(), skip_name);
}
}
}
// Copy and deanonymize interfaces.
for (name, interface) in spec.interfaces_by_name() {
@ -92,16 +100,6 @@ impl TypeDeanonymizer {
// and walk through their fields to deanonymize types.
let mut fields = vec![];
// If the interface is skippable, introduce a first invisible field `_skip`.
if interface.is_skippable() {
let name = field_skip.get_or_insert_with(||
result.builder.field_name("_skip")
);
fields.push(Field::new(
name.clone(),
Type::offset().required()
))
}
// Copy other fields.
for field in interface.contents().fields() {
@ -113,9 +111,16 @@ impl TypeDeanonymizer {
let mut declaration = result.builder.add_interface(name)
.unwrap();
for field in fields.drain(..) {
declaration.with_field(field.name(), field.type_().clone());
// Create *_skip field just before the lazy field.
// See also tagged_tuple in write.rs.
if field.is_lazy() {
declaration.with_field(skip_name_map.get(field.name()).unwrap(),
Type::offset().required(),
Laziness::Eager);
}
declaration.with_field(field.name(), field.type_().clone(),
field.laziness());
}
declaration.with_skippable(interface.is_skippable());
}
// Copy and deanonymize typedefs
for (name, definition) in spec.typedefs_by_name() {
@ -185,6 +190,7 @@ impl TypeDeanonymizer {
match *type_spec {
TypeSpec::Boolean |
TypeSpec::Number |
TypeSpec::UnsignedLong |
TypeSpec::String |
TypeSpec::Offset |
TypeSpec::Void => {
@ -233,6 +239,7 @@ impl TypeDeanonymizer {
Some(IsNullable { content: Primitive::Interface(_), .. }) => Type::named(&content).required(),
Some(IsNullable { content: Primitive::String, .. }) => Type::string().required(),
Some(IsNullable { content: Primitive::Number, .. }) => Type::number().required(),
Some(IsNullable { content: Primitive::UnsignedLong, .. }) => Type::unsigned_long().required(),
Some(IsNullable { content: Primitive::Boolean, .. }) => Type::bool().required(),
Some(IsNullable { content: Primitive::Offset, .. }) => Type::offset().required(),
Some(IsNullable { content: Primitive::Void, .. }) => Type::void().required()
@ -362,6 +369,8 @@ impl TypeName {
"_Bool".to_string(),
TypeSpec::Number =>
"_Number".to_string(),
TypeSpec::UnsignedLong =>
"_UnsignedLong".to_string(),
TypeSpec::String =>
"_String".to_string(),
TypeSpec::Void =>
@ -401,6 +410,8 @@ impl ToWebidl {
"string".to_string(),
TypeSpec::Number =>
"number".to_string(),
TypeSpec::UnsignedLong =>
"unsigned long".to_string(),
TypeSpec::NamedType(ref name) =>
name.to_str().to_string(),
TypeSpec::TypeSum(ref sum) => {

View File

@ -1,4 +1,4 @@
use spec::{ self, SpecBuilder, TypeSum };
use spec::{ self, SpecBuilder, TypeSum, Laziness };
use webidl::ast::*;
@ -12,33 +12,52 @@ impl Importer {
/// extern crate binjs_meta;
/// extern crate webidl;
/// use webidl;
/// use binjs_meta::spec::SpecOptions;
///
/// let ast = webidl::parse_string("
/// [Skippable] interface SkippableFoo {
/// attribute EagerFoo eager;
/// interface FooContents {
/// attribute boolean value;
/// };
/// interface LazyFoo {
/// [Lazy] attribute FooContents contents;
/// };
/// interface EagerFoo {
/// attribute bool value;
/// attribute FooContents contents;
/// };
/// ").expect("Could not parse");
///
/// let mut builder = binjs_meta::import::Importer::import(&ast);
///
/// let name_eager = builder.get_node_name("EagerFoo")
/// let fake_root = builder.node_name("@@ROOT@@"); // Unused
/// let null = builder.node_name(""); // Used
/// let spec = builder.into_spec(SpecOptions {
/// root: &fake_root,
/// null: &null,
/// });
///
/// let name_eager = spec.get_node_name("EagerFoo")
/// .expect("Missing name EagerFoo");
/// let name_skippable = builder.get_node_name("SkippableFoo")
/// .expect("Missing name SkippableFoo");
/// let name_lazy = spec.get_node_name("LazyFoo")
/// .expect("Missing name LazyFoo");
/// let name_contents = spec.get_field_name("contents")
/// .expect("Missing name contents");
///
/// {
/// let interface_eager = builder.get_interface(&name_eager)
/// let interface_eager = spec.get_interface_by_name(&name_eager)
/// .expect("Missing interface EagerFoo");
/// assert_eq!(interface_eager.is_skippable(), false);
/// let contents_field =
/// interface_eager.get_field_by_name(&name_contents)
/// .expect("Missing field contents");
/// assert_eq!(contents_field.is_lazy(), false);
/// }
///
/// {
/// let interface_skippable = builder.get_interface(&name_skippable)
/// .expect("Missing interface SkippableFoo");
/// assert_eq!(interface_skippable.is_skippable(), true);
/// let interface_lazy = spec.get_interface_by_name(&name_lazy)
/// .expect("Missing interface LazyFoo");
/// let contents_field =
/// interface_lazy.get_field_by_name(&name_contents)
/// .expect("Missing field contents");
/// assert_eq!(contents_field.is_lazy(), true);
/// }
/// ```
pub fn import(ast: &AST) -> SpecBuilder {
@ -95,7 +114,19 @@ impl Importer {
if let InterfaceMember::Attribute(Attribute::Regular(ref attribute)) = *member {
let name = self.builder.field_name(&attribute.name);
let type_ = self.convert_type(&*attribute.type_);
fields.push((name, type_));
let mut laziness = Laziness::Eager;
for extended_attribute in &attribute.extended_attributes {
use webidl::ast::ExtendedAttribute::NoArguments;
use webidl::ast::Other::Identifier;
if let &NoArguments(Identifier(ref id)) = extended_attribute.as_ref() {
if &*id == "Lazy" {
laziness = Laziness::Lazy;
}
}
}
fields.push((name, type_, laziness));
} else {
panic!("Expected an attribute, got {:?}", member);
}
@ -103,18 +134,8 @@ impl Importer {
let name = self.builder.node_name(&interface.name);
let mut node = self.builder.add_interface(&name)
.expect("Name already present");
for (field_name, field_type) in fields.drain(..) {
node.with_field(&field_name, field_type);
}
for extended_attribute in &interface.extended_attributes {
use webidl::ast::ExtendedAttribute::NoArguments;
use webidl::ast::Other::Identifier;
if let &NoArguments(Identifier(ref id)) = extended_attribute.as_ref() {
if &*id == "Skippable" {
node.with_skippable(true);
}
}
for (field_name, field_type, field_laziness) in fields.drain(..) {
node.with_field(&field_name, field_type, field_laziness);
}
}
fn convert_type(&mut self, t: &Type) -> spec::Type {
@ -140,6 +161,8 @@ impl Importer {
}
TypeKind::RestrictedDouble =>
spec::TypeSpec::Number,
TypeKind::UnsignedLong =>
spec::TypeSpec::UnsignedLong,
_ => {
panic!("I don't know how to import {:?} yet", t);
}
@ -151,4 +174,4 @@ impl Importer {
spec.required()
}
}
}
}

View File

@ -100,12 +100,20 @@ impl TypeSum {
}
}
/// Lazy for a field with [lazy] attribute. Eager for others.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Laziness {
Eager,
Lazy,
}
/// Representation of a field in an interface.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Field {
name: FieldName,
type_: Type,
documentation: Option<String>,
laziness: Laziness,
}
impl Hash for Field {
fn hash<H>(&self, state: &mut H) where H: Hasher {
@ -118,6 +126,7 @@ impl Field {
name,
type_,
documentation: None,
laziness: Laziness::Eager,
}
}
pub fn name(&self) -> &FieldName {
@ -126,6 +135,12 @@ impl Field {
pub fn type_(&self) -> &Type {
&self.type_
}
pub fn is_lazy(&self) -> bool {
self.laziness == Laziness::Lazy
}
pub fn laziness(&self) -> Laziness {
self.laziness.clone()
}
pub fn doc(&self) -> Option<&str> {
match self.documentation {
None => None,
@ -163,11 +178,13 @@ pub enum TypeSpec {
/// A number, as per JavaScript specifications.
Number,
UnsignedLong,
/// A number of bytes in the binary file.
///
/// This spec is used only internally, as a hidden
/// field injected by deanonymization, to represent
/// Skippable nodes.
/// lazy fields.
Offset,
/// Nothing.
@ -275,6 +292,7 @@ impl TypeSpec {
TypeSpec::Boolean => Some(IsNullable::non_nullable(Primitive::Boolean)),
TypeSpec::Void => Some(IsNullable::non_nullable(Primitive::Void)),
TypeSpec::Number => Some(IsNullable::non_nullable(Primitive::Number)),
TypeSpec::UnsignedLong => Some(IsNullable::non_nullable(Primitive::UnsignedLong)),
TypeSpec::String => Some(IsNullable::non_nullable(Primitive::String)),
TypeSpec::Offset => Some(IsNullable::non_nullable(Primitive::Offset)),
TypeSpec::NamedType(ref name) => {
@ -311,6 +329,7 @@ pub enum Primitive {
Boolean,
Void,
Number,
UnsignedLong,
Offset,
Interface(Rc<Interface>),
}
@ -365,6 +384,9 @@ impl Type {
pub fn number() -> TypeSpec {
TypeSpec::Number
}
pub fn unsigned_long() -> TypeSpec {
TypeSpec::UnsignedLong
}
pub fn bool() -> TypeSpec {
TypeSpec::Boolean
}
@ -445,7 +467,8 @@ impl Obj {
self
}
fn with_field_aux(self, name: &FieldName, type_: Type, doc: Option<&str>) -> Self {
fn with_field_aux(self, name: &FieldName, type_: Type, laziness: Laziness,
doc: Option<&str>) -> Self {
if self.field(name).is_some() {
warn!("Field: attempting to overwrite {:?}", name);
return self
@ -455,6 +478,7 @@ impl Obj {
name: name.clone(),
type_,
documentation: doc.map(str::to_string),
laziness,
});
Obj {
fields
@ -463,12 +487,12 @@ impl Obj {
}
/// Extend a structure with a field.
pub fn with_field(self, name: &FieldName, type_: Type) -> Self {
self.with_field_aux(name, type_, None)
pub fn with_field(self, name: &FieldName, type_: Type, laziness: Laziness) -> Self {
self.with_field_aux(name, type_, laziness, None)
}
pub fn with_field_doc(self, name: &FieldName, type_: Type, doc: &str) -> Self {
self.with_field_aux(name, type_, Some(doc))
pub fn with_field_doc(self, name: &FieldName, type_: Type, laziness: Laziness, doc: &str) -> Self {
self.with_field_aux(name, type_, laziness, Some(doc))
}
}
@ -505,9 +529,6 @@ pub struct InterfaceDeclaration {
/// The contents of this interface, excluding the contents of parent interfaces.
contents: Obj,
/// If `true`, objects of this interface may be skipped during parsing.
is_skippable: bool,
}
impl InterfaceDeclaration {
@ -515,25 +536,18 @@ impl InterfaceDeclaration {
let _ = self.contents.with_full_field(contents);
self
}
pub fn with_field(&mut self, name: &FieldName, type_: Type) -> &mut Self {
self.with_field_aux(name, type_, None)
pub fn with_field(&mut self, name: &FieldName, type_: Type, laziness: Laziness) -> &mut Self {
self.with_field_aux(name, type_, laziness, None)
}
pub fn with_field_doc(&mut self, name: &FieldName, type_: Type, doc: &str) -> &mut Self {
self.with_field_aux(name, type_, Some(doc))
pub fn with_field_doc(&mut self, name: &FieldName, type_: Type, laziness: Laziness, doc: &str) -> &mut Self {
self.with_field_aux(name, type_, laziness, Some(doc))
}
fn with_field_aux(&mut self, name: &FieldName, type_: Type, doc: Option<&str>) -> &mut Self {
fn with_field_aux(&mut self, name: &FieldName, type_: Type, laziness: Laziness, doc: Option<&str>) -> &mut Self {
let mut contents = Obj::new();
std::mem::swap(&mut self.contents, &mut contents);
self.contents = contents.with_field_aux(name, type_, doc);
self.contents = contents.with_field_aux(name, type_, laziness, doc);
self
}
pub fn with_skippable(&mut self, value: bool) -> &mut Self {
self.is_skippable = value;
self
}
pub fn is_skippable(&self) -> bool {
self.is_skippable
}
}
/// A data structure used to progressively construct the `Spec`.
@ -603,7 +617,6 @@ impl SpecBuilder {
let result = RefCell::new(InterfaceDeclaration {
name: name.clone(),
contents: Obj::new(),
is_skippable: false,
});
self.interfaces_by_name.insert(name.clone(), result);
self.interfaces_by_name.get(name)
@ -750,7 +763,7 @@ impl SpecBuilder {
debug!(target: "spec", "classify_type => don't put me in an interface");
TypeClassification::Array
},
TypeSpec::Boolean | TypeSpec::Number | TypeSpec::String | TypeSpec::Void | TypeSpec::Offset => {
TypeSpec::Boolean | TypeSpec::Number | TypeSpec::UnsignedLong | TypeSpec::String | TypeSpec::Void | TypeSpec::Offset => {
debug!(target: "spec", "classify_type => don't put me in an interface");
TypeClassification::Primitive
}
@ -849,8 +862,7 @@ impl SpecBuilder {
///
/// Interfaces represent nodes in the AST. Each interface
/// has a name, a type, defines properties (also known as
/// `attribute` in webidl) which hold values. Interfaces
/// may also have meta-properties, such as their skippability.
/// `attribute` in webidl) which hold values.
#[derive(Debug)]
pub struct Interface {
declaration: InterfaceDeclaration,
@ -890,12 +902,6 @@ impl Interface {
}
None
}
/// `true` if parsers should have the ability to skip instances of this
/// interface.
pub fn is_skippable(&self) -> bool {
self.declaration.is_skippable
}
}
/// Immutable representation of the spec.