Skip to content

Commit

Permalink
Refactor and clean-up
Browse files Browse the repository at this point in the history
  • Loading branch information
Diggsey committed Mar 4, 2018
1 parent 1823a5d commit 12a4d86
Show file tree
Hide file tree
Showing 7 changed files with 924 additions and 733 deletions.
7 changes: 7 additions & 0 deletions webgl_generator/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@
//! used to generate all constants and functions of a given OpenGL version.
//!
//! See the `webgl` crate for an example of use.
extern crate webidl;
extern crate heck;
extern crate khronos_api;
extern crate xml;
extern crate regex;
extern crate html2runes;

mod utils;
mod webgl_generators;
mod webgl_registry;

Expand Down
81 changes: 81 additions & 0 deletions webgl_generator/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use std::collections::BTreeMap;
use std::str;

use webidl::{self, ast};

/// Helper method for inserting into a BTreeMap-based multi-map
pub fn multimap_insert<K: Ord, V: PartialEq>(m: &mut BTreeMap<K, Vec<V>>, key: K, value: V) {
let v = m.entry(key).or_insert_with(Vec::new);
if !v.contains(&value) {
v.push(value);
}
}

/// Helper method for appending to a BTreeMap-based multi-map
pub fn multimap_append<K: Ord + Clone, V: PartialEq>(m: &mut BTreeMap<K, Vec<V>>, other: BTreeMap<K, Vec<V>>) {
for (k, v) in other {
for value in v {
multimap_insert(m, k.clone(), value);
}
}
}

/// Best-effort attempt to render HTML into a doc-comment which can
/// be placed in the generated code.
pub fn convert_html_to_doc_comment(html: &str) -> String {
use regex::RegexBuilder;
use html2runes;

// Create doc comments
let doc_comment_regex = RegexBuilder::new("^").multi_line(true).build().unwrap();

let md = html2runes::markdown::convert_string(html);
let mut doc = doc_comment_regex.replace_all(md.trim_right(), "/// ").into();
doc += "\n";
doc
}

/// Appends an underscore to a name if it conflicts with a reserved word.
pub fn unreserve<S: Into<String>>(name: S) -> String {
const RESERVED_WORDS: &'static [&'static str] = &[
"as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for",
"if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return",
"Self", "self", "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where",
"while", "abstract", "alignof", "become", "box", "do", "final", "macro", "offsetof",
"override", "priv", "proc", "pure", "sizeof", "typeof", "unsized", "virtual", "yield"
];

let mut s = name.into();
if RESERVED_WORDS.contains(&&*s) {
s += "_";
}
s
}

/// Converts to lower snake-case
pub fn snake(name: &str) -> String {
use heck::SnakeCase;
name.to_snake_case()
}

/// Converts to upper snake-case
pub fn shouty_snake(name: &str) -> String {
use heck::ShoutySnakeCase;
name.to_shouty_snake_case()
}

/// Converts to upper camel case
pub fn camel(name: &str) -> String {
use heck::CamelCase;
name.to_camel_case()
}

/// Parse WebIDL content into an AST
pub fn parse_defs(src: &[u8]) -> Vec<ast::Definition> {
let src = str::from_utf8(src)
.expect("IDL contained invalid UTF-8");

let parser = webidl::Parser::new();
parser.parse_string(src)
.expect("Failed to parse IDL")
}
100 changes: 52 additions & 48 deletions webgl_generator/webgl_generators/stdweb_gen.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::io;
use std::collections::BTreeSet;

use utils::*;
use webgl_registry::*;

#[allow(missing_copy_implementations)]
Expand Down Expand Up @@ -86,14 +87,14 @@ impl ProcessedArg {
}
}

fn process_arg_type_kind(name: &str, type_kind: &TypeKind, registry: &Registry, gc: &mut GenericContext) -> ProcessedArg {
let flat_kind = type_kind.flatten(registry);
fn process_arg_type_kind(type_kind: &TypeKind, registry: &Registry, gc: &mut GenericContext) -> ProcessedArg {
let (name, flat_kind) = type_kind.flatten(registry);
match flat_kind {
&TypeKind::Primitive(ref p) => {
match p {
&Primitive::I64 => ProcessedArg { type_: name.into(), wrapper: ArgWrapper::DoubleCast, optional: false },
&Primitive::U64 => ProcessedArg { type_: name.into(), wrapper: ArgWrapper::DoubleCast, optional: false },
_ => ProcessedArg::simple(name)
&Primitive::I64 => ProcessedArg { type_: name.unwrap().into(), wrapper: ArgWrapper::DoubleCast, optional: false },
&Primitive::U64 => ProcessedArg { type_: name.unwrap().into(), wrapper: ArgWrapper::DoubleCast, optional: false },
_ => ProcessedArg::simple(name.unwrap())
}
},
&TypeKind::String => ProcessedArg::simple("&str"),
Expand All @@ -119,40 +120,43 @@ fn process_arg_type_kind(name: &str, type_kind: &TypeKind, registry: &Registry,
},
&TypeKind::Union(ref ts) => {
let t = ts.iter().filter_map(|t| {
let t_kind = registry.resolve_type(&t.name);
match t_kind {
&TypeKind::TypedArray(_) => Some(t),
&TypeKind::Sequence(_) => None,
match t.kind {
TypeKind::TypedArray(_) => Some(t),
TypeKind::Sequence(_) => None,
_ => panic!("Union support is limited!")
}
}).next().expect("Union did not contain a TypedArray");

process_arg_type(t, registry, gc)
},
&TypeKind::Dictionary | &TypeKind::Interface => ProcessedArg::simple(format!("&{}", name)),
&TypeKind::Enum => ProcessedArg::simple(name),
&TypeKind::Typedef(ref t) => {
// We have to "look through" the typedef, as the correct parameter
// type is not representable using the alias.
assert!(t.optional);
process_arg_type(t, registry, gc)
&TypeKind::Named(ref actual_name) => {
match registry.resolve_type(actual_name) {
&NamedType::Dictionary(_) | &NamedType::Interface(_) => ProcessedArg::simple(format!("&{}", name.unwrap())),
&NamedType::Enum(_) => ProcessedArg::simple(name.unwrap()),
&NamedType::Typedef(ref t) => {
// We have to "look through" the typedef, as the correct parameter
// type is not representable using the alias.
assert!(t.optional);
process_arg_type(t, registry, gc)
},
&NamedType::Callback(_) => {
let gp = gc.arg("F");
gc.constrain(format!("{}: FnOnce() + 'static", gp));
ProcessedArg { type_: gp, wrapper: ArgWrapper::Once, optional: false }
},
&NamedType::Mixin(_) => panic!("Mixins are not usable as types!")
}
},
&TypeKind::Any | &TypeKind::Object => {
let gp = gc.arg("T");
gc.constrain(format!("{}: JsSerialize", gp));
ProcessedArg::simple(gp)
},
&TypeKind::Callback(ref _args, ref _return_type) => {
let gp = gc.arg("F");
gc.constrain(format!("{}: FnOnce() + 'static", gp));
ProcessedArg { type_: gp, wrapper: ArgWrapper::Once, optional: false }
}
}
}

fn process_arg_type(type_: &Type, registry: &Registry, gc: &mut GenericContext) -> ProcessedArg {
let type_kind = registry.resolve_type(&type_.name);
let mut result = process_arg_type_kind(&type_.name, &type_kind, registry, gc);
let mut result = process_arg_type_kind(&type_.kind, registry, gc);
if type_.optional && !result.optional {
result.type_ = format!("Option<{}>", result.type_);
result.wrapper = match result.wrapper {
Expand Down Expand Up @@ -192,7 +196,7 @@ impl ProcessedResult {
}
}

fn process_result_type_kind(name: &str, type_kind: &TypeKind, registry: &Registry) -> ProcessedResult {
fn process_result_type_kind(type_kind: &TypeKind, registry: &Registry) -> ProcessedResult {
match type_kind {
&TypeKind::Primitive(ref p) => ProcessedResult::simple(p.name()),
&TypeKind::String => ProcessedResult::simple("String"),
Expand All @@ -206,33 +210,38 @@ fn process_result_type_kind(name: &str, type_kind: &TypeKind, registry: &Registr
},
&TypeKind::Union(ref ts) => {
let t = ts.iter().filter_map(|t| {
let t_kind = registry.resolve_type(&t.name);
match t_kind {
&TypeKind::TypedArray(_) => Some(t),
&TypeKind::Sequence(_) => None,
match t.kind {
TypeKind::TypedArray(_) => Some(t),
TypeKind::Sequence(_) => None,
_ => panic!("Union support is limited!")
}
}).next().expect("Union did not contain a TypedArray");

process_result_type(t, registry)
},
&TypeKind::Dictionary | &TypeKind::Interface | &TypeKind::Enum => ProcessedResult::simple(name),
&TypeKind::Typedef(ref t) => {
let inner = process_result_type(t, registry);
ProcessedResult {
type_: name.into(),
wrapper: inner.wrapper.clone(),
optional: inner.optional
&TypeKind::Named(ref name) => {
match registry.resolve_type(name) {
&NamedType::Dictionary(_) | &NamedType::Interface(_) | &NamedType::Enum(_) => {
ProcessedResult::simple(name.as_str())
},
&NamedType::Typedef(ref t) => {
let inner = process_result_type(t, registry);
ProcessedResult {
type_: name.clone(),
wrapper: inner.wrapper.clone(),
optional: inner.optional
}
},
&NamedType::Callback(_) => unimplemented!(),
&NamedType::Mixin(_) => panic!("Mixins are not usable as types!")
}
},
&TypeKind::Any | &TypeKind::Object => ProcessedResult::simple("Value"),
&TypeKind::Callback(ref _args, ref _return_type) => unimplemented!()
}
}

fn process_result_type(type_: &Type, registry: &Registry) -> ProcessedResult {
let type_kind = registry.resolve_type(&type_.name);
let mut result = process_result_type_kind(&type_.name, type_kind, registry);
let mut result = process_result_type_kind(&type_.kind, registry);
if type_.optional && !result.optional {
result.type_ = format!("Option<{}>", result.type_);
result.wrapper = ResultWrapper::Ok;
Expand Down Expand Up @@ -306,13 +315,8 @@ impl super::Generator for StdwebGenerator {
}

fn write_typedefs<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
for (name, type_kind) in &registry.types {
match type_kind {
&TypeKind::Typedef(ref t) => {
write_typedef(name, t, registry, dest)?;
},
_ => {}
}
for (name, t) in registry.iter_types(NamedType::as_typedef) {
write_typedef(name, t, registry, dest)?;
}
Ok(())
}
Expand All @@ -326,7 +330,7 @@ fn write_typedef<W>(name: &str, type_: &Type, registry: &Registry, dest: &mut W)
}

fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
for (name, enum_) in &registry.enums {
for (name, enum_) in registry.iter_types(NamedType::as_enum) {
write_enum(name, enum_, registry, dest)?;
}
Ok(())
Expand Down Expand Up @@ -355,7 +359,7 @@ js_serializable!({name});
}

fn write_dictionaries<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
for (name, dictionary) in &registry.dictionaries {
for (name, dictionary) in registry.iter_types(NamedType::as_dictionary) {
write_dictionary(name, dictionary, registry, dest)?;
}
Ok(())
Expand Down Expand Up @@ -407,7 +411,7 @@ fn write_field<W>(name: &str, field: &Field, registry: &Registry, dest: &mut W)
}

fn write_interfaces<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
for (name, interface) in &registry.interfaces {
for (name, interface) in registry.iter_types(NamedType::as_interface) {
write_interface(name, interface, registry, dest)?;
}
Ok(())
Expand Down
Loading

0 comments on commit 12a4d86

Please sign in to comment.