<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::attr::Attr;
use dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::HTMLButtonElementBinding;
use dom::bindings::codegen::Bindings::HTMLButtonElementBinding::HTMLButtonElementMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::{HTMLButtonElementDerived, HTMLFieldSetElementDerived};
use dom::bindings::js::{JSRef, Temporary};
use dom::document::Document;
use dom::element::{AttributeHandlers, Element};
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::element::ElementTypeId;
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, NodeTypeId, window_from_node};
use dom::validitystate::ValidityState;
use dom::virtualmethods::VirtualMethods;

use std::ascii::OwnedAsciiExt;
use std::borrow::ToOwned;
use util::str::DOMString;
use string_cache::Atom;

#[dom_struct]
pub struct HTMLButtonElement {
    htmlelement: HTMLElement
}

impl HTMLButtonElementDerived for EventTarget {
    fn is_htmlbuttonelement(&self) -> bool {
        *self.type_id() == EventTargetTypeId::Node(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)))
    }
}

impl HTMLButtonElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLButtonElement {
        HTMLButtonElement {
            htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLButtonElement, localName, prefix, document)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLButtonElement> {
        let element = HTMLButtonElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLButtonElementBinding::Wrap)
    }
}

impl<'a> HTMLButtonElementMethods for JSRef<'a, HTMLButtonElement> {
    fn Validity(self) -> Temporary<ValidityState> {
        let window = window_from_node(self).root();
        ValidityState::new(window.r())
    }

    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_getter!(Disabled);

    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_setter!(SetDisabled, "disabled");

    // https://html.spec.whatwg.org/multipage/forms.html#dom-button-type
    fn Type(self) -> DOMString {
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        let ty = elem.get_string_attribute(&atom!("type")).into_ascii_lowercase();
        // https://html.spec.whatwg.org/multipage/forms.html#attr-button-type
        match ty.as_slice() {
            "reset" | "button" | "menu" => ty,
            _ => "submit".to_owned()
        }
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-button-type
    make_setter!(SetType, "type");
}

impl<'a> VirtualMethods for JSRef<'a, HTMLButtonElement> {
    fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, attr: JSRef<Attr>) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(attr),
            _ => (),
        }

        match attr.local_name() {
            &atom!("disabled") => {
                let node: JSRef<Node> = NodeCast::from_ref(*self);
                node.set_disabled_state(true);
                node.set_enabled_state(false);
            },
            _ => ()
        }
    }

    fn before_remove_attr(&self, attr: JSRef<Attr>) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(attr),
            _ => (),
        }

        match attr.local_name() {
            &atom!("disabled") => {
                let node: JSRef<Node> = NodeCast::from_ref(*self);
                node.set_disabled_state(false);
                node.set_enabled_state(true);
                node.check_ancestors_disabled_state_for_form_control();
            },
            _ => ()
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        node.check_ancestors_disabled_state_for_form_control();
    }

    fn unbind_from_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.unbind_from_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        if node.ancestors().any(|ancestor| ancestor.is_htmlfieldsetelement()) {
            node.check_ancestors_disabled_state_for_form_control();
        } else {
            node.check_disabled_attribute();
        }
    }
}

<commit_msg>add button type into HTMLButtonElement<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::attr::Attr;
use dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::HTMLButtonElementBinding;
use dom::bindings::codegen::Bindings::HTMLButtonElementBinding::HTMLButtonElementMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::{HTMLButtonElementDerived, HTMLFieldSetElementDerived};
use dom::bindings::js::{JSRef, Temporary};
use dom::document::Document;
use dom::element::{AttributeHandlers, Element};
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::element::ElementTypeId;
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, NodeTypeId, window_from_node};
use dom::validitystate::ValidityState;
use dom::virtualmethods::VirtualMethods;

use std::ascii::OwnedAsciiExt;
use std::borrow::ToOwned;
use util::str::DOMString;
use std::cell::Cell;
use string_cache::Atom;

#[jstraceable]
#[derive(PartialEq, Copy)]
#[allow(dead_code)]
enum ButtonType {
    ButtonSubmit,
    ButtonReset,
    ButtonButton,
    ButtonMenu
}

#[dom_struct]
pub struct HTMLButtonElement {
    htmlelement: HTMLElement,
    button_type: Cell<ButtonType>
}

impl HTMLButtonElementDerived for EventTarget {
    fn is_htmlbuttonelement(&self) -> bool {
        *self.type_id() == EventTargetTypeId::Node(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)))
    }
}

impl HTMLButtonElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLButtonElement {
        HTMLButtonElement {
            htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLButtonElement, localName, prefix, document),
            button_type: Cell::new(ButtonType::ButtonSubmit)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLButtonElement> {
        let element = HTMLButtonElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLButtonElementBinding::Wrap)
    }
}

impl<'a> HTMLButtonElementMethods for JSRef<'a, HTMLButtonElement> {
    fn Validity(self) -> Temporary<ValidityState> {
        let window = window_from_node(self).root();
        ValidityState::new(window.r())
    }

    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_getter!(Disabled);

    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_setter!(SetDisabled, "disabled");

    // https://html.spec.whatwg.org/multipage/forms.html#dom-button-type
    fn Type(self) -> DOMString {
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        let ty = elem.get_string_attribute(&atom!("type")).into_ascii_lowercase();
        // https://html.spec.whatwg.org/multipage/forms.html#attr-button-type
        match ty.as_slice() {
            "reset" | "button" | "menu" => ty,
            _ => "submit".to_owned()
        }
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-button-type
    make_setter!(SetType, "type");
}

impl<'a> VirtualMethods for JSRef<'a, HTMLButtonElement> {
    fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, attr: JSRef<Attr>) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(attr),
            _ => (),
        }

        match attr.local_name() {
            &atom!("disabled") => {
                let node: JSRef<Node> = NodeCast::from_ref(*self);
                node.set_disabled_state(true);
                node.set_enabled_state(false);
            },
            _ => ()
        }
    }

    fn before_remove_attr(&self, attr: JSRef<Attr>) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(attr),
            _ => (),
        }

        match attr.local_name() {
            &atom!("disabled") => {
                let node: JSRef<Node> = NodeCast::from_ref(*self);
                node.set_disabled_state(false);
                node.set_enabled_state(true);
                node.check_ancestors_disabled_state_for_form_control();
            },
            _ => ()
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        node.check_ancestors_disabled_state_for_form_control();
    }

    fn unbind_from_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.unbind_from_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        if node.ancestors().any(|ancestor| ancestor.is_htmlfieldsetelement()) {
            node.check_ancestors_disabled_state_for_form_control();
        } else {
            node.check_disabled_attribute();
        }
    }
}

<|endoftext|>


<commit_before>use kernel::int;
use cpu::io;

#[repr(u8)]
pub enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yellow      = 14,
    White       = 15,
}

#[packed]
struct Char {
    char: u8,
    attr: u8,
}

impl Char {
    #[inline]
    pub fn new(c: char, fg: Color, bg: Color) -> Char {
        Char { char: c as u8, attr: fg as u8 | (bg as u8 << 4) }
    }
}

pub static SCREEN_SIZE: uint = 80*25;
type screen = [Char, ..SCREEN_SIZE];
pub static SCREEN: *mut screen = 0xb8000 as *mut screen;

pub fn clear_screen(bg: Color) {
    int::range(0, SCREEN_SIZE, |i| {
        unsafe {
            (*SCREEN)[i] = Char::new(' ', Black, bg);
        }
    });
}

pub fn cursor_at(pos: uint) {
    io::out(0x3D4, 15);
    io::out(0x3D5, pos as u8);
    io::out(0x3D4, 14);
    io::out(0x3D5, (pos >> 8) as u8);
}
<commit_msg>Struct fields changed to inherit privacy of the struct<commit_after>use kernel::int;
use cpu::io;

#[repr(u8)]
pub enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yellow      = 14,
    White       = 15,
}

#[packed]
pub struct Char {
    char: u8,
    attr: u8,
}

impl Char {
    #[inline]
    pub fn new(c: char, fg: Color, bg: Color) -> Char {
        Char { char: c as u8, attr: fg as u8 | (bg as u8 << 4) }
    }
}

pub static SCREEN_SIZE: uint = 80*25;
type screen = [Char, ..SCREEN_SIZE];
pub static SCREEN: *mut screen = 0xb8000 as *mut screen;

pub fn clear_screen(bg: Color) {
    int::range(0, SCREEN_SIZE, |i| {
        unsafe {
            (*SCREEN)[i] = Char::new(' ', Black, bg);
        }
    });
}

pub fn cursor_at(pos: uint) {
    io::out(0x3D4, 15);
    io::out(0x3D5, pos as u8);
    io::out(0x3D4, 14);
    io::out(0x3D5, (pos >> 8) as u8);
}
<|endoftext|>


<commit_before>use parser::{Cond, Expr, Node, Target, WS};
use std::str;
use std::collections::HashSet;
use syn;

fn annotations(generics: &syn::Generics) -> String {
    if generics.lifetimes.len() < 1 {
        return String::new();
    }
    let mut res = String::new();
    res.push('<');
    for lt in &generics.lifetimes {
        res.push_str(lt.lifetime.ident.as_ref());
    }
    res.push('>');
    res
}

fn path_as_identifier(s: &str) -> String {
    let mut res = String::new();
    for c in s.chars() {
        if c.is_alphanumeric() {
            res.push(c);
        } else {
            res.push_str(&format!("{:x}", c as u32));
        }
    }
    res
}

struct Generator<'a> {
    buf: String,
    indent: u8,
    start: bool,
    locals: HashSet<String>,
    next_ws: Option<&'a str>,
    skip_ws: bool,
}

impl<'a> Generator<'a> {

    fn new() -> Generator<'a> {
        Generator {
            buf: String::new(),
            indent: 0,
            start: true,
            locals: HashSet::new(),
            next_ws: None,
            skip_ws: false,
        }
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        self.write(s);
        self.buf.push('\n');
        self.start = true;
    }

    fn flush_ws(&mut self, ws: &WS) {
        if self.next_ws.is_some() && !ws.0 {
            let val = self.next_ws.unwrap();
            if !val.is_empty() {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      val));
            }
        }
        self.next_ws = None;
    }

    fn prepare_ws(&mut self, ws: &WS) {
        self.skip_ws = ws.1;
    }

    fn handle_ws(&mut self, ws: &WS) {
        self.flush_ws(ws);
        self.prepare_ws(ws);
    }

    fn visit_str_lit(&mut self, s: &str) {
        self.write(&format!("\"{}\"", s));
    }

    fn visit_var(&mut self, s: &str) {
        if self.locals.contains(s) {
            self.write(s);
        } else {
            self.write(&format!("self.{}", s));
        }
    }

    fn visit_filter(&mut self, name: &str, val: &Expr) {
        self.write(&format!("askama::filters::{}(&", name));
        self.visit_expr(val);
        self.write(")");
    }

    fn visit_binop(&mut self, op: &str, left: &Expr, right: &Expr) {
        self.visit_expr(left);
        self.write(&format!(" {} ", op));
        self.visit_expr(right);
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match *expr {
            Expr::StrLit(s) => self.visit_str_lit(s),
            Expr::Var(s) => self.visit_var(s),
            Expr::Filter(name, ref val) => self.visit_filter(name, val),
            Expr::BinOp(op, ref left, ref right) =>
                self.visit_binop(op, left, right),
        }
    }

    fn visit_target_single(&mut self, name: &str) -> Vec<String> {
        vec![name.to_string()]
    }

    fn visit_target(&mut self, target: &Target) -> Vec<String> {
        match *target {
            Target::Name(s) => { self.visit_target_single(s) },
        }
    }

    fn write_lit(&mut self, lws: &'a str, val: &str, rws: &'a str) {
        assert!(self.next_ws.is_none());
        if !lws.is_empty() {
            if self.skip_ws {
                self.skip_ws = false;
            } else if val.is_empty() {
                assert!(rws.is_empty());
                self.next_ws = Some(lws);
            } else {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      lws));
            }
        }
        if !val.is_empty() {
            self.writeln(&format!("writer.write_str({:#?}).unwrap();", val));
        }
        if !rws.is_empty() {
            self.next_ws = Some(rws);
        }
    }

    fn write_expr(&mut self, ws: &WS, s: &Expr) {
        self.handle_ws(ws);
        self.write("writer.write_fmt(format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
        for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
            self.handle_ws(cws);
            match *cond {
                Some(ref expr) => {
                    if i == 0 {
                        self.write("if ");
                    } else {
                        self.write("} else if ");
                    }
                    self.visit_expr(expr);
                },
                None => { self.writeln("} else"); },
            }
            self.writeln(" {");
            self.indent();
            self.handle(nodes);
            self.dedent();
        }
        self.handle_ws(ws);
        self.writeln("}");
    }

    fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
                  body: &'a [Node], ws2: &WS) {

        self.handle_ws(ws1);
        self.write("for ");
        let targets = self.visit_target(var);
        for name in &targets {
            self.locals.insert(name.clone());
            self.write(name);
        }
        self.write(" in &");
        self.visit_expr(iter);
        self.writeln(" {");

        self.indent();
        self.handle(body);
        self.handle_ws(ws2);
        self.dedent();
        self.writeln("}");
        for name in &targets {
            self.locals.remove(name);
        }
    }

    fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
        self.flush_ws(ws1);
        self.writeln(&format!("timpl.render_block_{}_to(writer);", name));
        self.prepare_ws(ws2);
    }

    fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
                       ws2: &WS) {
        self.writeln("#[allow(unused_variables)]");
        self.writeln(&format!(
            "fn render_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
            name));
        self.indent();
        self.prepare_ws(ws1);
        self.handle(nodes);
        self.flush_ws(ws2);
        self.dedent();
        self.writeln("}");
    }

    fn handle(&mut self, nodes: &'a [Node]) {
        for n in nodes {
            match *n {
                Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
                Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
                Node::Cond(ref conds, ref ws) => {
                    self.write_cond(conds, ws);
                },
                Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
                    self.write_loop(ws1, var, iter, body, ws2);
                },
                Node::Block(ref ws1, name, ref ws2) => {
                    self.write_block(ws1, name, ws2);
                },
                Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
                    self.write_block_def(ws1, name, block_nodes, ws2);
                }
                Node::Extends(_) => {
                    panic!("no extends or block definition allowed in content");
                },
            }
        }
    }

    fn path_based_name(&mut self, ast: &syn::DeriveInput, path: &str) {
        let encoded = path_as_identifier(path);
        let original = ast.ident.as_ref();
        let anno = annotations(&ast.generics);
        self.writeln("#[allow(dead_code, non_camel_case_types)]");
        let s = format!("type TemplateFrom{}{} = {}{};",
                        encoded, &anno, original, &anno);
        self.writeln(&s);
    }

    fn impl_template(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn impl_trait(&mut self, ast: &syn::DeriveInput, base: &str,
                  blocks: &'a [Node], nodes: Option<&'a [Node]>) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} TraitFrom{} for {}{} {{",
                              anno, path_as_identifier(base),
                              ast.ident.as_ref(), anno));
        self.indent();
        self.handle(blocks);

        self.writeln("#[allow(unused_variables)]");
        let trait_name = format!("TraitFrom{}", path_as_identifier(base));
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write) {{",
            trait_name));
        self.indent();

        if let Some(nodes) = nodes {
            self.handle(nodes);
            self.flush_ws(&WS(false, false));
        } else {
            self.writeln("self._parent.render_trait_to(self, writer);");
        }

        self.dedent();
        self.writeln("}");
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");
    }

    fn impl_template_for_trait(&mut self, ast: &syn::DeriveInput, derived: bool) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        if derived {
            self.writeln("self._parent.render_trait_to(self, writer);");
        } else {
            self.writeln("self.render_trait_to(self, writer);");
        }
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn define_trait(&mut self, path: &str, block_names: &[&str]) {
        let trait_name = format!("TraitFrom{}", path_as_identifier(path));
        self.writeln(&format!("trait {} {{", &trait_name));
        self.indent();

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write);",
                bname));
        }
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write);",
            trait_name));

        self.dedent();
        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
    let mut base: Option<Expr> = None;
    let mut blocks = Vec::new();
    let mut block_names = Vec::new();
    let mut content = Vec::new();
    for n in nodes.drain(..) {
        match n {
            Node::Extends(path) => {
                match base {
                    Some(_) => panic!("multiple extend blocks found"),
                    None => { base = Some(path); },
                }
            },
            Node::BlockDef(ws1, name, _, ws2) => {
                blocks.push(n);
                block_names.push(name);
                content.push(Node::Block(ws1, name, ws2));
            },
            _ => { content.push(n); },
        }
    }

    let mut gen = Generator::new();
    gen.path_based_name(ast, path);
    if !blocks.is_empty() {
        if base.is_none() {
            gen.define_trait(path, &block_names);
        }
        let tmpl_path = match base {
            Some(Expr::StrLit(base_path)) => { base_path },
            _ => { path },
        };
        let trait_nodes = if base.is_none() { Some(&content[..]) } else { None };
        gen.impl_trait(ast, tmpl_path, &blocks, trait_nodes);
        gen.impl_template_for_trait(ast, base.is_some());
    } else {
        gen.impl_template(ast, &content);
    }
    gen.result()
}
<commit_msg>Fix indentation for else clauses<commit_after>use parser::{Cond, Expr, Node, Target, WS};
use std::str;
use std::collections::HashSet;
use syn;

fn annotations(generics: &syn::Generics) -> String {
    if generics.lifetimes.len() < 1 {
        return String::new();
    }
    let mut res = String::new();
    res.push('<');
    for lt in &generics.lifetimes {
        res.push_str(lt.lifetime.ident.as_ref());
    }
    res.push('>');
    res
}

fn path_as_identifier(s: &str) -> String {
    let mut res = String::new();
    for c in s.chars() {
        if c.is_alphanumeric() {
            res.push(c);
        } else {
            res.push_str(&format!("{:x}", c as u32));
        }
    }
    res
}

struct Generator<'a> {
    buf: String,
    indent: u8,
    start: bool,
    locals: HashSet<String>,
    next_ws: Option<&'a str>,
    skip_ws: bool,
}

impl<'a> Generator<'a> {

    fn new() -> Generator<'a> {
        Generator {
            buf: String::new(),
            indent: 0,
            start: true,
            locals: HashSet::new(),
            next_ws: None,
            skip_ws: false,
        }
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        self.write(s);
        self.buf.push('\n');
        self.start = true;
    }

    fn flush_ws(&mut self, ws: &WS) {
        if self.next_ws.is_some() && !ws.0 {
            let val = self.next_ws.unwrap();
            if !val.is_empty() {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      val));
            }
        }
        self.next_ws = None;
    }

    fn prepare_ws(&mut self, ws: &WS) {
        self.skip_ws = ws.1;
    }

    fn handle_ws(&mut self, ws: &WS) {
        self.flush_ws(ws);
        self.prepare_ws(ws);
    }

    fn visit_str_lit(&mut self, s: &str) {
        self.write(&format!("\"{}\"", s));
    }

    fn visit_var(&mut self, s: &str) {
        if self.locals.contains(s) {
            self.write(s);
        } else {
            self.write(&format!("self.{}", s));
        }
    }

    fn visit_filter(&mut self, name: &str, val: &Expr) {
        self.write(&format!("askama::filters::{}(&", name));
        self.visit_expr(val);
        self.write(")");
    }

    fn visit_binop(&mut self, op: &str, left: &Expr, right: &Expr) {
        self.visit_expr(left);
        self.write(&format!(" {} ", op));
        self.visit_expr(right);
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match *expr {
            Expr::StrLit(s) => self.visit_str_lit(s),
            Expr::Var(s) => self.visit_var(s),
            Expr::Filter(name, ref val) => self.visit_filter(name, val),
            Expr::BinOp(op, ref left, ref right) =>
                self.visit_binop(op, left, right),
        }
    }

    fn visit_target_single(&mut self, name: &str) -> Vec<String> {
        vec![name.to_string()]
    }

    fn visit_target(&mut self, target: &Target) -> Vec<String> {
        match *target {
            Target::Name(s) => { self.visit_target_single(s) },
        }
    }

    fn write_lit(&mut self, lws: &'a str, val: &str, rws: &'a str) {
        assert!(self.next_ws.is_none());
        if !lws.is_empty() {
            if self.skip_ws {
                self.skip_ws = false;
            } else if val.is_empty() {
                assert!(rws.is_empty());
                self.next_ws = Some(lws);
            } else {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      lws));
            }
        }
        if !val.is_empty() {
            self.writeln(&format!("writer.write_str({:#?}).unwrap();", val));
        }
        if !rws.is_empty() {
            self.next_ws = Some(rws);
        }
    }

    fn write_expr(&mut self, ws: &WS, s: &Expr) {
        self.handle_ws(ws);
        self.write("writer.write_fmt(format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
        for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
            self.handle_ws(cws);
            match *cond {
                Some(ref expr) => {
                    if i == 0 {
                        self.write("if ");
                    } else {
                        self.write("} else if ");
                    }
                    self.visit_expr(expr);
                },
                None => { self.write("} else"); },
            }
            self.writeln(" {");
            self.indent();
            self.handle(nodes);
            self.dedent();
        }
        self.handle_ws(ws);
        self.writeln("}");
    }

    fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
                  body: &'a [Node], ws2: &WS) {

        self.handle_ws(ws1);
        self.write("for ");
        let targets = self.visit_target(var);
        for name in &targets {
            self.locals.insert(name.clone());
            self.write(name);
        }
        self.write(" in &");
        self.visit_expr(iter);
        self.writeln(" {");

        self.indent();
        self.handle(body);
        self.handle_ws(ws2);
        self.dedent();
        self.writeln("}");
        for name in &targets {
            self.locals.remove(name);
        }
    }

    fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
        self.flush_ws(ws1);
        self.writeln(&format!("timpl.render_block_{}_to(writer);", name));
        self.prepare_ws(ws2);
    }

    fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
                       ws2: &WS) {
        self.writeln("#[allow(unused_variables)]");
        self.writeln(&format!(
            "fn render_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
            name));
        self.indent();
        self.prepare_ws(ws1);
        self.handle(nodes);
        self.flush_ws(ws2);
        self.dedent();
        self.writeln("}");
    }

    fn handle(&mut self, nodes: &'a [Node]) {
        for n in nodes {
            match *n {
                Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
                Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
                Node::Cond(ref conds, ref ws) => {
                    self.write_cond(conds, ws);
                },
                Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
                    self.write_loop(ws1, var, iter, body, ws2);
                },
                Node::Block(ref ws1, name, ref ws2) => {
                    self.write_block(ws1, name, ws2);
                },
                Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
                    self.write_block_def(ws1, name, block_nodes, ws2);
                }
                Node::Extends(_) => {
                    panic!("no extends or block definition allowed in content");
                },
            }
        }
    }

    fn path_based_name(&mut self, ast: &syn::DeriveInput, path: &str) {
        let encoded = path_as_identifier(path);
        let original = ast.ident.as_ref();
        let anno = annotations(&ast.generics);
        self.writeln("#[allow(dead_code, non_camel_case_types)]");
        let s = format!("type TemplateFrom{}{} = {}{};",
                        encoded, &anno, original, &anno);
        self.writeln(&s);
    }

    fn impl_template(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn impl_trait(&mut self, ast: &syn::DeriveInput, base: &str,
                  blocks: &'a [Node], nodes: Option<&'a [Node]>) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} TraitFrom{} for {}{} {{",
                              anno, path_as_identifier(base),
                              ast.ident.as_ref(), anno));
        self.indent();
        self.handle(blocks);

        self.writeln("#[allow(unused_variables)]");
        let trait_name = format!("TraitFrom{}", path_as_identifier(base));
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write) {{",
            trait_name));
        self.indent();

        if let Some(nodes) = nodes {
            self.handle(nodes);
            self.flush_ws(&WS(false, false));
        } else {
            self.writeln("self._parent.render_trait_to(self, writer);");
        }

        self.dedent();
        self.writeln("}");
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");
    }

    fn impl_template_for_trait(&mut self, ast: &syn::DeriveInput, derived: bool) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        if derived {
            self.writeln("self._parent.render_trait_to(self, writer);");
        } else {
            self.writeln("self.render_trait_to(self, writer);");
        }
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn define_trait(&mut self, path: &str, block_names: &[&str]) {
        let trait_name = format!("TraitFrom{}", path_as_identifier(path));
        self.writeln(&format!("trait {} {{", &trait_name));
        self.indent();

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write);",
                bname));
        }
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write);",
            trait_name));

        self.dedent();
        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
    let mut base: Option<Expr> = None;
    let mut blocks = Vec::new();
    let mut block_names = Vec::new();
    let mut content = Vec::new();
    for n in nodes.drain(..) {
        match n {
            Node::Extends(path) => {
                match base {
                    Some(_) => panic!("multiple extend blocks found"),
                    None => { base = Some(path); },
                }
            },
            Node::BlockDef(ws1, name, _, ws2) => {
                blocks.push(n);
                block_names.push(name);
                content.push(Node::Block(ws1, name, ws2));
            },
            _ => { content.push(n); },
        }
    }

    let mut gen = Generator::new();
    gen.path_based_name(ast, path);
    if !blocks.is_empty() {
        if base.is_none() {
            gen.define_trait(path, &block_names);
        }
        let tmpl_path = match base {
            Some(Expr::StrLit(base_path)) => { base_path },
            _ => { path },
        };
        let trait_nodes = if base.is_none() { Some(&content[..]) } else { None };
        gen.impl_trait(ast, tmpl_path, &blocks, trait_nodes);
        gen.impl_template_for_trait(ast, base.is_some());
    } else {
        gen.impl_template(ast, &content);
    }
    gen.result()
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::fs::File;
use std::path::Path;

fn main() {
    let decoders = [
        "src/cpu/arm.decoder",
        "src/cpu/thumb.decoder"
    ];

    for decoder in decoders.iter() {
        let out_dir = env::var("OUT_DIR").unwrap();
        let filename = Path::new(decoder).file_name().unwrap();
        let out = format!("{}/{}.rs", out_dir, filename.to_os_string().to_str().unwrap());

        Command::new("python3")
            .arg("tools/decoder-gen/decoder-gen.py")
            .arg(decoder)
            .stdout(File::create(out).unwrap())
            .spawn()
            .expect("failed to execute child");

        println!("cargo:rerun-if-changed={}", decoder);
    }
}<commit_msg>build.rs: Fail on decoder-gen failure<commit_after>use std::env;
use std::process::Command;
use std::fs::File;
use std::path::Path;

fn main() {
    let decoders = [
        "src/cpu/arm.decoder",
        "src/cpu/thumb.decoder"
    ];

    for decoder in decoders.iter() {
        let out_dir = env::var("OUT_DIR").unwrap();
        let filename = Path::new(decoder).file_name().unwrap();
        let out = format!("{}/{}.rs", out_dir, filename.to_os_string().to_str().unwrap());

        let decoder_stat = Command::new("python3")
            .arg("tools/decoder-gen/decoder-gen.py")
            .arg(decoder)
            .stdout(File::create(&out).unwrap())
            .output()
            .expect("failed to execute child");

        if !decoder_stat.status.success() {
            use std::io::{stderr, Write};

            eprintln!("ERROR: decoder generation failed on {}!", out);
            eprintln!("Script stderr:");
            stderr().write_all(&decoder_stat.stderr).unwrap();
        }

        println!("cargo:rerun-if-changed={}", decoder);
    }
}
<|endoftext|>


<commit_before>cfg_if! {
    if #[cfg(target_arch = "x86_64")] {
        mod b64;
        pub use self::b64::*;
    } else if #[cfg(any(target_arch = "arm",
                        target_arch = "powerpc",
                        target_arch = "x86"))] {
        mod b32;
        pub use self::b32::*;
    } else {
        // Unknown target_arch
    }
}
<commit_msg>Recognize NetBSD/sparc64 as a generic 64-bit NetBSD<commit_after>cfg_if! {
    if #[cfg(any(target_arch = "sparc64",
                 target_arch = "x86_64"))] {
        mod b64;
        pub use self::b64::*;
    } else if #[cfg(any(target_arch = "arm",
                        target_arch = "powerpc",
                        target_arch = "x86"))] {
        mod b32;
        pub use self::b32::*;
    } else {
        // Unknown target_arch
    }
}
<|endoftext|>


<commit_before>use super::ast as pc_ast;
use crate::base::parser::{get_buffer, expect_token};
use crate::js::parser::parse as parse_js;
use crate::js::ast as js_ast;
use crate::base::tokenizer::{Token, Tokenizer};
use crate::css::parser::parse as parse_css;

pub fn parse<'a>(source: &'a str) -> Result<pc_ast::Node, &'static str> {
  parse_fragment(&mut Tokenizer::new(source))
}

fn parse_fragment<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  let mut children: Vec<pc_ast::Node> = vec![];

  while !tokenizer.is_eof() {
    children.push(parse_node(tokenizer)?);
    tokenizer.eat_whitespace();
  }

  if children.len() == 1 {
    Ok(children.pop().unwrap())
  } else {
    Ok(pc_ast::Node::Fragment(pc_ast::Fragment { children }))
  }
}

fn parse_node<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  tokenizer.eat_whitespace();
  let pos = tokenizer.pos;
  let token = tokenizer.next()?;
  match token {
    Token::SlotOpen => { parse_slot(tokenizer) },
    Token::LessThan => { parse_element(tokenizer) },
    Token::HtmlCommentOpen => {
      let buffer = get_buffer(tokenizer, |tokenizer| {
        let tok = tokenizer.peek(1)?;
        Ok(tok != Token::HtmlCommentClose)
      })?.to_string();
      tokenizer.next()?; // eat -->
      Ok(pc_ast::Node::Comment(pc_ast::ValueObject { value: buffer }))
    },
    Token::BlockOpen => {
      parse_block(tokenizer)
    }
    _ => {
      tokenizer.pos = pos;
      Ok(pc_ast::Node::Text(pc_ast::ValueObject {
        value: get_buffer(tokenizer, |tokenizer| {
          let tok = tokenizer.peek(1)?;
          Ok(
            tok != Token::SlotOpen &&
            tok != Token::LessThan &&
            tok != Token::CloseTag &&
            tok != Token::HtmlCommentOpen &&
            tok != Token::BlockOpen &&
            tok != Token::BlockClose
          )
        })?.to_string()
      }))
    }
  }
}

fn parse_slot<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  let script = parse_slot_script(tokenizer)?;
  Ok(pc_ast::Node::Slot(script))
}

fn parse_slot_script<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<js_ast::Statement, &'static str> {
  let script = get_buffer(tokenizer, |tokenizer| { Ok(tokenizer.peek(1)? != Token::SlotClose) })?.to_string();
  expect_token(tokenizer.next()?, Token::SlotClose)?;
  parse_js(script.as_str())
}

fn parse_element<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  let tag_name = parse_tag_name(tokenizer)?;
  let attributes = parse_attributes(tokenizer)?;

  if tag_name == "style" {
    parse_next_style_element_parts(attributes, tokenizer)
  } else {
    parse_next_basic_element_parts(tag_name, attributes, tokenizer)
  }
}

fn parse_next_basic_element_parts<'a>(tag_name: String, attributes: Vec<pc_ast::Attribute>, tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  let mut children: Vec<pc_ast::Node> = vec![];

  tokenizer.eat_whitespace();

  match tokenizer.next()? {
    Token::SelfCloseTag => {
    },
    Token::GreaterThan => {
      tokenizer.eat_whitespace();
      while !tokenizer.is_eof() && tokenizer.peek(1)? != Token::CloseTag {
        children.push(parse_node(tokenizer)?);
        tokenizer.eat_whitespace();
      }

      expect_token(tokenizer.next()?, Token::CloseTag)?;
      parse_tag_name(tokenizer)?;
      expect_token(tokenizer.next()?, Token::GreaterThan)?;
    },
    _ => {
      return Err("Unexpected token")
    }
  }

  Ok(pc_ast::Node::Element(pc_ast::Element {
    tag_name,
    attributes,
    children
  }))
}

fn parse_block<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  let token = tokenizer.next()?; // eat {{# or {{/
  if let Token::Word(keyword) = token {
    match keyword {
      "if" => parse_if_block(tokenizer),
      _ => {
        Err("Unexpected token")
      }
    }
  } else {
    Err("Unxpected token")
  }
}

fn parse_if_block<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  Ok(pc_ast::Node::Block(pc_ast::Block::Conditional(
    parse_pass_fail_block(tokenizer)?
  )))
}

fn parse_pass_fail_block<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::ConditionalBlock, &'static str> {
  tokenizer.eat_whitespace();
  let js_source = get_buffer(tokenizer, |tokenizer| { Ok(tokenizer.peek(1)? != Token::SlotClose) })?;
  let condition = parse_js(js_source)?;
  expect_token(tokenizer.next()?, Token::SlotClose)?;

  let node = parse_block_children(tokenizer)?;
  let fail = parse_else_block(tokenizer)?;

  Ok(pc_ast::ConditionalBlock::PassFailBlock(
    pc_ast::PassFailBlock {
      condition,
      node,
      fail,
    }
  ))
}

fn parse_block_children<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<Option<Box<pc_ast::Node>>, &'static str> {

  let mut children = vec![];

  // TODO - we don't really want this since whitespace technically renders. Though, right
  // now it's not handled.
  tokenizer.eat_whitespace();

  while !tokenizer.is_eof() && tokenizer.peek(1)? != Token::BlockClose {
    children.push(parse_node(tokenizer)?);
    tokenizer.eat_whitespace();
  }

  let node = if children.len() == 0 {
    None
  } else if children.len() == 1 {
    Some(Box::new(children.pop().unwrap()))
  } else {
    Some(Box::new(pc_ast::Node::Fragment(pc_ast::Fragment {
      children
    })))
  };

  Ok(node)
}

fn parse_else_block<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<Option<Box<pc_ast::ConditionalBlock>>, &'static str> {
  tokenizer.eat_whitespace();
  expect_token(tokenizer.next()?, Token::BlockClose)?;
  tokenizer.eat_whitespace();
  match tokenizer.next()? {
    Token::Word(value) => {
      match value {
        "else" => {
          tokenizer.eat_whitespace();
          match tokenizer.next()? {
            Token::Word(value2) => {
              if value2 == "if" {
                Ok(Some(Box::new(parse_pass_fail_block(tokenizer)?)))
              } else {
                Err("Unexpected token")
              }
            },
            Token::SlotClose => {
              Ok(Some(Box::new(parse_final_condition_block(tokenizer)?)))
            }
            _ => {
              Err("Unexpected token")
            }
          }
        },
        _ => {
          Err("Unexpected token")
        }
      }
    },
    Token::SlotClose => {
      Ok(None)
    },
    _ => {
      Err("Unexpected token")
    }
  }
}

fn parse_final_condition_block<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::ConditionalBlock, &'static str> {
  let node =  parse_block_children(tokenizer)?;
  expect_token(tokenizer.next()?, Token::BlockClose)?;
  expect_token(tokenizer.next()?, Token::SlotClose)?;
  Ok(pc_ast::ConditionalBlock::FinalBlock(pc_ast::FinalBlock {
    node
  }))
}

fn parse_next_style_element_parts<'a>(attributes: Vec<pc_ast::Attribute>, tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  tokenizer.next()?; // eat >
  let sheet_source = get_buffer(tokenizer, |tokenizer| {
    Ok(tokenizer.peek(1)? != Token::CloseTag && tokenizer.peek(2)? != Token::Word("style"))
  })?;

  // TODO - assert tokens equal these
  expect_token(tokenizer.next()?, Token::CloseTag)?; // eat </
  expect_token(tokenizer.next()?, Token::Word("style"))?; // eat style
  expect_token(tokenizer.next()?, Token::GreaterThan)?; // eat >

  Ok(pc_ast::Node::StyleElement(pc_ast::StyleElement {
    attributes,
    sheet: parse_css(&sheet_source)?
  }))
}

fn parse_tag_name<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<String, &'static str> {
  Ok(get_buffer(tokenizer, |tokenizer| { Ok(!matches!(tokenizer.peek(1)?, Token::Whitespace | Token::GreaterThan | Token::Equals)) })?.to_string())
}

fn parse_attributes<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<Vec<pc_ast::Attribute>, &'static str> {

  let mut attributes: Vec<pc_ast::Attribute> = vec![];

  loop {
    tokenizer.eat_whitespace();
    match tokenizer.peek(1)? {
      Token::SelfCloseTag | Token::GreaterThan => break,
      _ => {
        attributes.push(parse_attribute(tokenizer)?);
      }
    }
  }

  Ok(attributes)
}

fn parse_attribute<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Attribute, &'static str> {
  if tokenizer.peek(1)? == Token::SlotOpen {
    tokenizer.next()?;
    parse_shorthand_attribute(tokenizer)
  } else {
    parse_key_value_attribute(tokenizer)
  }
}

fn parse_shorthand_attribute<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Attribute, &'static str> {
  let reference = parse_slot_script(tokenizer)?;

  // TODO - expect script to be reference with path.length === 1

  Ok(pc_ast::Attribute::ShorthandAttribute(pc_ast::ShorthandAttribute {
    reference,
  }))
}

fn parse_key_value_attribute<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Attribute, &'static str> {

  let name = parse_tag_name(tokenizer)?;
  let mut value = None;

  if tokenizer.peek(1)? == Token::Equals {
    tokenizer.next()?; // eat =
    value = Some(parse_attribute_value(tokenizer)?);
  }

  Ok(pc_ast::Attribute::KeyValueAttribute(pc_ast::KeyValueAttribute {
    name,
    value
  }))
}

fn parse_attribute_value<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::AttributeValue, &'static str> {
  match tokenizer.peek(1)? {
    Token::SingleQuote | Token::DoubleQuote => parse_string(tokenizer),
    Token::SlotOpen => parse_attribute_slot(tokenizer),
    _ => Err("Unexpected token")
  }
}

fn parse_attribute_slot<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::AttributeValue, &'static str> {
  expect_token(tokenizer.next()?, Token::SlotOpen)?;
  let script = parse_slot_script(tokenizer)?;
  Ok(pc_ast::AttributeValue::Slot(script))
}

fn parse_string<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::AttributeValue, &'static str> {
  let quote = tokenizer.next()?;
  let value = get_buffer(tokenizer, |tokenizer| { Ok(tokenizer.peek(1)? != quote) })?.to_string();
  tokenizer.next()?; // eat
  Ok(pc_ast::AttributeValue::String(pc_ast::AttributeStringValue { value }))
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn can_parse_various_nodes() {

    let cases = [

      // text blocks
      "text",

      // comments
      "ab ",

      // slots
      "{{ok}}",

      // elements
      "

",
      "

",
      "

",
      "

",

      "

          c {{block}} d {{block}}

          color {{block}}

",

      // mixed elements
    ];

    for i in 0..cases.len() {
      let case = cases[i];

      // TODO - strip whitespace
      let expr = parse(case).unwrap();
      assert_eq!(expr.to_string().replace("\n", "").replace(" ", ""), case.replace("\n", "").replace(" ", ""));
    }
  }
}<commit_msg>add void elements<commit_after>use super::ast as pc_ast;
use crate::base::parser::{get_buffer, expect_token};
use crate::js::parser::parse as parse_js;
use crate::js::ast as js_ast;
use crate::base::tokenizer::{Token, Tokenizer};
use crate::css::parser::parse as parse_css;

/*

void elements: [ 'area',
  'base',
  'basefont',
  'bgsound',
  'br',
  'col',
  'command',
  'embed',
  'frame',
  'hr',
  'image',
  'img',
  'input',
  'isindex',
  'keygen',
  'link',
  'menuitem',
  'meta',
  'nextid',
  'param',
  'source',
  'track',
  'wbr' ]
*/

pub fn parse<'a>(source: &'a str) -> Result<pc_ast::Node, &'static str> {
  parse_fragment(&mut Tokenizer::new(source))
}

fn parse_fragment<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  let mut children: Vec<pc_ast::Node> = vec![];

  while !tokenizer.is_eof() {
    children.push(parse_node(tokenizer)?);
    tokenizer.eat_whitespace();
  }

  if children.len() == 1 {
    Ok(children.pop().unwrap())
  } else {
    Ok(pc_ast::Node::Fragment(pc_ast::Fragment { children }))
  }
}

fn parse_node<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  tokenizer.eat_whitespace();
  let pos = tokenizer.pos;
  let token = tokenizer.next()?;
  match token {
    Token::SlotOpen => { parse_slot(tokenizer) },
    Token::LessThan => { parse_element(tokenizer) },
    Token::HtmlCommentOpen => {
      let buffer = get_buffer(tokenizer, |tokenizer| {
        let tok = tokenizer.peek(1)?;
        Ok(tok != Token::HtmlCommentClose)
      })?.to_string();
      tokenizer.next()?; // eat -->
      Ok(pc_ast::Node::Comment(pc_ast::ValueObject { value: buffer }))
    },
    Token::BlockOpen => {
      parse_block(tokenizer)
    }
    _ => {
      tokenizer.pos = pos;
      Ok(pc_ast::Node::Text(pc_ast::ValueObject {
        value: get_buffer(tokenizer, |tokenizer| {
          let tok = tokenizer.peek(1)?;
          Ok(
            tok != Token::SlotOpen &&
            tok != Token::LessThan &&
            tok != Token::CloseTag &&
            tok != Token::HtmlCommentOpen &&
            tok != Token::BlockOpen &&
            tok != Token::BlockClose
          )
        })?.to_string()
      }))
    }
  }
}

fn parse_slot<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  let script = parse_slot_script(tokenizer)?;
  Ok(pc_ast::Node::Slot(script))
}

fn parse_slot_script<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<js_ast::Statement, &'static str> {
  let script = get_buffer(tokenizer, |tokenizer| { Ok(tokenizer.peek(1)? != Token::SlotClose) })?.to_string();
  expect_token(tokenizer.next()?, Token::SlotClose)?;
  parse_js(script.as_str())
}

fn parse_element<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  let tag_name = parse_tag_name(tokenizer)?;
  let attributes = parse_attributes(tokenizer)?;

  if tag_name == "style" {
    parse_next_style_element_parts(attributes, tokenizer)
  } else {
    parse_next_basic_element_parts(tag_name, attributes, tokenizer)
  }
}

fn parse_next_basic_element_parts<'a>(tag_name: String, attributes: Vec<pc_ast::Attribute>, tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  let mut children: Vec<pc_ast::Node> = vec![];

  tokenizer.eat_whitespace();

  match tokenizer.next()? {
    Token::SelfCloseTag => {
    },
    Token::GreaterThan => {
      tokenizer.eat_whitespace();
      while !tokenizer.is_eof() && tokenizer.peek(1)? != Token::CloseTag {
        children.push(parse_node(tokenizer)?);
        tokenizer.eat_whitespace();
      }

      expect_token(tokenizer.next()?, Token::CloseTag)?;
      parse_tag_name(tokenizer)?;
      expect_token(tokenizer.next()?, Token::GreaterThan)?;
    },
    _ => {
      return Err("Unexpected token")
    }
  }

  Ok(pc_ast::Node::Element(pc_ast::Element {
    tag_name,
    attributes,
    children
  }))
}

fn parse_block<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  let token = tokenizer.next()?; // eat {{# or {{/
  if let Token::Word(keyword) = token {
    match keyword {
      "if" => parse_if_block(tokenizer),
      _ => {
        Err("Unexpected token")
      }
    }
  } else {
    Err("Unxpected token")
  }
}

fn parse_if_block<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  Ok(pc_ast::Node::Block(pc_ast::Block::Conditional(
    parse_pass_fail_block(tokenizer)?
  )))
}

fn parse_pass_fail_block<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::ConditionalBlock, &'static str> {
  tokenizer.eat_whitespace();
  let js_source = get_buffer(tokenizer, |tokenizer| { Ok(tokenizer.peek(1)? != Token::SlotClose) })?;
  let condition = parse_js(js_source)?;
  expect_token(tokenizer.next()?, Token::SlotClose)?;

  let node = parse_block_children(tokenizer)?;
  let fail = parse_else_block(tokenizer)?;

  Ok(pc_ast::ConditionalBlock::PassFailBlock(
    pc_ast::PassFailBlock {
      condition,
      node,
      fail,
    }
  ))
}

fn parse_block_children<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<Option<Box<pc_ast::Node>>, &'static str> {

  let mut children = vec![];

  // TODO - we don't really want this since whitespace technically renders. Though, right
  // now it's not handled.
  tokenizer.eat_whitespace();

  while !tokenizer.is_eof() && tokenizer.peek(1)? != Token::BlockClose {
    children.push(parse_node(tokenizer)?);
    tokenizer.eat_whitespace();
  }

  let node = if children.len() == 0 {
    None
  } else if children.len() == 1 {
    Some(Box::new(children.pop().unwrap()))
  } else {
    Some(Box::new(pc_ast::Node::Fragment(pc_ast::Fragment {
      children
    })))
  };

  Ok(node)
}

fn parse_else_block<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<Option<Box<pc_ast::ConditionalBlock>>, &'static str> {
  tokenizer.eat_whitespace();
  expect_token(tokenizer.next()?, Token::BlockClose)?;
  tokenizer.eat_whitespace();
  match tokenizer.next()? {
    Token::Word(value) => {
      match value {
        "else" => {
          tokenizer.eat_whitespace();
          match tokenizer.next()? {
            Token::Word(value2) => {
              if value2 == "if" {
                Ok(Some(Box::new(parse_pass_fail_block(tokenizer)?)))
              } else {
                Err("Unexpected token")
              }
            },
            Token::SlotClose => {
              Ok(Some(Box::new(parse_final_condition_block(tokenizer)?)))
            }
            _ => {
              Err("Unexpected token")
            }
          }
        },
        _ => {
          Err("Unexpected token")
        }
      }
    },
    Token::SlotClose => {
      Ok(None)
    },
    _ => {
      Err("Unexpected token")
    }
  }
}

fn parse_final_condition_block<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::ConditionalBlock, &'static str> {
  let node =  parse_block_children(tokenizer)?;
  expect_token(tokenizer.next()?, Token::BlockClose)?;
  expect_token(tokenizer.next()?, Token::SlotClose)?;
  Ok(pc_ast::ConditionalBlock::FinalBlock(pc_ast::FinalBlock {
    node
  }))
}

fn parse_next_style_element_parts<'a>(attributes: Vec<pc_ast::Attribute>, tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Node, &'static str> {
  tokenizer.next()?; // eat >
  let sheet_source = get_buffer(tokenizer, |tokenizer| {
    Ok(tokenizer.peek(1)? != Token::CloseTag && tokenizer.peek(2)? != Token::Word("style"))
  })?;

  // TODO - assert tokens equal these
  expect_token(tokenizer.next()?, Token::CloseTag)?; // eat </
  expect_token(tokenizer.next()?, Token::Word("style"))?; // eat style
  expect_token(tokenizer.next()?, Token::GreaterThan)?; // eat >

  Ok(pc_ast::Node::StyleElement(pc_ast::StyleElement {
    attributes,
    sheet: parse_css(&sheet_source)?
  }))
}

fn parse_tag_name<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<String, &'static str> {
  Ok(get_buffer(tokenizer, |tokenizer| { Ok(!matches!(tokenizer.peek(1)?, Token::Whitespace | Token::GreaterThan | Token::Equals)) })?.to_string())
}

fn parse_attributes<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<Vec<pc_ast::Attribute>, &'static str> {

  let mut attributes: Vec<pc_ast::Attribute> = vec![];

  loop {
    tokenizer.eat_whitespace();
    match tokenizer.peek(1)? {
      Token::SelfCloseTag | Token::GreaterThan => break,
      _ => {
        attributes.push(parse_attribute(tokenizer)?);
      }
    }
  }

  Ok(attributes)
}

fn parse_attribute<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Attribute, &'static str> {
  if tokenizer.peek(1)? == Token::SlotOpen {
    tokenizer.next()?;
    parse_shorthand_attribute(tokenizer)
  } else {
    parse_key_value_attribute(tokenizer)
  }
}

fn parse_shorthand_attribute<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Attribute, &'static str> {
  let reference = parse_slot_script(tokenizer)?;

  // TODO - expect script to be reference with path.length === 1

  Ok(pc_ast::Attribute::ShorthandAttribute(pc_ast::ShorthandAttribute {
    reference,
  }))
}

fn parse_key_value_attribute<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::Attribute, &'static str> {

  let name = parse_tag_name(tokenizer)?;
  let mut value = None;

  if tokenizer.peek(1)? == Token::Equals {
    tokenizer.next()?; // eat =
    value = Some(parse_attribute_value(tokenizer)?);
  }

  Ok(pc_ast::Attribute::KeyValueAttribute(pc_ast::KeyValueAttribute {
    name,
    value
  }))
}

fn parse_attribute_value<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::AttributeValue, &'static str> {
  match tokenizer.peek(1)? {
    Token::SingleQuote | Token::DoubleQuote => parse_string(tokenizer),
    Token::SlotOpen => parse_attribute_slot(tokenizer),
    _ => Err("Unexpected token")
  }
}

fn parse_attribute_slot<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::AttributeValue, &'static str> {
  expect_token(tokenizer.next()?, Token::SlotOpen)?;
  let script = parse_slot_script(tokenizer)?;
  Ok(pc_ast::AttributeValue::Slot(script))
}

fn parse_string<'a>(tokenizer: &mut Tokenizer<'a>) -> Result<pc_ast::AttributeValue, &'static str> {
  let quote = tokenizer.next()?;
  let value = get_buffer(tokenizer, |tokenizer| { Ok(tokenizer.peek(1)? != quote) })?.to_string();
  tokenizer.next()?; // eat
  Ok(pc_ast::AttributeValue::String(pc_ast::AttributeStringValue { value }))
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn can_parse_various_nodes() {

    let cases = [

      // text blocks
      "text",

      // comments
      "ab ",

      // slots
      "{{ok}}",

      // elements
      "

",
      "

",
      "

",
      "

",

      "

          c {{block}} d {{block}}

          color {{block}}

",

      // mixed elements
    ];

    for i in 0..cases.len() {
      let case = cases[i];

      // TODO - strip whitespace
      let expr = parse(case).unwrap();
      assert_eq!(expr.to_string().replace("\n", "").replace(" ", ""), case.replace("\n", "").replace(" ", ""));
    }
  }
}<|endoftext|>


<commit_before>use std::io;
use std::path::Path;
use std::fs::File;

extern crate intercom_common;
extern crate failure;

use intercom_common::tyhandlers::TypeSystem;
use intercom_common::generators;

#[macro_use]
extern crate clap;
use clap::{App, AppSettings, SubCommand, Arg, ArgMatches};

/// Main entry point.
fn main() {

    // Define the command line arguments using clap.
    let matches = App::new( "Rust COM utility" )
            .version( crate_version!() )
            .author( "Mikko Rantanen <rantanen@jubjubnest.net>" )
            .setting( AppSettings::SubcommandRequiredElseHelp )
            .subcommand( SubCommand::with_name( "idl" )
                .about( "Generates IDL file from the Rust crate" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
                .arg( Arg::with_name( "all" )
                    .long( "all" )
                    .help( "Include all type system interfaces in the IDL" )
                )
            )
            .subcommand( SubCommand::with_name( "manifest" )
                .about( "Generates a manifest file for the Rust crate for \
                            registration free COM" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
            )
            .subcommand( SubCommand::with_name( "cpp" )
                .about( "Generates C++ header files from the Rust crate" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
                .arg( Arg::with_name( "output" )
                   .help( "Target where the C++ header file and associated library implementation are generated." )
                   .default_value( "." )
                   .index( 2 )
                )
                .arg( Arg::with_name( "all" )
                    .long( "all" )
                    .help( "Include all type system interfaces in the IDL" )
                )
            )
        .get_matches();

    // Run the command and report possible errors.
    if let Err( e ) = run_cmd( &matches ) {
        eprintln!( "{}", e );
    }
}

fn run_cmd( matches : &ArgMatches ) -> Result<(), failure::Error>
{
    match matches.subcommand() {
        ( "idl", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            let all = args.is_present( "all" );
            let model = generators::idl::IdlModel::from_path( path, all )?;
            model.write( &mut io::stdout() )?;
        },
        ( "manifest", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            let model = generators::manifest::ManifestModel::from_path( path )?;
            model.write( &mut io::stdout() )?;
        },
        ( "cpp", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            let all = args.is_present( "all" );
            let model = generators::cpp::CppModel::from_path( path, all )?;

            let output = Path::new( args.value_of( "output" ).unwrap() );
            std::fs::create_dir_all( output ).expect( "Preparing output failed." );
            model.write_header( &mut File::create(
                    output.join( format!( "{}.hpp", model.lib_name ) ) )? )?;
            model.write_source( &mut File::create(
                    output.join( format!( "{}.cpp", model.lib_name ) ) )? )?;
        },
        _ => unreachable!(),
    }

    Ok(())
}
<commit_msg>Remove unused import<commit_after>use std::io;
use std::path::Path;
use std::fs::File;

extern crate intercom_common;
extern crate failure;

use intercom_common::generators;

#[macro_use]
extern crate clap;
use clap::{App, AppSettings, SubCommand, Arg, ArgMatches};

/// Main entry point.
fn main() {

    // Define the command line arguments using clap.
    let matches = App::new( "Rust COM utility" )
            .version( crate_version!() )
            .author( "Mikko Rantanen <rantanen@jubjubnest.net>" )
            .setting( AppSettings::SubcommandRequiredElseHelp )
            .subcommand( SubCommand::with_name( "idl" )
                .about( "Generates IDL file from the Rust crate" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
                .arg( Arg::with_name( "all" )
                    .long( "all" )
                    .help( "Include all type system interfaces in the IDL" )
                )
            )
            .subcommand( SubCommand::with_name( "manifest" )
                .about( "Generates a manifest file for the Rust crate for \
                            registration free COM" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
            )
            .subcommand( SubCommand::with_name( "cpp" )
                .about( "Generates C++ header files from the Rust crate" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
                .arg( Arg::with_name( "output" )
                   .help( "Target where the C++ header file and associated library implementation are generated." )
                   .default_value( "." )
                   .index( 2 )
                )
                .arg( Arg::with_name( "all" )
                    .long( "all" )
                    .help( "Include all type system interfaces in the IDL" )
                )
            )
        .get_matches();

    // Run the command and report possible errors.
    if let Err( e ) = run_cmd( &matches ) {
        eprintln!( "{}", e );
    }
}

fn run_cmd( matches : &ArgMatches ) -> Result<(), failure::Error>
{
    match matches.subcommand() {
        ( "idl", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            let all = args.is_present( "all" );
            let model = generators::idl::IdlModel::from_path( path, all )?;
            model.write( &mut io::stdout() )?;
        },
        ( "manifest", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            let model = generators::manifest::ManifestModel::from_path( path )?;
            model.write( &mut io::stdout() )?;
        },
        ( "cpp", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            let all = args.is_present( "all" );
            let model = generators::cpp::CppModel::from_path( path, all )?;

            let output = Path::new( args.value_of( "output" ).unwrap() );
            std::fs::create_dir_all( output ).expect( "Preparing output failed." );
            model.write_header( &mut File::create(
                    output.join( format!( "{}.hpp", model.lib_name ) ) )? )?;
            model.write_source( &mut File::create(
                    output.join( format!( "{}.cpp", model.lib_name ) ) )? )?;
        },
        _ => unreachable!(),
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::ast;
use syntax::ast::P;
use syntax::ext::base::ExtCtxt;
use syntax::codemap::DUMMY_SP;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::super::node;
use super::utils;

/// A visitor to build the field setters for primitive registers
pub struct BuildSetters<'a, 'b, 'c> {
  builder: &'a mut Builder,
  cx: &'b ExtCtxt<'c>,
}

impl<'a, 'b, 'c> BuildSetters<'a, 'b, 'c> {
  pub fn new(builder: &'a mut Builder, cx: &'b ExtCtxt<'c>)
             -> BuildSetters<'a, 'b, 'c> {
    BuildSetters { builder: builder, cx: cx }
  }
}

impl<'a, 'b, 'c> node::RegVisitor for BuildSetters<'a, 'b, 'c> {
  fn visit_prim_reg<'a>(&'a mut self, path: &Vec<String>,
      reg: &'a node::Reg, _width: node::RegWidth, fields: &Vec<node::Field>)
  {
    if fields.iter().any(|f| f.access != node::ReadOnly) {
      let it = build_type(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_drop(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_impl(self.cx, path, reg, fields);
      self.builder.push_item(it);
    }
  }
}

fn build_type<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _fields: &Vec<node::Field>) -> P<ast::Item>
{
  let packed_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let name = utils::setter_name(cx, path);
  let reg_ty = cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));

  let reg_doc = match reg.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Update value of `{}` register: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let item = quote_item!(cx,
    $doc_attr
    #[allow(non_camel_case_types)]
    pub struct $name<'a> {
      value: $packed_ty,
      mask: $packed_ty,
      reg: &'a $reg_ty,
    }
  );
  item.unwrap()
}

fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec<String>)
                 -> P<ast::Item> {
  let reg_ty: P<ast::Ty> =
    cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let item = quote_item!(cx,
    #[doc="Create a new updater"]
    pub fn new(reg: &'a $reg_ty) -> $setter_ty {
      $setter_ty {
        value: 0,
        mask: 0,
        reg: reg,
      }
    });
  item.unwrap()
}

fn build_drop<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, fields: &Vec<node::Field>) -> P<ast::Item>
{
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");

  // ensure we don't unintentionally clear a set-to-clear flag
  let mut clear: u32 = 0;
  for f in fields.iter() {
    match f.access {
      node::SetToClear => {
        let mask = 1 << (f.count.node * f.width) - 1;
        clear |= mask;
      },
      _ => {},
    }
  }

  // no need to read write-only registers
  let wo_reg: bool = fields.iter().all(|f| f.access == node::WriteOnly);
  let initial_value =
    if wo_reg {
      quote_expr!(cx, 0)
    } else {
      quote_expr!(cx, self.reg.value.get())
    };

  let item = quote_item!(cx,
    #[unsafe_destructor]
    #[doc = "This performs the register update"]
    impl<'a> Drop for $setter_ty<'a> {
      fn drop(&mut self) {
        let clear_mask: $unpacked_ty = $clear as $unpacked_ty;
        if self.mask != 0 {
          let v: $unpacked_ty = $initial_value & ! clear_mask & ! self.mask;
          self.reg.value.set(self.value | v);
        }
      }
    }
  );
  item.unwrap()
}

fn build_done<'a>(cx: &'a ExtCtxt) -> P<ast::Method>
{
  quote_method!(cx,
    #[doc="Commit changes to register. This is to allow chains of `set_*` \
           invocations to be used as a statement."]
    pub fn done(self) {}
  )
}

fn build_impl<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                  fields: &Vec<node::Field>) -> P<ast::Item>
{
  let new = build_new(cx, path);
  let setter_ty: P<ast::Ty> = cx.ty_ident(
    DUMMY_SP,
    utils::setter_name(cx, path));
  let methods: Vec<P<ast::Method>> =
    FromIterator::from_iter(
      fields.iter()
        .filter_map(|field| build_field_fn(cx, path, reg, field)));
  let done: P<ast::Method> = build_done(cx);
  let impl_ = quote_item!(cx,
    #[allow(dead_code)]
    impl<'a> $setter_ty<'a> {
      $new
      $methods
      $done
    }
    );
  impl_.unwrap()
}

fn build_field_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                      field: &node::Field) -> Option<P<ast::Method>>
{
  match field.access {
    node::ReadOnly => None,
    node::SetToClear => Some(build_field_clear_fn(cx, path, reg, field)),
    _ => Some(build_field_set_fn(cx, path, reg, field)),
  }
}

/// Build a setter for a field
fn build_field_set_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                          field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let fn_name =
    cx.ident_of((String::from_str("set_")+field.name.node).as_slice());
  let field_ty: P<ast::Ty> =
    cx.ty_path(utils::field_type_path(cx, path, reg, field), None);
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Set value of `{}` field: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, new_value: $field_ty)
          -> &'b mut $setter_ty<'a> {
        self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, idx: uint, new_value: $field_ty)
          -> &'b mut $setter_ty<'a> {
        self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  }
}

fn build_field_clear_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    _: &node::Reg, field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let fn_name =
    cx.ident_of((String::from_str("clear_")+field.name.node).as_slice());
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Clear `{}` flag: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self) -> &'b mut $setter_ty<'a> {
        self.value |= $mask << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, idx: uint) -> &'b mut $setter_ty<'a> {
        self.value |= $mask << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  }
}
<commit_msg>ioreg::setter: Associate correct span with Setter type<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::gc::GC;
use syntax::ast;
use syntax::ast::P;
use syntax::ext::base::ExtCtxt;
use syntax::codemap::DUMMY_SP;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::super::node;
use super::utils;

/// A visitor to build the field setters for primitive registers
pub struct BuildSetters<'a, 'b, 'c> {
  builder: &'a mut Builder,
  cx: &'b ExtCtxt<'c>,
}

impl<'a, 'b, 'c> BuildSetters<'a, 'b, 'c> {
  pub fn new(builder: &'a mut Builder, cx: &'b ExtCtxt<'c>)
             -> BuildSetters<'a, 'b, 'c> {
    BuildSetters { builder: builder, cx: cx }
  }
}

impl<'a, 'b, 'c> node::RegVisitor for BuildSetters<'a, 'b, 'c> {
  fn visit_prim_reg<'a>(&'a mut self, path: &Vec<String>,
      reg: &'a node::Reg, _width: node::RegWidth, fields: &Vec<node::Field>)
  {
    if fields.iter().any(|f| f.access != node::ReadOnly) {
      let it = build_type(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_drop(self.cx, path, reg, fields);
      self.builder.push_item(it);

      let it = build_impl(self.cx, path, reg, fields);
      self.builder.push_item(it);
    }
  }
}

fn build_type<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _fields: &Vec<node::Field>) -> P<ast::Item>
{
  let packed_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let name = utils::setter_name(cx, path);
  let reg_ty = cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));

  let reg_doc = match reg.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Update value of `{}` register: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let item = quote_item!(cx,
    $doc_attr
    #[allow(non_camel_case_types)]
    pub struct $name<'a> {
      value: $packed_ty,
      mask: $packed_ty,
      reg: &'a $reg_ty,
    }
  );
  let mut item: ast::Item = item.unwrap().deref().clone();
  item.span = reg.name.span;
  box(GC) item
}

fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec<String>)
                 -> P<ast::Item> {
  let reg_ty: P<ast::Ty> =
    cx.ty_ident(DUMMY_SP, utils::path_ident(cx, path));
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let item = quote_item!(cx,
    #[doc="Create a new updater"]
    pub fn new(reg: &'a $reg_ty) -> $setter_ty {
      $setter_ty {
        value: 0,
        mask: 0,
        reg: reg,
      }
    });
  item.unwrap()
}

fn build_drop<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, fields: &Vec<node::Field>) -> P<ast::Item>
{
  let setter_ty: P<ast::Ty> = cx.ty_ident(DUMMY_SP,
                                          utils::setter_name(cx, path));
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");

  // ensure we don't unintentionally clear a set-to-clear flag
  let mut clear: u32 = 0;
  for f in fields.iter() {
    match f.access {
      node::SetToClear => {
        let mask = 1 << (f.count.node * f.width) - 1;
        clear |= mask;
      },
      _ => {},
    }
  }

  // no need to read write-only registers
  let wo_reg: bool = fields.iter().all(|f| f.access == node::WriteOnly);
  let initial_value =
    if wo_reg {
      quote_expr!(cx, 0)
    } else {
      quote_expr!(cx, self.reg.value.get())
    };

  let item = quote_item!(cx,
    #[unsafe_destructor]
    #[doc = "This performs the register update"]
    impl<'a> Drop for $setter_ty<'a> {
      fn drop(&mut self) {
        let clear_mask: $unpacked_ty = $clear as $unpacked_ty;
        if self.mask != 0 {
          let v: $unpacked_ty = $initial_value & ! clear_mask & ! self.mask;
          self.reg.value.set(self.value | v);
        }
      }
    }
  );
  item.unwrap()
}

fn build_done<'a>(cx: &'a ExtCtxt) -> P<ast::Method>
{
  quote_method!(cx,
    #[doc="Commit changes to register. This is to allow chains of `set_*` \
           invocations to be used as a statement."]
    pub fn done(self) {}
  )
}

fn build_impl<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                  fields: &Vec<node::Field>) -> P<ast::Item>
{
  let new = build_new(cx, path);
  let setter_ty: P<ast::Ty> = cx.ty_ident(
    DUMMY_SP,
    utils::setter_name(cx, path));
  let methods: Vec<P<ast::Method>> =
    FromIterator::from_iter(
      fields.iter()
        .filter_map(|field| build_field_fn(cx, path, reg, field)));
  let done: P<ast::Method> = build_done(cx);
  let impl_ = quote_item!(cx,
    #[allow(dead_code)]
    impl<'a> $setter_ty<'a> {
      $new
      $methods
      $done
    }
    );
  impl_.unwrap()
}

fn build_field_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                      field: &node::Field) -> Option<P<ast::Method>>
{
  match field.access {
    node::ReadOnly => None,
    node::SetToClear => Some(build_field_clear_fn(cx, path, reg, field)),
    _ => Some(build_field_set_fn(cx, path, reg, field)),
  }
}

/// Build a setter for a field
fn build_field_set_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg,
                          field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let unpacked_ty = utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive register");
  let fn_name =
    cx.ident_of((String::from_str("set_")+field.name.node).as_slice());
  let field_ty: P<ast::Ty> =
    cx.ty_path(utils::field_type_path(cx, path, reg, field), None);
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Set value of `{}` field: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, new_value: $field_ty)
          -> &'b mut $setter_ty<'a> {
        self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, idx: uint, new_value: $field_ty)
          -> &'b mut $setter_ty<'a> {
        self.value |= (self.value & ! $mask) | ((new_value as $unpacked_ty) & $mask) << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  }
}

fn build_field_clear_fn<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
    _: &node::Reg, field: &node::Field) -> P<ast::Method>
{
  let setter_ty = utils::setter_name(cx, path);
  let fn_name =
    cx.ident_of((String::from_str("clear_")+field.name.node).as_slice());
  let mask = utils::mask(cx, field);

  let field_doc = match field.docstring {
    Some(d) => token::get_ident(d.node).get().into_string(),
    None => "no documentation".into_string(),
  };
  let docstring = format!("Clear `{}` flag: {}",
                          field.name.node,
                          field_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  if field.count.node == 1 {
    let shift = utils::shift(cx, None, field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self) -> &'b mut $setter_ty<'a> {
        self.value |= $mask << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  } else {
    let shift = utils::shift(cx, Some(quote_expr!(cx, idx)), field);
    quote_method!(cx,
      $doc_attr
      pub fn $fn_name<'b>(&'b mut self, idx: uint) -> &'b mut $setter_ty<'a> {
        self.value |= $mask << $shift;
        self.mask |= $mask << $shift;
        self
      }
    )
  }
}
<|endoftext|>


<commit_before>// mandelbrot.rs
// Calulate Mandelbrot sets in Rust
//
// vim: ft=rust sw=4 ts=4
//

use image;
use image::{ImageBuffer, Rgb};
use num_complex::Complex;

// global constant for Mandelbrot set
const R_MAX: f64 = 2.0;
const N_MAX: u8 = 255;

// calculate pixel value
fn pixel_value(x: f64, y: f64) -> u8 {
    let z0 = Complex::new(x, y);
    let mut z = Complex::new(x, y);
    let mut n = N_MAX;

    while z.norm() <= R_MAX && n > 0 {
        z = z * z + z0;
        n -= 1;
    }

    // return final "index"
    n
}

// convert pixel value to RGB color
fn to_rgb(n: u8) -> image::Rgb<u8> {
    image::Rgb([15 * (n % 15), 32 * (n % 7), 8 * (n % 31)])
}

// convert pixel value to RGB color
fn to_vec(n: u8) -> Vec<u8> {
    vec![15 * (n % 15), 32 * (n % 7), 8 * (n % 31)]
}

// Calculate Mandelbrot set for given image size
pub fn mandelbrot(
    width: u32,
    height: u32,
    center_x: f64,
    center_y: f64,
    pixel_size: f64,
) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
    let x_offset = center_x - 0.5 * pixel_size * width as f64;
    let y_offset = center_y + 0.5 * pixel_size * height as f64;

    ImageBuffer::from_fn(width, height, |x, y| {
        to_rgb(pixel_value(
            x as f64 * pixel_size + x_offset,
            y as f64 * pixel_size - y_offset,
        ))
    })
}

// Calculate Mandelbrot set with multithreading
pub fn mandelbrot_rayon(
    width: u32,
    height: u32,
    center_x: f64,
    center_y: f64,
    pixel_size: f64,
) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
    use rayon::prelude::*;

    let x_offset = center_x - 0.5 * pixel_size * width as f64;
    let y_offset = center_y + 0.5 * pixel_size * height as f64;

    let buf: Vec<_> = (0..width * height)
        .into_par_iter()
        .map(|i| {
            let x = i % width;
            let y = i / width;
            to_vec(pixel_value(
                x as f64 * pixel_size + x_offset,
                y as f64 * pixel_size - y_offset,
            ))
        }).flatten()
        .collect();

    let img: ImageBuffer<Rgb<u8>, Vec<u8>> =
        image::ImageBuffer::from_vec(width, height, buf).unwrap();
    img
}
<commit_msg>skeleton for mutlithreaded Mandelbrot set<commit_after>// mandelbrot.rs
// Calulate Mandelbrot sets in Rust
//
// vim: ft=rust sw=4 ts=4
//

use image;
use image::{ImageBuffer, Rgb};
use num_complex::Complex;

// global constant for Mandelbrot set
const R_MAX: f64 = 2.0;
const N_MAX: u8 = 255;

// calculate pixel value
fn pixel_value(x: f64, y: f64) -> u8 {
    let z0 = Complex::new(x, y);
    let mut z = Complex::new(x, y);
    let mut n = N_MAX;

    while z.norm() <= R_MAX && n > 0 {
        z = z * z + z0;
        n -= 1;
    }

    // return final "index"
    n
}

// convert pixel value to RGB color
fn to_rgb(n: u8) -> image::Rgb<u8> {
    image::Rgb([15 * (n % 15), 32 * (n % 7), 8 * (n % 31)])
}

// convert pixel value to RGB color
fn to_vec(n: u8) -> Vec<u8> {
    vec![15 * (n % 15), 32 * (n % 7), 8 * (n % 31)]
}

// Calculate Mandelbrot set for given image size
pub fn mandelbrot(
    width: u32,
    height: u32,
    center_x: f64,
    center_y: f64,
    pixel_size: f64,
) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
    let x_offset = center_x - 0.5 * pixel_size * width as f64;
    let y_offset = center_y + 0.5 * pixel_size * height as f64;

    ImageBuffer::from_fn(width, height, |x, y| {
        to_rgb(pixel_value(
            x as f64 * pixel_size + x_offset,
            y as f64 * pixel_size - y_offset,
        ))
    })
}

// Calculate Mandelbrot set with multithreading
pub fn mandelbrot_rayon(
    width: u32,
    height: u32,
    center_x: f64,
    center_y: f64,
    pixel_size: f64,
) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
    use rayon::prelude::*;

    let x_offset = center_x - 0.5 * pixel_size * width as f64;
    let y_offset = center_y + 0.5 * pixel_size * height as f64;

    let buf: Vec<_> = (0..width * height)
        .into_par_iter()
        .map(|i| {
            let x = i % width;
            let y = i / width;
            to_vec(pixel_value(
                x as f64 * pixel_size + x_offset,
                y as f64 * pixel_size - y_offset,
            ))
        }).flatten()
        .collect();

    let img: ImageBuffer<Rgb<u8>, Vec<u8>> =
        image::ImageBuffer::from_vec(width, height, buf).unwrap();
    img
}
#[allow(dead_code)]
pub fn mandelbrot_rayon2(
    width: u32,
    height: u32,
    //center_x: f64,
    //center_y: f64,
    //pixel_size: f64,
) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
    ImageBuffer::new(width, height)
}
<|endoftext|>