<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/. */

//! Element nodes.

use dom::attr::Attr;
use dom::attrlist::AttrList;
use dom::bindings::utils::{Reflectable, DOMString, ErrorResult, Fallible, Reflector};
use dom::bindings::utils::{null_str_as_empty, NamespaceError};
use dom::bindings::utils::{InvalidCharacter, QName, Name, InvalidXMLName, xml_name_type};
use dom::htmlcollection::HTMLCollection;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::document::AbstractDocument;
use dom::node::{AbstractNode, ElementNodeTypeId, Node};
use dom::document;
use dom::namespace;
use dom::namespace::{Namespace, Null};
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
use layout_interface::{MatchSelectorsDocumentDamage};
use style;

use std::str::eq;
use std::ascii::StrAsciiExt;

pub struct Element {
    node: Node,
    tag_name: ~str,     // TODO: This should be an atom, not a ~str.
    namespace: Namespace,
    attrs: ~[@mut Attr],
    style_attribute: Option<style::PropertyDeclarationBlock>,
    attr_list: Option<@mut AttrList>
}

impl Reflectable for Element {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.node.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.node.mut_reflector()
    }
}

#[deriving(Eq)]
pub enum ElementTypeId {
    HTMLElementTypeId,
    HTMLAnchorElementTypeId,
    HTMLAppletElementTypeId,
    HTMLAreaElementTypeId,
    HTMLAudioElementTypeId,
    HTMLBaseElementTypeId,
    HTMLBRElementTypeId,
    HTMLBodyElementTypeId,
    HTMLButtonElementTypeId,
    HTMLCanvasElementTypeId,
    HTMLDataElementTypeId,
    HTMLDataListElementTypeId,
    HTMLDirectoryElementTypeId,
    HTMLDListElementTypeId,
    HTMLDivElementTypeId,
    HTMLEmbedElementTypeId,
    HTMLFieldSetElementTypeId,
    HTMLFontElementTypeId,
    HTMLFormElementTypeId,
    HTMLFrameElementTypeId,
    HTMLFrameSetElementTypeId,
    HTMLHRElementTypeId,
    HTMLHeadElementTypeId,
    HTMLHeadingElementTypeId,
    HTMLHtmlElementTypeId,
    HTMLIframeElementTypeId,
    HTMLImageElementTypeId,
    HTMLInputElementTypeId,
    HTMLLabelElementTypeId,
    HTMLLegendElementTypeId,
    HTMLLinkElementTypeId,
    HTMLLIElementTypeId,
    HTMLMainElementTypeId,
    HTMLMapElementTypeId,
    HTMLMediaElementTypeId,
    HTMLMetaElementTypeId,
    HTMLMeterElementTypeId,
    HTMLModElementTypeId,
    HTMLObjectElementTypeId,
    HTMLOListElementTypeId,
    HTMLOptGroupElementTypeId,
    HTMLOptionElementTypeId,
    HTMLOutputElementTypeId,
    HTMLParagraphElementTypeId,
    HTMLParamElementTypeId,
    HTMLPreElementTypeId,
    HTMLProgressElementTypeId,
    HTMLQuoteElementTypeId,
    HTMLScriptElementTypeId,
    HTMLSelectElementTypeId,
    HTMLSourceElementTypeId,
    HTMLSpanElementTypeId,
    HTMLStyleElementTypeId,
    HTMLTableElementTypeId,
    HTMLTableCaptionElementTypeId,
    HTMLTableCellElementTypeId,
    HTMLTableDataCellElementTypeId,
    HTMLTableHeaderCellElementTypeId,
    HTMLTableColElementTypeId,
    HTMLTableRowElementTypeId,
    HTMLTableSectionElementTypeId,
    HTMLTemplateElementTypeId,
    HTMLTextAreaElementTypeId,
    HTMLTimeElementTypeId,
    HTMLTitleElementTypeId,
    HTMLTrackElementTypeId,
    HTMLUListElementTypeId,
    HTMLVideoElementTypeId,
    HTMLUnknownElementTypeId,
}

//
// Element methods
//

impl Element {
    pub fn new_inherited(type_id: ElementTypeId, tag_name: ~str, namespace: Namespace, document: AbstractDocument) -> Element {
        Element {
            node: Node::new_inherited(ElementNodeTypeId(type_id), document),
            tag_name: tag_name,
            namespace: namespace,
            attrs: ~[],
            attr_list: None,
            style_attribute: None,
        }
    }

    pub fn normalize_attr_name(&self, name: Option<DOMString>) -> ~str {
        //FIXME: Throw for XML-invalid names
        let owner = self.node.owner_doc();
        if owner.document().doctype == document::HTML { // && self.namespace == Namespace::HTML
            null_str_as_empty(&name).to_ascii_lower()
        } else {
            null_str_as_empty(&name)
        }
    }

    pub fn get_attribute(&self,
                         namespace: Namespace,
                         name: &str) -> Option<@mut Attr> {
        // FIXME: only case-insensitive in the HTML namespace (as opposed to SVG, etc.)
        let name = name.to_ascii_lower();
        self.attrs.iter().find(|attr| {
            name == attr.local_name && attr.namespace == namespace
        }).map(|&x| x)
    }

    // FIXME(pcwalton): This is kind of confusingly named relative to the above...
    pub fn get_attr(&self, namespace: Namespace, name: &str) -> Option<~str> {
        self.get_attribute(namespace, name).map(|attr| attr.value.clone())
    }

    pub fn set_attr(&mut self, abstract_self: AbstractNode, name: DOMString, value: DOMString)
                    -> ErrorResult {
        // FIXME: HTML-in-HTML only.
        let name = name.to_ascii_lower();
        self.set_attribute(abstract_self, namespace::Null, name, value)
    }

    pub fn set_attribute(&mut self,
                         abstract_self: AbstractNode,
                         namespace: Namespace,
                         name: DOMString,
                         value: DOMString) -> ErrorResult {
        //FIXME: Throw for XML-invalid names
        //FIXME: Throw for XMLNS-invalid names
        let (prefix, local_name) = if name.contains(":")  {
            let parts: ~[&str] = name.splitn(':', 1).collect();
            (Some(parts[0].to_owned()), parts[1].to_owned())
        } else {
            (None, name.clone())
        };
        match prefix {
            Some(ref prefix_str) => {
                if (namespace == namespace::Null ||
                    (eq(prefix_str, &~"xml") && namespace != namespace::XML) ||
                    (eq(prefix_str, &~"xmlns") && namespace != namespace::XMLNS)) {
                    return Err(NamespaceError);
                }
            },
            None => {}
        }

        self.node.wait_until_safe_to_modify_dom();

        // FIXME: reduce the time of `value.clone()`.
        let mut old_raw_value: Option<DOMString> = None;
        for attr in self.attrs.iter() {
            if attr.local_name == local_name {
                old_raw_value = Some(attr.set_value(value.clone()));
                break;
            }
        }

        if old_raw_value.is_none() {
            let win = self.node.owner_doc().document().window;
            let new_attr = Attr::new_ns(win, local_name.clone(), value.clone(),
                                        name.clone(), namespace.clone(),
                                        prefix);
            self.attrs.push(new_attr);
        }

        if namespace == namespace::Null {
            self.after_set_attr(abstract_self, local_name, value, old_raw_value);
        }
        Ok(())
    }

    fn after_set_attr(&mut self,
                      abstract_self: AbstractNode,
                      local_name: DOMString,
                      value: DOMString,
                      old_value: Option<DOMString>) {

        match local_name.as_slice() {
            "style" => {
                self.style_attribute = Some(style::parse_style_attribute(value))
            }
            "id" => {
                let doc = self.node.owner_doc();
                let doc = doc.mut_document();
                doc.update_idmap(abstract_self, value.clone(), old_value);
            }
            _ => ()
        }

        //XXXjdm We really need something like a vtable so we can call AfterSetAttr.
        //       This hardcoding is awful.
        match abstract_self.type_id() {
            ElementNodeTypeId(HTMLImageElementTypeId) => {
                abstract_self.with_mut_image_element(|image| {
                    image.AfterSetAttr(local_name.clone(), value.clone());
                });
            }
            ElementNodeTypeId(HTMLIframeElementTypeId) => {
                abstract_self.with_mut_iframe_element(|iframe| {
                    iframe.AfterSetAttr(local_name.clone(), value.clone());
                });
            }
            _ => ()
        }

        if abstract_self.is_in_doc() {
            let damage = match local_name.as_slice() {
                "style" | "id" | "class" => MatchSelectorsDocumentDamage,
                _ => ContentChangedDocumentDamage
            };
            let document = self.node.owner_doc();
            document.document().damage_and_reflow(damage);
        }
    }
}

// http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes
impl Element {
    pub fn get_url_attribute(&self, name: &str) -> DOMString {
        // XXX Resolve URL.
        self.get_string_attribute(name)
    }
    pub fn set_url_attribute(&mut self, abstract_self: AbstractNode,
                             name: &str, value: DOMString) {
        self.set_string_attribute(abstract_self, name, value);
    }

    pub fn get_string_attribute(&self, name: &str) -> DOMString {
        match self.get_attr(Null, name) {
            Some(x) => x,
            None => ~""
        }
    }
    pub fn set_string_attribute(&mut self, abstract_self: AbstractNode,
                                name: &str, value: DOMString) {
        assert!(name == name.to_ascii_lower());
        self.set_attribute(abstract_self, Null, name.to_owned(), value);
    }
}

impl Element {
    pub fn TagName(&self) -> DOMString {
        self.tag_name.to_ascii_upper()
    }

    pub fn Id(&self, _abstract_self: AbstractNode) -> DOMString {
        self.get_string_attribute("id")
    }

    pub fn SetId(&mut self, abstract_self: AbstractNode, id: DOMString) {
        self.set_string_attribute(abstract_self, "id", id);
    }

    pub fn Attributes(&mut self, abstract_self: AbstractNode) -> @mut AttrList {
        match self.attr_list {
            None => {
                let window = self.node.owner_doc().document().window;
                let list = AttrList::new(window, abstract_self);
                self.attr_list = Some(list);
                list
            }
            Some(list) => list
        }
    }

    pub fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
        self.get_attr(Null, name).map(|s| s.to_owned())
    }

    pub fn GetAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> Option<DOMString> {
        let namespace = Namespace::from_str(namespace);
        self.get_attribute(namespace, local_name)
            .map(|attr| attr.value.clone())
    }

    pub fn SetAttribute(&mut self, abstract_self: AbstractNode, name: DOMString, value: DOMString)
                        -> ErrorResult {
        self.set_attr(abstract_self, name, value)
    }

    pub fn SetAttributeNS(&mut self,
                          abstract_self: AbstractNode,
                          namespace_url: Option<DOMString>,
                          name: DOMString,
                          value: DOMString) -> ErrorResult {
        let name_type = xml_name_type(name);
        match name_type {
            InvalidXMLName => return Err(InvalidCharacter),
            Name => return Err(NamespaceError),
            QName => {}
        }

        let namespace = Namespace::from_str(namespace_url);
        self.set_attribute(abstract_self, namespace, name, value)
    }

    pub fn RemoveAttribute(&self, _name: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn RemoveAttributeNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn HasAttribute(&self, name: DOMString) -> bool {
        self.GetAttribute(name).is_some()
    }

    pub fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
        self.GetAttributeNS(namespace, local_name).is_some()
    }

    pub fn GetElementsByTagName(&self, _localname: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn GetElementsByTagNameNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> Fallible<@mut HTMLCollection> {
        Ok(HTMLCollection::new(self.node.owner_doc().document().window, ~[]))
    }

    pub fn GetElementsByClassName(&self, _names: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn MozMatchesSelector(&self, _selector: DOMString) -> Fallible<bool> {
        Ok(false)
    }

    pub fn SetCapture(&self, _retargetToElement: bool) {
    }

    pub fn ReleaseCapture(&self) {
    }

    pub fn MozRequestFullScreen(&self) {
    }

    pub fn MozRequestPointerLock(&self) {
    }

    pub fn GetClientRects(&self, abstract_self: AbstractNode) -> @mut ClientRectList {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = Chan::new();
        let rects =
            match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
                ContentBoxesResponse(rects) => {
                    rects.map(|r| {
                        ClientRect::new(
                            win,
                            r.origin.y,
                            r.origin.y + r.size.height,
                            r.origin.x,
                            r.origin.x + r.size.width)
                    })
                },
            };

        ClientRectList::new(win, rects)
    }

    pub fn GetBoundingClientRect(&self, abstract_self: AbstractNode) -> @mut ClientRect {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = Chan::new();
        match win.page.query_layout(ContentBoxQuery(node, chan), port) {
            ContentBoxResponse(rect) => {
                ClientRect::new(
                    win,
                    rect.origin.y,
                    rect.origin.y + rect.size.height,
                    rect.origin.x,
                    rect.origin.x + rect.size.width)
            }
        }
    }

    pub fn ScrollIntoView(&self, _top: bool) {
    }

    pub fn ScrollTop(&self) -> i32 {
        0
    }

    pub fn SetScrollTop(&mut self, _scroll_top: i32) {
    }

    pub fn ScrollLeft(&self) -> i32 {
        0
    }

    pub fn SetScrollLeft(&mut self, _scroll_left: i32) {
    }

    pub fn ScrollWidth(&self) -> i32 {
        0
    }

    pub fn ScrollHeight(&self) -> i32 {
        0
    }

    pub fn ClientTop(&self) -> i32 {
        0
    }

    pub fn ClientLeft(&self) -> i32 {
        0
    }

    pub fn ClientWidth(&self) -> i32 {
        0
    }

    pub fn ClientHeight(&self) -> i32 {
        0
    }

    pub fn GetInnerHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetInnerHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn GetOuterHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetOuterHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn InsertAdjacentHTML(&mut self, _position: DOMString, _text: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn QuerySelector(&self, _selectors: DOMString) -> Fallible<Option<AbstractNode>> {
        Ok(None)
    }
}
<commit_msg>Split up the utility function to make internal attribute's namespace.<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/. */

//! Element nodes.

use dom::attr::Attr;
use dom::attrlist::AttrList;
use dom::bindings::utils::{Reflectable, DOMString, ErrorResult, Fallible, Reflector};
use dom::bindings::utils::{null_str_as_empty, NamespaceError};
use dom::bindings::utils::{InvalidCharacter, QName, Name, InvalidXMLName, xml_name_type};
use dom::htmlcollection::HTMLCollection;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::document::AbstractDocument;
use dom::node::{AbstractNode, ElementNodeTypeId, Node};
use dom::document;
use dom::namespace;
use dom::namespace::{Namespace, Null};
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse, ContentChangedDocumentDamage};
use layout_interface::{MatchSelectorsDocumentDamage};
use style;

use std::str::eq;
use std::ascii::StrAsciiExt;

pub struct Element {
    node: Node,
    tag_name: ~str,     // TODO: This should be an atom, not a ~str.
    namespace: Namespace,
    attrs: ~[@mut Attr],
    style_attribute: Option<style::PropertyDeclarationBlock>,
    attr_list: Option<@mut AttrList>
}

impl Reflectable for Element {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.node.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.node.mut_reflector()
    }
}

#[deriving(Eq)]
pub enum ElementTypeId {
    HTMLElementTypeId,
    HTMLAnchorElementTypeId,
    HTMLAppletElementTypeId,
    HTMLAreaElementTypeId,
    HTMLAudioElementTypeId,
    HTMLBaseElementTypeId,
    HTMLBRElementTypeId,
    HTMLBodyElementTypeId,
    HTMLButtonElementTypeId,
    HTMLCanvasElementTypeId,
    HTMLDataElementTypeId,
    HTMLDataListElementTypeId,
    HTMLDirectoryElementTypeId,
    HTMLDListElementTypeId,
    HTMLDivElementTypeId,
    HTMLEmbedElementTypeId,
    HTMLFieldSetElementTypeId,
    HTMLFontElementTypeId,
    HTMLFormElementTypeId,
    HTMLFrameElementTypeId,
    HTMLFrameSetElementTypeId,
    HTMLHRElementTypeId,
    HTMLHeadElementTypeId,
    HTMLHeadingElementTypeId,
    HTMLHtmlElementTypeId,
    HTMLIframeElementTypeId,
    HTMLImageElementTypeId,
    HTMLInputElementTypeId,
    HTMLLabelElementTypeId,
    HTMLLegendElementTypeId,
    HTMLLinkElementTypeId,
    HTMLLIElementTypeId,
    HTMLMainElementTypeId,
    HTMLMapElementTypeId,
    HTMLMediaElementTypeId,
    HTMLMetaElementTypeId,
    HTMLMeterElementTypeId,
    HTMLModElementTypeId,
    HTMLObjectElementTypeId,
    HTMLOListElementTypeId,
    HTMLOptGroupElementTypeId,
    HTMLOptionElementTypeId,
    HTMLOutputElementTypeId,
    HTMLParagraphElementTypeId,
    HTMLParamElementTypeId,
    HTMLPreElementTypeId,
    HTMLProgressElementTypeId,
    HTMLQuoteElementTypeId,
    HTMLScriptElementTypeId,
    HTMLSelectElementTypeId,
    HTMLSourceElementTypeId,
    HTMLSpanElementTypeId,
    HTMLStyleElementTypeId,
    HTMLTableElementTypeId,
    HTMLTableCaptionElementTypeId,
    HTMLTableCellElementTypeId,
    HTMLTableDataCellElementTypeId,
    HTMLTableHeaderCellElementTypeId,
    HTMLTableColElementTypeId,
    HTMLTableRowElementTypeId,
    HTMLTableSectionElementTypeId,
    HTMLTemplateElementTypeId,
    HTMLTextAreaElementTypeId,
    HTMLTimeElementTypeId,
    HTMLTitleElementTypeId,
    HTMLTrackElementTypeId,
    HTMLUListElementTypeId,
    HTMLVideoElementTypeId,
    HTMLUnknownElementTypeId,
}

//
// Element methods
//

impl Element {
    pub fn new_inherited(type_id: ElementTypeId, tag_name: ~str, namespace: Namespace, document: AbstractDocument) -> Element {
        Element {
            node: Node::new_inherited(ElementNodeTypeId(type_id), document),
            tag_name: tag_name,
            namespace: namespace,
            attrs: ~[],
            attr_list: None,
            style_attribute: None,
        }
    }

    pub fn normalize_attr_name(&self, name: Option<DOMString>) -> ~str {
        //FIXME: Throw for XML-invalid names
        let owner = self.node.owner_doc();
        if owner.document().doctype == document::HTML { // && self.namespace == Namespace::HTML
            null_str_as_empty(&name).to_ascii_lower()
        } else {
            null_str_as_empty(&name)
        }
    }

    pub fn get_attribute(&self,
                         namespace: Namespace,
                         name: &str) -> Option<@mut Attr> {
        // FIXME: only case-insensitive in the HTML namespace (as opposed to SVG, etc.)
        let name = name.to_ascii_lower();
        self.attrs.iter().find(|attr| {
            name == attr.local_name && attr.namespace == namespace
        }).map(|&x| x)
    }

    // FIXME(pcwalton): This is kind of confusingly named relative to the above...
    pub fn get_attr(&self, namespace: Namespace, name: &str) -> Option<~str> {
        self.get_attribute(namespace, name).map(|attr| attr.value.clone())
    }

    pub fn set_attr(&mut self, abstract_self: AbstractNode, name: DOMString, value: DOMString)
                    -> ErrorResult {
        // FIXME: HTML-in-HTML only.
        let name = name.to_ascii_lower();
        self.set_attribute(abstract_self, namespace::Null, name, value)
    }

    pub fn set_attribute(&mut self,
                         abstract_self: AbstractNode,
                         namespace: Namespace,
                         name: DOMString,
                         value: DOMString) -> ErrorResult {
        let (prefix, local_name) = get_attribute_parts(name.clone());
        match prefix {
            Some(ref prefix_str) => {
                if (namespace == namespace::Null ||
                    (eq(prefix_str, &~"xml") && namespace != namespace::XML) ||
                    (eq(prefix_str, &~"xmlns") && namespace != namespace::XMLNS)) {
                    return Err(NamespaceError);
                }
            },
            None => {}
        }

        self.node.wait_until_safe_to_modify_dom();

        // FIXME: reduce the time of `value.clone()`.
        let mut old_raw_value: Option<DOMString> = None;
        for attr in self.attrs.iter() {
            if attr.local_name == local_name {
                old_raw_value = Some(attr.set_value(value.clone()));
                break;
            }
        }

        if old_raw_value.is_none() {
            let win = self.node.owner_doc().document().window;
            let new_attr = Attr::new_ns(win, local_name.clone(), value.clone(),
                                        name.clone(), namespace.clone(),
                                        prefix);
            self.attrs.push(new_attr);
        }

        if namespace == namespace::Null {
            self.after_set_attr(abstract_self, local_name, value, old_raw_value);
        }
        Ok(())
    }

    fn after_set_attr(&mut self,
                      abstract_self: AbstractNode,
                      local_name: DOMString,
                      value: DOMString,
                      old_value: Option<DOMString>) {

        match local_name.as_slice() {
            "style" => {
                self.style_attribute = Some(style::parse_style_attribute(value))
            }
            "id" => {
                let doc = self.node.owner_doc();
                let doc = doc.mut_document();
                doc.update_idmap(abstract_self, value.clone(), old_value);
            }
            _ => ()
        }

        //XXXjdm We really need something like a vtable so we can call AfterSetAttr.
        //       This hardcoding is awful.
        match abstract_self.type_id() {
            ElementNodeTypeId(HTMLImageElementTypeId) => {
                abstract_self.with_mut_image_element(|image| {
                    image.AfterSetAttr(local_name.clone(), value.clone());
                });
            }
            ElementNodeTypeId(HTMLIframeElementTypeId) => {
                abstract_self.with_mut_iframe_element(|iframe| {
                    iframe.AfterSetAttr(local_name.clone(), value.clone());
                });
            }
            _ => ()
        }

        if abstract_self.is_in_doc() {
            let damage = match local_name.as_slice() {
                "style" | "id" | "class" => MatchSelectorsDocumentDamage,
                _ => ContentChangedDocumentDamage
            };
            let document = self.node.owner_doc();
            document.document().damage_and_reflow(damage);
        }
    }
}

// http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes
impl Element {
    pub fn get_url_attribute(&self, name: &str) -> DOMString {
        // XXX Resolve URL.
        self.get_string_attribute(name)
    }
    pub fn set_url_attribute(&mut self, abstract_self: AbstractNode,
                             name: &str, value: DOMString) {
        self.set_string_attribute(abstract_self, name, value);
    }

    pub fn get_string_attribute(&self, name: &str) -> DOMString {
        match self.get_attr(Null, name) {
            Some(x) => x,
            None => ~""
        }
    }
    pub fn set_string_attribute(&mut self, abstract_self: AbstractNode,
                                name: &str, value: DOMString) {
        assert!(name == name.to_ascii_lower());
        self.set_attribute(abstract_self, Null, name.to_owned(), value);
    }
}

impl Element {
    pub fn TagName(&self) -> DOMString {
        self.tag_name.to_ascii_upper()
    }

    pub fn Id(&self, _abstract_self: AbstractNode) -> DOMString {
        self.get_string_attribute("id")
    }

    pub fn SetId(&mut self, abstract_self: AbstractNode, id: DOMString) {
        self.set_string_attribute(abstract_self, "id", id);
    }

    pub fn Attributes(&mut self, abstract_self: AbstractNode) -> @mut AttrList {
        match self.attr_list {
            None => {
                let window = self.node.owner_doc().document().window;
                let list = AttrList::new(window, abstract_self);
                self.attr_list = Some(list);
                list
            }
            Some(list) => list
        }
    }

    pub fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
        self.get_attr(Null, name).map(|s| s.to_owned())
    }

    pub fn GetAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> Option<DOMString> {
        let namespace = Namespace::from_str(namespace);
        self.get_attribute(namespace, local_name)
            .map(|attr| attr.value.clone())
    }

    pub fn SetAttribute(&mut self, abstract_self: AbstractNode, name: DOMString, value: DOMString)
                        -> ErrorResult {
        self.set_attr(abstract_self, name, value)
    }

    pub fn SetAttributeNS(&mut self,
                          abstract_self: AbstractNode,
                          namespace_url: Option<DOMString>,
                          name: DOMString,
                          value: DOMString) -> ErrorResult {
        let name_type = xml_name_type(name);
        match name_type {
            InvalidXMLName => return Err(InvalidCharacter),
            Name => return Err(NamespaceError),
            QName => {}
        }

        let namespace = Namespace::from_str(namespace_url);
        self.set_attribute(abstract_self, namespace, name, value)
    }

    pub fn RemoveAttribute(&self, _name: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn RemoveAttributeNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn HasAttribute(&self, name: DOMString) -> bool {
        self.GetAttribute(name).is_some()
    }

    pub fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
        self.GetAttributeNS(namespace, local_name).is_some()
    }

    pub fn GetElementsByTagName(&self, _localname: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn GetElementsByTagNameNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> Fallible<@mut HTMLCollection> {
        Ok(HTMLCollection::new(self.node.owner_doc().document().window, ~[]))
    }

    pub fn GetElementsByClassName(&self, _names: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn MozMatchesSelector(&self, _selector: DOMString) -> Fallible<bool> {
        Ok(false)
    }

    pub fn SetCapture(&self, _retargetToElement: bool) {
    }

    pub fn ReleaseCapture(&self) {
    }

    pub fn MozRequestFullScreen(&self) {
    }

    pub fn MozRequestPointerLock(&self) {
    }

    pub fn GetClientRects(&self, abstract_self: AbstractNode) -> @mut ClientRectList {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = Chan::new();
        let rects =
            match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
                ContentBoxesResponse(rects) => {
                    rects.map(|r| {
                        ClientRect::new(
                            win,
                            r.origin.y,
                            r.origin.y + r.size.height,
                            r.origin.x,
                            r.origin.x + r.size.width)
                    })
                },
            };

        ClientRectList::new(win, rects)
    }

    pub fn GetBoundingClientRect(&self, abstract_self: AbstractNode) -> @mut ClientRect {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = Chan::new();
        match win.page.query_layout(ContentBoxQuery(node, chan), port) {
            ContentBoxResponse(rect) => {
                ClientRect::new(
                    win,
                    rect.origin.y,
                    rect.origin.y + rect.size.height,
                    rect.origin.x,
                    rect.origin.x + rect.size.width)
            }
        }
    }

    pub fn ScrollIntoView(&self, _top: bool) {
    }

    pub fn ScrollTop(&self) -> i32 {
        0
    }

    pub fn SetScrollTop(&mut self, _scroll_top: i32) {
    }

    pub fn ScrollLeft(&self) -> i32 {
        0
    }

    pub fn SetScrollLeft(&mut self, _scroll_left: i32) {
    }

    pub fn ScrollWidth(&self) -> i32 {
        0
    }

    pub fn ScrollHeight(&self) -> i32 {
        0
    }

    pub fn ClientTop(&self) -> i32 {
        0
    }

    pub fn ClientLeft(&self) -> i32 {
        0
    }

    pub fn ClientWidth(&self) -> i32 {
        0
    }

    pub fn ClientHeight(&self) -> i32 {
        0
    }

    pub fn GetInnerHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetInnerHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn GetOuterHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetOuterHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn InsertAdjacentHTML(&mut self, _position: DOMString, _text: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn QuerySelector(&self, _selectors: DOMString) -> Fallible<Option<AbstractNode>> {
        Ok(None)
    }
}

fn get_attribute_parts(name: DOMString) -> (Option<~str>, ~str) {
    //FIXME: Throw for XML-invalid names
    //FIXME: Throw for XMLNS-invalid names
    let (prefix, local_name) = if name.contains(":")  {
        let parts: ~[&str] = name.splitn(':', 1).collect();
        (Some(parts[0].to_owned()), parts[1].to_owned())
    } else {
        (None, name)
    };

    (prefix, local_name)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
//
// 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.

//! Sane serialization & deserialization of cryptographic structs into hex

use crate::keychain::BlindingFactor;
use crate::serde::{Deserialize, Deserializer, Serializer};
use crate::util::secp::pedersen::{Commitment, RangeProof};
use crate::util::{from_hex, to_hex};

/// Serializes a secp PublicKey to and from hex
pub mod pubkey_serde {
	use crate::serde::{Deserialize, Deserializer, Serializer};
	use crate::util::secp::key::PublicKey;
	use crate::util::{from_hex, static_secp_instance, to_hex};

	///
	pub fn serialize<S>(key: &PublicKey, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: Serializer,
	{
		let static_secp = static_secp_instance();
		let static_secp = static_secp.lock();
		serializer.serialize_str(&to_hex(key.serialize_vec(&static_secp, false).to_vec()))
	}

	///
	pub fn deserialize<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
	where
		D: Deserializer<'de>,
	{
		use serde::de::Error;
		let static_secp = static_secp_instance();
		let static_secp = static_secp.lock();
		String::deserialize(deserializer)
			.and_then(|string| from_hex(string).map_err(|err| Error::custom(err.to_string())))
			.and_then(|bytes: Vec<u8>| {
				PublicKey::from_slice(&static_secp, &bytes)
					.map_err(|err| Error::custom(err.to_string()))
			})
	}
}

/// Serializes an Option<secp::Signature> to and from hex
pub mod option_sig_serde {
	use crate::serde::{Deserialize, Deserializer, Serializer};
	use crate::util::secp;
	use crate::util::{from_hex, to_hex};
	use serde::de::Error;

	///
	pub fn serialize<S>(sig: &Option<secp::Signature>, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: Serializer,
	{
		match sig {
			Some(sig) => serializer.serialize_str(&to_hex(sig.to_raw_data().to_vec())),
			None => serializer.serialize_none(),
		}
	}

	///
	pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<secp::Signature>, D::Error>
	where
		D: Deserializer<'de>,
	{
		Option::<&str>::deserialize(deserializer).and_then(|res| match res {
			Some(string) => from_hex(string.to_string())
				.map_err(|err| Error::custom(err.to_string()))
				.and_then(|bytes: Vec<u8>| {
					let mut b = [0u8; 64];
					b.copy_from_slice(&bytes[0..64]);
					secp::Signature::from_raw_data(&b)
						.map(|val| Some(val))
						.map_err(|err| Error::custom(err.to_string()))
				}),
			None => Ok(None),
		})
	}

}

/// Serializes a secp::Signature to and from hex
pub mod sig_serde {
	use crate::serde::{Deserialize, Deserializer, Serializer};
	use crate::util::secp;
	use crate::util::static_secp_instance;
	use crate::util::{from_hex, to_hex};
	use serde::de::Error;

	///
	pub fn serialize<S>(sig: &secp::Signature, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: Serializer,
	{
		let static_secp = static_secp_instance();
		let static_secp = static_secp.lock();
		serializer.serialize_str(&to_hex(sig.serialize_der(&static_secp)))
	}

	///
	pub fn deserialize<'de, D>(deserializer: D) -> Result<secp::Signature, D::Error>
	where
		D: Deserializer<'de>,
	{
		let static_secp = static_secp_instance();
		let static_secp = static_secp.lock();
		String::deserialize(deserializer)
			.and_then(|string| from_hex(string).map_err(|err| Error::custom(err.to_string())))
			.and_then(|bytes: Vec<u8>| {
				secp::Signature::from_der(&static_secp, &bytes)
					.map_err(|err| Error::custom(err.to_string()))
			})
	}
}

/// Creates a BlindingFactor from a hex string
pub fn blind_from_hex<'de, D>(deserializer: D) -> Result<BlindingFactor, D::Error>
where
	D: Deserializer<'de>,
{
	use serde::de::Error;
	String::deserialize(deserializer).and_then(|string| {
		BlindingFactor::from_hex(&string).map_err(|err| Error::custom(err.to_string()))
	})
}

/// Creates a RangeProof from a hex string
pub fn rangeproof_from_hex<'de, D>(deserializer: D) -> Result<RangeProof, D::Error>
where
	D: Deserializer<'de>,
{
	use serde::de::{Error, IntoDeserializer};

	let val = String::deserialize(deserializer)
		.and_then(|string| from_hex(string).map_err(|err| Error::custom(err.to_string())))?;
	RangeProof::deserialize(val.into_deserializer())
}

/// Creates a Pedersen Commitment from a hex string
pub fn commitment_from_hex<'de, D>(deserializer: D) -> Result<Commitment, D::Error>
where
	D: Deserializer<'de>,
{
	use serde::de::Error;
	String::deserialize(deserializer)
		.and_then(|string| from_hex(string).map_err(|err| Error::custom(err.to_string())))
		.and_then(|bytes: Vec<u8>| Ok(Commitment::from_vec(bytes.to_vec())))
}

/// Seralizes a byte string into hex
pub fn as_hex<T, S>(bytes: T, serializer: S) -> Result<S::Ok, S::Error>
where
	T: AsRef<[u8]>,
	S: Serializer,
{
	serializer.serialize_str(&to_hex(bytes.as_ref().to_vec()))
}

// Test serialization methods of components that are being used
#[cfg(test)]
mod test {
	use super::*;
	use crate::libtx::aggsig;
	use crate::util::secp::key::{PublicKey, SecretKey};
	use crate::util::secp::{Message, Signature};
	use crate::util::static_secp_instance;

	use serde_json;

	use rand::{thread_rng, Rng};

	#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
	struct SerTest {
		#[serde(with = "pubkey_serde")]
		pub pub_key: PublicKey,
		#[serde(with = "option_sig_serde")]
		pub opt_sig: Option<Signature>,
		#[serde(with = "sig_serde")]
		pub sig: Signature,
	}

	impl SerTest {
		pub fn random() -> SerTest {
			let static_secp = static_secp_instance();
			let secp = static_secp.lock();
			let sk = SecretKey::new(&secp, &mut thread_rng());
			let mut msg = [0u8; 32];
			thread_rng().fill(&mut msg);
			let msg = Message::from_slice(&msg).unwrap();
			let sig = aggsig::sign_single(&secp, &msg, &sk, None).unwrap();
			SerTest {
				pub_key: PublicKey::from_secret_key(&secp, &sk).unwrap(),
				opt_sig: Some(sig.clone()),
				sig: sig.clone(),
			}
		}
	}

	#[test]
	fn ser_secp_primitives() {
		for _ in 0..10 {
			let s = SerTest::random();
			println!("Before Serialization: {:?}", s);
			let serialized = serde_json::to_string_pretty(&s).unwrap();
			println!("JSON: {}", serialized);
			let deserialized: SerTest = serde_json::from_str(&serialized).unwrap();
			println!("After Serialization: {:?}", deserialized);
			println!();
			assert_eq!(s, deserialized);
		}
	}
}
<commit_msg>[1.1.0] Additional secp primitive serialization changes (#2669)<commit_after>// Copyright 2018 The Grin Developers
//
// 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.

//! Sane serialization & deserialization of cryptographic structs into hex

use crate::keychain::BlindingFactor;
use crate::serde::{Deserialize, Deserializer, Serializer};
use crate::util::secp::pedersen::{Commitment, RangeProof};
use crate::util::{from_hex, to_hex};

/// Serializes a secp PublicKey to and from hex
pub mod pubkey_serde {
	use crate::serde::{Deserialize, Deserializer, Serializer};
	use crate::util::secp::key::PublicKey;
	use crate::util::{from_hex, static_secp_instance, to_hex};

	///
	pub fn serialize<S>(key: &PublicKey, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: Serializer,
	{
		let static_secp = static_secp_instance();
		let static_secp = static_secp.lock();
		serializer.serialize_str(&to_hex(key.serialize_vec(&static_secp, true).to_vec()))
	}

	///
	pub fn deserialize<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
	where
		D: Deserializer<'de>,
	{
		use serde::de::Error;
		let static_secp = static_secp_instance();
		let static_secp = static_secp.lock();
		String::deserialize(deserializer)
			.and_then(|string| from_hex(string).map_err(|err| Error::custom(err.to_string())))
			.and_then(|bytes: Vec<u8>| {
				PublicKey::from_slice(&static_secp, &bytes)
					.map_err(|err| Error::custom(err.to_string()))
			})
	}
}

/// Serializes an Option<secp::Signature> to and from hex
pub mod option_sig_serde {
	use crate::serde::{Deserialize, Deserializer, Serializer};
	use crate::util::secp;
	use crate::util::{from_hex, to_hex};
	use serde::de::Error;

	///
	pub fn serialize<S>(sig: &Option<secp::Signature>, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: Serializer,
	{
		match sig {
			Some(sig) => serializer.serialize_str(&to_hex(sig.to_raw_data().to_vec())),
			None => serializer.serialize_none(),
		}
	}

	///
	pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<secp::Signature>, D::Error>
	where
		D: Deserializer<'de>,
	{
		Option::<&str>::deserialize(deserializer).and_then(|res| match res {
			Some(string) => from_hex(string.to_string())
				.map_err(|err| Error::custom(err.to_string()))
				.and_then(|bytes: Vec<u8>| {
					let mut b = [0u8; 64];
					b.copy_from_slice(&bytes[0..64]);
					secp::Signature::from_raw_data(&b)
						.map(|val| Some(val))
						.map_err(|err| Error::custom(err.to_string()))
				}),
			None => Ok(None),
		})
	}

}

/// Serializes a secp::Signature to and from hex
pub mod sig_serde {
	use crate::serde::{Deserialize, Deserializer, Serializer};
	use crate::util::secp;
	use crate::util::{from_hex, to_hex};
	use serde::de::Error;

	///
	pub fn serialize<S>(sig: &secp::Signature, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: Serializer,
	{
		serializer.serialize_str(&to_hex(sig.to_raw_data().to_vec()))
	}

	///
	pub fn deserialize<'de, D>(deserializer: D) -> Result<secp::Signature, D::Error>
	where
		D: Deserializer<'de>,
	{
		String::deserialize(deserializer)
			.and_then(|string| from_hex(string).map_err(|err| Error::custom(err.to_string())))
			.and_then(|bytes: Vec<u8>| {
				let mut b = [0u8; 64];
				b.copy_from_slice(&bytes[0..64]);
				secp::Signature::from_raw_data(&b).map_err(|err| Error::custom(err.to_string()))
			})
	}
}

/// Creates a BlindingFactor from a hex string
pub fn blind_from_hex<'de, D>(deserializer: D) -> Result<BlindingFactor, D::Error>
where
	D: Deserializer<'de>,
{
	use serde::de::Error;
	String::deserialize(deserializer).and_then(|string| {
		BlindingFactor::from_hex(&string).map_err(|err| Error::custom(err.to_string()))
	})
}

/// Creates a RangeProof from a hex string
pub fn rangeproof_from_hex<'de, D>(deserializer: D) -> Result<RangeProof, D::Error>
where
	D: Deserializer<'de>,
{
	use serde::de::{Error, IntoDeserializer};

	let val = String::deserialize(deserializer)
		.and_then(|string| from_hex(string).map_err(|err| Error::custom(err.to_string())))?;
	RangeProof::deserialize(val.into_deserializer())
}

/// Creates a Pedersen Commitment from a hex string
pub fn commitment_from_hex<'de, D>(deserializer: D) -> Result<Commitment, D::Error>
where
	D: Deserializer<'de>,
{
	use serde::de::Error;
	String::deserialize(deserializer)
		.and_then(|string| from_hex(string).map_err(|err| Error::custom(err.to_string())))
		.and_then(|bytes: Vec<u8>| Ok(Commitment::from_vec(bytes.to_vec())))
}

/// Seralizes a byte string into hex
pub fn as_hex<T, S>(bytes: T, serializer: S) -> Result<S::Ok, S::Error>
where
	T: AsRef<[u8]>,
	S: Serializer,
{
	serializer.serialize_str(&to_hex(bytes.as_ref().to_vec()))
}

// Test serialization methods of components that are being used
#[cfg(test)]
mod test {
	use super::*;
	use crate::libtx::aggsig;
	use crate::util::secp::key::{PublicKey, SecretKey};
	use crate::util::secp::{Message, Signature};
	use crate::util::static_secp_instance;

	use serde_json;

	use rand::{thread_rng, Rng};

	#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
	struct SerTest {
		#[serde(with = "pubkey_serde")]
		pub pub_key: PublicKey,
		#[serde(with = "option_sig_serde")]
		pub opt_sig: Option<Signature>,
		#[serde(with = "sig_serde")]
		pub sig: Signature,
	}

	impl SerTest {
		pub fn random() -> SerTest {
			let static_secp = static_secp_instance();
			let secp = static_secp.lock();
			let sk = SecretKey::new(&secp, &mut thread_rng());
			let mut msg = [0u8; 32];
			thread_rng().fill(&mut msg);
			let msg = Message::from_slice(&msg).unwrap();
			let sig = aggsig::sign_single(&secp, &msg, &sk, None).unwrap();
			SerTest {
				pub_key: PublicKey::from_secret_key(&secp, &sk).unwrap(),
				opt_sig: Some(sig.clone()),
				sig: sig.clone(),
			}
		}
	}

	#[test]
	fn ser_secp_primitives() {
		for _ in 0..10 {
			let s = SerTest::random();
			println!("Before Serialization: {:?}", s);
			let serialized = serde_json::to_string_pretty(&s).unwrap();
			println!("JSON: {}", serialized);
			let deserialized: SerTest = serde_json::from_str(&serialized).unwrap();
			println!("After Serialization: {:?}", deserialized);
			println!();
			assert_eq!(s, deserialized);
		}
	}
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use itertools::Itertools;

use fall_tree::{AstNode, AstClass, Text};
use fall_tree::search::{child_of_type, child_of_type_exn};
use fall_tree::visitor::{Visitor, NodeVisitor};

use super::{Analysis, DiagnosticSink};
use ::{Expr, CallExpr, SynRule, IDENT, SIMPLE_STRING, RefKind};

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum CallKind<'f> {
    Eof,
    Any,
    Commit,

    Not(Expr<'f>),
    Layer(Expr<'f>, Expr<'f>),
    WithSkip(Expr<'f>, Expr<'f>),

    Enter(u32, Expr<'f>),
    Exit(u32, Expr<'f>),
    IsIn(u32),

    RuleCall(SynRule<'f>, Arc<Vec<(u32, Expr<'f>)>>),
    // TODO: u32 is unclear
    PrevIs(Arc<Vec<usize>>)
}

pub (super) fn resolve<'f>(a: &Analysis<'f>, d: &mut DiagnosticSink, call: CallExpr<'f>) -> Option<CallKind<'f>> {
    let n_args = call.args().count();
    let expect_args = |d: &mut DiagnosticSink, n_expected: usize| {
        if n_expected != n_args {
            d.error(
                call.node(),
                format!("Wrong number of arguments, expected {}, got {}", n_expected, n_args)
            )
        }
    };

    let zero_arg = vec![
        ("any", CallKind::Any),
        ("commit", CallKind::Commit),
        ("eof", CallKind::Eof)
    ];
    for (name, kind) in zero_arg.into_iter() {
        if call.fn_name() == name {
            expect_args(d, 0);
            return Some(kind);
        }
    }

    let one_arg: Vec<(_, fn(&Analysis<'f>, &mut DiagnosticSink, Expr<'f>) -> Option<CallKind<'f>>)> = vec![
        ("not", |_, _, arg| Some(CallKind::Not(arg))),
        ("is_in", |a, d, arg| resolve_context(a, d, arg).map(CallKind::IsIn))
    ];
    for (name, kind) in one_arg.into_iter() {
        if call.fn_name() == name {
            expect_args(d, 1);
            return call.args().next().and_then(|arg| kind(a,d, arg))
        }
    }

    let two_arg: Vec<(_, fn(&Analysis<'f>, &mut DiagnosticSink, Expr<'f>, Expr<'f>) -> Option<CallKind<'f>>)> = vec![
        ("layer", |_, _, arg1, arg2 | {
            Some(CallKind::Layer(arg1, arg2))
        }),
        ("with_skip", |_, _, arg1, arg2 | {
            Some(CallKind::WithSkip(arg1, arg2))
        }),
        ("enter", |a, d, arg1, arg2| {
            resolve_context(a, d, arg1).map(|ctx| CallKind::Enter(ctx, arg2))
        }),
        ("exit", |a, d, arg1, arg2| {
            resolve_context(a, d, arg1).map(|ctx| CallKind::Exit(ctx, arg2))
        }),
    ];
    for (name, kind) in two_arg.into_iter() {
        if call.fn_name() == name {
            expect_args(d, 2);
            return call.args().next_tuple()
                .and_then(|(arg1, arg2)| kind(a, d,arg1, arg2));
        }
    }

    if call.fn_name() == "prev_is" {
        let mut args = Vec::new();
        for arg in call.args() {
            let mut ok = false;
            if let Expr::RefExpr(expr) = arg {
                if let Some(RefKind::RuleReference(rule)) = expr.resolve() {
                    if let Some(ty) = rule.resolve_ty() {
                        args.push(ty);
                        ok = true;
                    }
                }
            }
            if !ok {
                d.error(call.node(), "<prev_is> arguments must be public rules")
            }
        }
        return Some(CallKind::PrevIs(Arc::new(args)));
    }

    if let Some(rule) = a.file.resolve_rule(call.fn_name()) {
        if let Some(parameters) = rule.parameters() {
            let params = parameters.parameters()
                .map(|p| p.idx())
                .zip(call.args())
                .collect();
            return Some(CallKind::RuleCall(rule, Arc::new(params)));
        }
    }

    d.error(
        child_of_type_exn(call.node(), IDENT),
        "Unresolved reference"
    );
    return None;
}

pub fn contexts<'f>(a: &Analysis<'f>) -> Vec<Text<'f>> {
    Visitor(Vec::new())
        .visit::<CallExpr, _>(|contexts, call| {
            if call.fn_name() == "is_in" || call.fn_name() == "enter" || call.fn_name() == "exit" {
                if let Some(ctx) = call.args().next().and_then(context_name) {
                    contexts.push(ctx);
                }
            }
        })
        .walk_recursively_children_first(a.file().node())
}

fn context_name<'f>(ctx: Expr<'f>) -> Option<Text<'f>> {
    child_of_type(ctx.node(), SIMPLE_STRING)
        .map(|n| ::ast_ext::lit_body(n.text()))
}

fn resolve_context(a: &Analysis, d: &mut DiagnosticSink, ctx: Expr) -> Option<u32> {
    if let Some(name) = context_name(ctx) {
        a.contexts().iter()
            .position(|&c| c == name)
            .map(|usize_| usize_ as u32)
    } else {
        d.error(ctx.node(), "Context should be a single quoted string");
        None
    }
}

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

    use fall_tree::search;
    use fall_tree::search::ast;

    use ::test_util::parse_with_caret;

    #[test]
    fn test_resolve_no_args() {
        check_resolved("rule foo { <^eof> }", "Eof");
        check_resolved("rule foo { <^any> }", "Any");
        check_resolved("rule foo { <^commit> }", "Commit");
    }

    #[test]
    fn test_resolve_simple_args() {
        check_resolved("rule foo { <^not a> }", "Not(RefExpr@[16; 17))");
        check_resolved("rule foo { <^with_skip a b> }", "WithSkip(RefExpr@[22; 23), RefExpr@[24; 25))");
        check_resolved("rule foo { <^layer a b> }", "Layer(RefExpr@[18; 19), RefExpr@[20; 21))");
    }

    #[test]
    fn test_resolve_layer() {
        check_resolved("rule foo { <^enter 'ctx' a> }", "Enter(0, RefExpr@[24; 25))");
        check_resolved("rule foo { <^exit  'ctx' a> }", "Exit(0, RefExpr@[24; 25))");

        check_resolved("rule foo { <is_in 'ctx1'> <^enter 'ctx2' a> }", "Enter(1, RefExpr@[40; 41))");
        check_resolved("rule foo { <is_in 'ctx1'> <^exit  'ctx2' a> }", "Exit(1, RefExpr@[40; 41))");

        check_resolved(
            "rule foo { <enter 'ctx1' a> <enter 'ctx2' b> <^is_in 'ctx2'> }",
            "IsIn(1)"
        );

        check(
            r" rule foo { <^is_in foo>}",
            None,
            r#"[(foo, "Context should be a single quoted string")]"#,
        )
    }

    #[test]
    fn test_not() {
        resolve_call("rule foo { <^not bar>}", |c, _| {
            let c = c.unwrap();
            assert_eq!(format!("{:?}", c), "Not(RefExpr@[16; 19))");
        })
    }

    #[test]
    fn test_unresolved_call() {
        check(
            r"rule foo { <^abracadabra>}",
            None,
            r#"[(abracadabra, "Unresolved reference")]"#
        );
    }

    #[test]
    fn wrong_arity() {
        check(
            "rule foo { <^eof foo> }",
            Some(CallKind::Eof),
            r#"[(<eof foo>, "Wrong number of arguments, expected 0, got 1")]"#
        );

        check(
            "rule foo { <^any foo bar> }",
            Some(CallKind::Any),
            r#"[(<any foo bar>, "Wrong number of arguments, expected 0, got 2")]"#
        );

        check(
            "rule foo { <^commit foo bar baz> }",
            Some(CallKind::Commit),
            r#"[(<commit foo bar baz>, "Wrong number of arguments, expected 0, got 3")]"#
        );

        check(
            "rule foo { <^not> }",
            None,
            r#"[(<not>, "Wrong number of arguments, expected 1, got 0")]"#
        );
    }

    #[test]
    fn check_prev_is() {
        //TODO: check for errors
        check_resolved(
            "pub rule foo {} pub rule bar {} rule baz { <^prev_is foo bar> }",
            "PrevIs([1, 2])"
        )
    }

    #[test]
    fn call_custom_rule() {
        //TODO: check number of arguments
        //TODO: analysis based resolve of SynRule
        check_resolved(
            "rule foo { <^bar a b>} rule bar(x, y) { }",
            "RuleCall(SynRule@[22; 40), [(0, RefExpr@[16; 17)), (1, RefExpr@[18; 19))])"
        )
    }

    fn check(text: &str, kind: Option<CallKind>, diagnostics: &str) {
        resolve_call(text, |c, a| {
            assert_eq!(c, kind);
            assert_eq!(a.debug_diagnostics(), diagnostics);
        })
    }

    fn check_resolved(text: &str, kind: &str) {
        resolve_call(text, |c, a| {
            let c = c.unwrap();
            assert_eq!(format!("{:?}", c), kind);
            assert_eq!(a.debug_diagnostics(), "[]");
        })
    }

    fn resolve_call<F: FnOnce(Option<CallKind>, Analysis)>(text: &str, f: F) {
        let (file, caret) = parse_with_caret(&text);
        let call = {
            let leaf = search::find_leaf_at_offset(file.root(), caret)
                .left_biased().unwrap();
            ast::ancestor_exn(leaf)
        };
        let a = Analysis::new(::ast(&file));
        let c = a.resolve_call(call);
        f(c, a)
    }
}

<commit_msg>Remove copy-paste<commit_after>use std::sync::Arc;
use itertools::Itertools;

use fall_tree::{AstNode, AstClass, Text};
use fall_tree::search::{child_of_type, child_of_type_exn};
use fall_tree::visitor::{Visitor, NodeVisitor};

use super::{Analysis, DiagnosticSink};
use ::{Expr, CallExpr, SynRule, IDENT, SIMPLE_STRING, RefKind};

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum CallKind<'f> {
    Eof,
    Any,
    Commit,

    Not(Expr<'f>),
    Layer(Expr<'f>, Expr<'f>),
    WithSkip(Expr<'f>, Expr<'f>),

    Enter(u32, Expr<'f>),
    Exit(u32, Expr<'f>),
    IsIn(u32),

    RuleCall(SynRule<'f>, Arc<Vec<(u32, Expr<'f>)>>),
    // TODO: u32 is unclear
    PrevIs(Arc<Vec<usize>>)
}

pub (super) fn resolve<'f>(a: &Analysis<'f>, d: &mut DiagnosticSink, call: CallExpr<'f>) -> Option<CallKind<'f>> {
    let n_args = call.args().count();
    let expect_args = |d: &mut DiagnosticSink, n_expected: usize| {
        if n_expected != n_args {
            d.error(
                call.node(),
                format!("Wrong number of arguments, expected {}, got {}", n_expected, n_args)
            )
        }
    };

    let zero = |d: &mut DiagnosticSink, kind: CallKind<'f>| {
        expect_args(d, 0);
        Some(kind)
    };
    let mut any = |d: &mut DiagnosticSink| zero(d, CallKind::Any);
    let mut commit = |d: &mut DiagnosticSink| zero(d, CallKind::Commit);
    let mut eof = |d: &mut DiagnosticSink| zero(d, CallKind::Eof);

    let one = |d: &mut DiagnosticSink, kind: &mut FnMut(&mut DiagnosticSink, Expr<'f>) -> Option<CallKind<'f>>| {
        expect_args(d, 1);
        call.args().next().and_then(|arg| kind(d, arg))
    };
    let mut not = |d: &mut DiagnosticSink| one(d, &mut |_, arg| Some(CallKind::Not(arg)));
    let mut is_in = |d: &mut DiagnosticSink| one(d, &mut |d, arg| resolve_context(a, d, arg).map(CallKind::IsIn));

    let two = |d: &mut DiagnosticSink, kind: &mut FnMut(&mut DiagnosticSink, Expr<'f>, Expr<'f>) -> Option<CallKind<'f>>| {
        expect_args(d, 2);
        call.args().next_tuple().and_then(|(arg1, arg2)| kind(d, arg1, arg2))
    };
    let mut layer = |d: &mut DiagnosticSink| two(d, &mut |_, arg1, arg2| {
        Some(CallKind::Layer(arg1, arg2))
    });
    let mut with_skip = |d: &mut DiagnosticSink| two(d, &mut |_, arg1, arg2| {
        Some(CallKind::WithSkip(arg1, arg2))
    });
    let mut enter = |d: &mut DiagnosticSink| two(d, &mut |d, arg1, arg2| {
        resolve_context(a, d, arg1).map(|ctx| CallKind::Enter(ctx, arg2))
    });
    let mut exit = |d: &mut DiagnosticSink| two(d, &mut |d, arg1, arg2| {
        resolve_context(a, d, arg1).map(|ctx| CallKind::Exit(ctx, arg2))
    });

    let mut prev_is = |d: &mut DiagnosticSink| {
        let mut args = Vec::new();
        for arg in call.args() {
            let mut ok = false;
            if let Expr::RefExpr(expr) = arg {
                if let Some(RefKind::RuleReference(rule)) = expr.resolve() {
                    if let Some(ty) = rule.resolve_ty() {
                        args.push(ty);
                        ok = true;
                    }
                }
            }
            if !ok {
                d.error(call.node(), "<prev_is> arguments must be public rules")
            }
        }
        Some(CallKind::PrevIs(Arc::new(args)))
    };

    let build_in: Vec<(&str, &mut FnMut(&mut DiagnosticSink) -> Option<CallKind<'f>>)> = vec![
        ("any", &mut any),
        ("commit", &mut commit),
        ("eof", &mut eof),
        ("not", &mut not),
        ("is_in", &mut is_in),
        ("layer", &mut layer),
        ("with_skip", &mut with_skip),
        ("enter", &mut enter),
        ("exit", &mut exit),
        ("prev_is", &mut prev_is)
    ];

    for (name, kind) in build_in.into_iter() {
        if call.fn_name() == name {
            return kind(d);
        }
    }

    if let Some(rule) = a.file.resolve_rule(call.fn_name()) {
        if let Some(parameters) = rule.parameters() {
            let params = parameters.parameters()
                .map(|p| p.idx())
                .zip(call.args())
                .collect();
            return Some(CallKind::RuleCall(rule, Arc::new(params)));
        }
    }

    d.error(
        child_of_type_exn(call.node(), IDENT),
        "Unresolved reference"
    );
    return None;
}

pub fn contexts<'f>(a: &Analysis<'f>) -> Vec<Text<'f>> {
    Visitor(Vec::new())
        .visit::<CallExpr, _>(|contexts, call| {
            if call.fn_name() == "is_in" || call.fn_name() == "enter" || call.fn_name() == "exit" {
                if let Some(ctx) = call.args().next().and_then(context_name) {
                    contexts.push(ctx);
                }
            }
        })
        .walk_recursively_children_first(a.file().node())
}

fn context_name<'f>(ctx: Expr<'f>) -> Option<Text<'f>> {
    child_of_type(ctx.node(), SIMPLE_STRING)
        .map(|n| ::ast_ext::lit_body(n.text()))
}

fn resolve_context(a: &Analysis, d: &mut DiagnosticSink, ctx: Expr) -> Option<u32> {
    if let Some(name) = context_name(ctx) {
        a.contexts().iter()
            .position(|&c| c == name)
            .map(|usize_| usize_ as u32)
    } else {
        d.error(ctx.node(), "Context should be a single quoted string");
        None
    }
}

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

    use fall_tree::search;
    use fall_tree::search::ast;

    use ::test_util::parse_with_caret;

    #[test]
    fn test_resolve_no_args() {
        check_resolved("rule foo { <^eof> }", "Eof");
        check_resolved("rule foo { <^any> }", "Any");
        check_resolved("rule foo { <^commit> }", "Commit");
    }

    #[test]
    fn test_resolve_simple_args() {
        check_resolved("rule foo { <^not a> }", "Not(RefExpr@[16; 17))");
        check_resolved("rule foo { <^with_skip a b> }", "WithSkip(RefExpr@[22; 23), RefExpr@[24; 25))");
        check_resolved("rule foo { <^layer a b> }", "Layer(RefExpr@[18; 19), RefExpr@[20; 21))");
    }

    #[test]
    fn test_resolve_layer() {
        check_resolved("rule foo { <^enter 'ctx' a> }", "Enter(0, RefExpr@[24; 25))");
        check_resolved("rule foo { <^exit  'ctx' a> }", "Exit(0, RefExpr@[24; 25))");

        check_resolved("rule foo { <is_in 'ctx1'> <^enter 'ctx2' a> }", "Enter(1, RefExpr@[40; 41))");
        check_resolved("rule foo { <is_in 'ctx1'> <^exit  'ctx2' a> }", "Exit(1, RefExpr@[40; 41))");

        check_resolved(
            "rule foo { <enter 'ctx1' a> <enter 'ctx2' b> <^is_in 'ctx2'> }",
            "IsIn(1)"
        );

        check(
            r" rule foo { <^is_in foo>}",
            None,
            r#"[(foo, "Context should be a single quoted string")]"#,
        )
    }

    #[test]
    fn test_not() {
        resolve_call("rule foo { <^not bar>}", |c, _| {
            let c = c.unwrap();
            assert_eq!(format!("{:?}", c), "Not(RefExpr@[16; 19))");
        })
    }

    #[test]
    fn test_unresolved_call() {
        check(
            r"rule foo { <^abracadabra>}",
            None,
            r#"[(abracadabra, "Unresolved reference")]"#
        );
    }

    #[test]
    fn wrong_arity() {
        check(
            "rule foo { <^eof foo> }",
            Some(CallKind::Eof),
            r#"[(<eof foo>, "Wrong number of arguments, expected 0, got 1")]"#
        );

        check(
            "rule foo { <^any foo bar> }",
            Some(CallKind::Any),
            r#"[(<any foo bar>, "Wrong number of arguments, expected 0, got 2")]"#
        );

        check(
            "rule foo { <^commit foo bar baz> }",
            Some(CallKind::Commit),
            r#"[(<commit foo bar baz>, "Wrong number of arguments, expected 0, got 3")]"#
        );

        check(
            "rule foo { <^not> }",
            None,
            r#"[(<not>, "Wrong number of arguments, expected 1, got 0")]"#
        );
    }

    #[test]
    fn check_prev_is() {
        //TODO: check for errors
        check_resolved(
            "pub rule foo {} pub rule bar {} rule baz { <^prev_is foo bar> }",
            "PrevIs([1, 2])"
        )
    }

    #[test]
    fn call_custom_rule() {
        //TODO: check number of arguments
        //TODO: analysis based resolve of SynRule
        check_resolved(
            "rule foo { <^bar a b>} rule bar(x, y) { }",
            "RuleCall(SynRule@[22; 40), [(0, RefExpr@[16; 17)), (1, RefExpr@[18; 19))])"
        )
    }

    fn check(text: &str, kind: Option<CallKind>, diagnostics: &str) {
        resolve_call(text, |c, a| {
            assert_eq!(c, kind);
            assert_eq!(a.debug_diagnostics(), diagnostics);
        })
    }

    fn check_resolved(text: &str, kind: &str) {
        resolve_call(text, |c, a| {
            let c = c.unwrap();
            assert_eq!(format!("{:?}", c), kind);
            assert_eq!(a.debug_diagnostics(), "[]");
        })
    }

    fn resolve_call<F: FnOnce(Option<CallKind>, Analysis)>(text: &str, f: F) {
        let (file, caret) = parse_with_caret(&text);
        let call = {
            let leaf = search::find_leaf_at_offset(file.root(), caret)
                .left_biased().unwrap();
            ast::ancestor_exn(leaf)
        };
        let a = Analysis::new(::ast(&file));
        let c = a.resolve_call(call);
        f(c, a)
    }
}

<|endoftext|>


<commit_before>//! Transcriber takes a template, like `fn $ident() {}`, a set of bindings like
//! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}`

use syntax::SmolStr;
use tt::Delimiter;

use super::ExpandResult;
use crate::{
    expander::{Binding, Bindings, Fragment},
    parser::{Op, RepeatKind, Separator},
    ExpandError, MetaTemplate,
};

impl Bindings {
    fn contains(&self, name: &str) -> bool {
        self.inner.contains_key(name)
    }

    fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<&Fragment, ExpandError> {
        let mut b: &Binding = self.inner.get(name).ok_or_else(|| {
            ExpandError::BindingError(format!("could not find binding `{}`", name))
        })?;
        for nesting_state in nesting.iter_mut() {
            nesting_state.hit = true;
            b = match b {
                Binding::Fragment(_) => break,
                Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| {
                    nesting_state.at_end = true;
                    ExpandError::BindingError(format!("could not find nested binding `{}`", name))
                })?,
                Binding::Empty => {
                    nesting_state.at_end = true;
                    return Err(ExpandError::BindingError(format!(
                        "could not find empty binding `{}`",
                        name
                    )));
                }
            };
        }
        match b {
            Binding::Fragment(it) => Ok(it),
            Binding::Nested(_) => Err(ExpandError::BindingError(format!(
                "expected simple binding, found nested binding `{}`",
                name
            ))),
            Binding::Empty => Err(ExpandError::BindingError(format!(
                "expected simple binding, found empty binding `{}`",
                name
            ))),
        }
    }
}

pub(super) fn transcribe(
    template: &MetaTemplate,
    bindings: &Bindings,
) -> ExpandResult<tt::Subtree> {
    let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() };
    let mut arena: Vec<tt::TokenTree> = Vec::new();
    expand_subtree(&mut ctx, template, None, &mut arena)
}

#[derive(Debug)]
struct NestingState {
    idx: usize,
    /// `hit` is currently necessary to tell `expand_repeat` if it should stop
    /// because there is no variable in use by the current repetition
    hit: bool,
    /// `at_end` is currently necessary to tell `expand_repeat` if it should stop
    /// because there is no more value available for the current repetition
    at_end: bool,
}

#[derive(Debug)]
struct ExpandCtx<'a> {
    bindings: &'a Bindings,
    nesting: Vec<NestingState>,
}

fn expand_subtree(
    ctx: &mut ExpandCtx,
    template: &MetaTemplate,
    delimiter: Option<Delimiter>,
    arena: &mut Vec<tt::TokenTree>,
) -> ExpandResult<tt::Subtree> {
    // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation
    let start_elements = arena.len();
    let mut err = None;
    for op in template.iter() {
        match op {
            Op::Leaf(tt) => arena.push(tt.clone().into()),
            Op::Subtree { tokens, delimiter } => {
                let ExpandResult { value: tt, err: e } =
                    expand_subtree(ctx, &tokens, *delimiter, arena);
                err = err.or(e);
                arena.push(tt.into());
            }
            Op::Var { name, id, .. } => {
                let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name, *id);
                err = err.or(e);
                push_fragment(arena, fragment);
            }
            Op::Repeat { tokens: subtree, kind, separator } => {
                let ExpandResult { value: fragment, err: e } =
                    expand_repeat(ctx, subtree, *kind, separator, arena);
                err = err.or(e);
                push_fragment(arena, fragment)
            }
        }
    }
    // drain the elements added in this instance of expand_subtree
    let tts = arena.drain(start_elements..arena.len()).collect();
    ExpandResult { value: tt::Subtree { delimiter, token_trees: tts }, err }
}

fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> {
    // We already handle $crate case in mbe parser
    debug_assert!(v != "crate");

    if !ctx.bindings.contains(v) {
        // Note that it is possible to have a `$var` inside a macro which is not bound.
        // For example:
        // ```
        // macro_rules! foo {
        //     ($a:ident, $b:ident, $c:tt) => {
        //         macro_rules! bar {
        //             ($bi:ident) => {
        //                 fn $bi() -> u8 {$c}
        //             }
        //         }
        //     }
        // ```
        // We just treat it a normal tokens
        let tt = tt::Subtree {
            delimiter: None,
            token_trees: vec![
                tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(),
                tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(),
            ],
        }
        .into();
        ExpandResult::ok(Fragment::Tokens(tt))
    } else {
        ctx.bindings.get(&v, &mut ctx.nesting).map_or_else(
            |e| ExpandResult { value: Fragment::Tokens(tt::TokenTree::empty()), err: Some(e) },
            |b| ExpandResult::ok(b.clone()),
        )
    }
}

fn expand_repeat(
    ctx: &mut ExpandCtx,
    template: &MetaTemplate,
    kind: RepeatKind,
    separator: &Option<Separator>,
    arena: &mut Vec<tt::TokenTree>,
) -> ExpandResult<Fragment> {
    let mut buf: Vec<tt::TokenTree> = Vec::new();
    ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false });
    // Dirty hack to make macro-expansion terminate.
    // This should be replaced by a proper macro-by-example implementation
    let limit = 65536;
    let mut has_seps = 0;
    let mut counter = 0;

    loop {
        let ExpandResult { value: mut t, err: e } = expand_subtree(ctx, template, None, arena);
        let nesting_state = ctx.nesting.last_mut().unwrap();
        if nesting_state.at_end || !nesting_state.hit {
            break;
        }
        nesting_state.idx += 1;
        nesting_state.hit = false;

        counter += 1;
        if counter == limit {
            log::warn!("expand_tt in repeat pattern exceed limit => {:#?}\n{:#?}", template, ctx);
            break;
        }

        if e.is_some() {
            continue;
        }

        t.delimiter = None;
        push_subtree(&mut buf, t);

        if let Some(ref sep) = separator {
            match sep {
                Separator::Ident(ident) => {
                    has_seps = 1;
                    buf.push(tt::Leaf::from(ident.clone()).into());
                }
                Separator::Literal(lit) => {
                    has_seps = 1;
                    buf.push(tt::Leaf::from(lit.clone()).into());
                }

                Separator::Puncts(puncts) => {
                    has_seps = puncts.len();
                    for punct in puncts {
                        buf.push(tt::Leaf::from(*punct).into());
                    }
                }
            }
        }

        if RepeatKind::ZeroOrOne == kind {
            break;
        }
    }

    ctx.nesting.pop().unwrap();
    for _ in 0..has_seps {
        buf.pop();
    }

    // Check if it is a single token subtree without any delimiter
    // e.g {Delimiter:None> ['>'] /Delimiter:None>}
    let tt = tt::Subtree { delimiter: None, token_trees: buf }.into();

    if RepeatKind::OneOrMore == kind && counter == 0 {
        return ExpandResult {
            value: Fragment::Tokens(tt),
            err: Some(ExpandError::UnexpectedToken),
        };
    }
    ExpandResult::ok(Fragment::Tokens(tt))
}

fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
    match fragment {
        Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt),
        Fragment::Tokens(tt) | Fragment::Ast(tt) => buf.push(tt),
    }
}

fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
    match tt.delimiter {
        None => buf.extend(tt.token_trees),
        _ => buf.push(tt.into()),
    }
}
<commit_msg>Make sure ill-form macro handle propely<commit_after>//! Transcriber takes a template, like `fn $ident() {}`, a set of bindings like
//! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}`

use syntax::SmolStr;
use tt::{Delimiter, Subtree};

use super::ExpandResult;
use crate::{
    expander::{Binding, Bindings, Fragment},
    parser::{Op, RepeatKind, Separator},
    ExpandError, MetaTemplate,
};

impl Bindings {
    fn contains(&self, name: &str) -> bool {
        self.inner.contains_key(name)
    }

    fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<&Fragment, ExpandError> {
        let mut b: &Binding = self.inner.get(name).ok_or_else(|| {
            ExpandError::BindingError(format!("could not find binding `{}`", name))
        })?;
        for nesting_state in nesting.iter_mut() {
            nesting_state.hit = true;
            b = match b {
                Binding::Fragment(_) => break,
                Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| {
                    nesting_state.at_end = true;
                    ExpandError::BindingError(format!("could not find nested binding `{}`", name))
                })?,
                Binding::Empty => {
                    nesting_state.at_end = true;
                    return Err(ExpandError::BindingError(format!(
                        "could not find empty binding `{}`",
                        name
                    )));
                }
            };
        }
        match b {
            Binding::Fragment(it) => Ok(it),
            Binding::Nested(_) => Err(ExpandError::BindingError(format!(
                "expected simple binding, found nested binding `{}`",
                name
            ))),
            Binding::Empty => Err(ExpandError::BindingError(format!(
                "expected simple binding, found empty binding `{}`",
                name
            ))),
        }
    }
}

pub(super) fn transcribe(
    template: &MetaTemplate,
    bindings: &Bindings,
) -> ExpandResult<tt::Subtree> {
    let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() };
    let mut arena: Vec<tt::TokenTree> = Vec::new();
    expand_subtree(&mut ctx, template, None, &mut arena)
}

#[derive(Debug)]
struct NestingState {
    idx: usize,
    /// `hit` is currently necessary to tell `expand_repeat` if it should stop
    /// because there is no variable in use by the current repetition
    hit: bool,
    /// `at_end` is currently necessary to tell `expand_repeat` if it should stop
    /// because there is no more value available for the current repetition
    at_end: bool,
}

#[derive(Debug)]
struct ExpandCtx<'a> {
    bindings: &'a Bindings,
    nesting: Vec<NestingState>,
}

fn expand_subtree(
    ctx: &mut ExpandCtx,
    template: &MetaTemplate,
    delimiter: Option<Delimiter>,
    arena: &mut Vec<tt::TokenTree>,
) -> ExpandResult<tt::Subtree> {
    // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation
    let start_elements = arena.len();
    let mut err = None;
    for op in template.iter() {
        match op {
            Op::Leaf(tt) => arena.push(tt.clone().into()),
            Op::Subtree { tokens, delimiter } => {
                let ExpandResult { value: tt, err: e } =
                    expand_subtree(ctx, &tokens, *delimiter, arena);
                err = err.or(e);
                arena.push(tt.into());
            }
            Op::Var { name, id, .. } => {
                let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name, *id);
                err = err.or(e);
                push_fragment(arena, fragment);
            }
            Op::Repeat { tokens: subtree, kind, separator } => {
                let ExpandResult { value: fragment, err: e } =
                    expand_repeat(ctx, subtree, *kind, separator, arena);
                err = err.or(e);
                push_fragment(arena, fragment)
            }
        }
    }
    // drain the elements added in this instance of expand_subtree
    let tts = arena.drain(start_elements..arena.len()).collect();
    ExpandResult { value: tt::Subtree { delimiter, token_trees: tts }, err }
}

fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> {
    // We already handle $crate case in mbe parser
    debug_assert!(v != "crate");

    if !ctx.bindings.contains(v) {
        // Note that it is possible to have a `$var` inside a macro which is not bound.
        // For example:
        // ```
        // macro_rules! foo {
        //     ($a:ident, $b:ident, $c:tt) => {
        //         macro_rules! bar {
        //             ($bi:ident) => {
        //                 fn $bi() -> u8 {$c}
        //             }
        //         }
        //     }
        // ```
        // We just treat it a normal tokens
        let tt = tt::Subtree {
            delimiter: None,
            token_trees: vec![
                tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(),
                tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(),
            ],
        }
        .into();
        ExpandResult::ok(Fragment::Tokens(tt))
    } else {
        ctx.bindings.get(&v, &mut ctx.nesting).map_or_else(
            |e| ExpandResult { value: Fragment::Tokens(tt::TokenTree::empty()), err: Some(e) },
            |b| ExpandResult::ok(b.clone()),
        )
    }
}

fn expand_repeat(
    ctx: &mut ExpandCtx,
    template: &MetaTemplate,
    kind: RepeatKind,
    separator: &Option<Separator>,
    arena: &mut Vec<tt::TokenTree>,
) -> ExpandResult<Fragment> {
    let mut buf: Vec<tt::TokenTree> = Vec::new();
    ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false });
    // Dirty hack to make macro-expansion terminate.
    // This should be replaced by a proper macro-by-example implementation
    let limit = 65536;
    let mut has_seps = 0;
    let mut counter = 0;

    loop {
        let ExpandResult { value: mut t, err: e } = expand_subtree(ctx, template, None, arena);
        let nesting_state = ctx.nesting.last_mut().unwrap();
        if nesting_state.at_end || !nesting_state.hit {
            break;
        }
        nesting_state.idx += 1;
        nesting_state.hit = false;

        counter += 1;
        if counter == limit {
            log::warn!("expand_tt in repeat pattern exceed limit => {:#?}\n{:#?}", template, ctx);
            return ExpandResult {
                value: Fragment::Tokens(Subtree::default().into()),
                err: Some(ExpandError::Other("Expand exceed limit".to_string())),
            };
        }

        if e.is_some() {
            continue;
        }

        t.delimiter = None;
        push_subtree(&mut buf, t);

        if let Some(ref sep) = separator {
            match sep {
                Separator::Ident(ident) => {
                    has_seps = 1;
                    buf.push(tt::Leaf::from(ident.clone()).into());
                }
                Separator::Literal(lit) => {
                    has_seps = 1;
                    buf.push(tt::Leaf::from(lit.clone()).into());
                }

                Separator::Puncts(puncts) => {
                    has_seps = puncts.len();
                    for punct in puncts {
                        buf.push(tt::Leaf::from(*punct).into());
                    }
                }
            }
        }

        if RepeatKind::ZeroOrOne == kind {
            break;
        }
    }

    ctx.nesting.pop().unwrap();
    for _ in 0..has_seps {
        buf.pop();
    }

    // Check if it is a single token subtree without any delimiter
    // e.g {Delimiter:None> ['>'] /Delimiter:None>}
    let tt = tt::Subtree { delimiter: None, token_trees: buf }.into();

    if RepeatKind::OneOrMore == kind && counter == 0 {
        return ExpandResult {
            value: Fragment::Tokens(tt),
            err: Some(ExpandError::UnexpectedToken),
        };
    }
    ExpandResult::ok(Fragment::Tokens(tt))
}

fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
    match fragment {
        Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt),
        Fragment::Tokens(tt) | Fragment::Ast(tt) => buf.push(tt),
    }
}

fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
    match tt.delimiter {
        None => buf.extend(tt.token_trees),
        _ => buf.push(tt.into()),
    }
}
<|endoftext|>


<commit_before>use ffi::prelude::LLVMTypeRef;
use ffi::{core, target, LLVMTypeKind};
use libc::{c_int, c_uint};
use compile::Compile;
use context::{Context, GetContext};
use target::TargetData;
use util::{self, CastFrom};
use std::{fmt, mem};
use std::iter::Iterator;
use std::ops::Deref;

/// Defines how a value should be laid out in memory.
pub struct Type;
native_ref!(&Type = LLVMTypeRef);
impl Type {
    #[inline(always)]
    /// Get the type given as an LLVM type descriptor in the context given.
    pub fn get<'a, T>(context:&'a Context) -> &'a Type where T:Compile<'a> {
        T::get_type(context)
    }
    /// Make a new function signature with the return type and arguments given.
    pub fn new_function<'a>(ret: &'a Type, args: &[&'a Type]) -> &'a FunctionType {
        unsafe { core::LLVMFunctionType(ret.into(), args.as_ptr() as *mut LLVMTypeRef, args.len() as c_uint, 0) }.into()
    }
    /// Make a new array with the length given.
    pub fn new_array<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMArrayType(element.into(), length as c_uint) }.into()
    }
    /// Make a new vector with the length given.
    pub fn new_vector<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMVectorType(element.into(), length as c_uint) }.into()
    }
    /// Make a new pointer with the given element type.
    pub fn new_pointer<'a>(elem: &'a Type) -> &'a Type {
        unsafe { core::LLVMPointerType(elem.into(), 0 as c_uint) }.into()
    }
    /// Make a new structure type with the given types.
    pub fn new_struct<'a>(elems: &[&'a Type], packed: bool) -> &'a Type {
        unsafe { core::LLVMStructType(elems.as_ptr() as *mut LLVMTypeRef, elems.len() as c_uint, packed as c_int) }.into()
    }
    /// Returns true if the size of the type is known at compile-time.
    ///
    /// This is equivalent to the type implementing `Sized` in Rust
    pub fn is_sized(&self) -> bool {
        unsafe { core::LLVMTypeIsSized(self.into()) != 0 }
    }
    /// Returns true if this type is a function.
    pub fn is_function(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
    }
    /// Returns true if this type is a struct.
    pub fn is_struct(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint
    }
    /// Returns true if this type is void.
    pub fn is_void(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMVoidTypeKind as c_uint
    }
    /// Returns true if this type is a pointer.
    pub fn is_pointer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMPointerTypeKind as c_uint
    }
    /// Returns true if this type is an integer.
    pub fn is_integer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMIntegerTypeKind as c_uint
    }
    /// Returns true if this type is any floating-point number.
    pub fn is_float(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) } as c_uint;
        kind == LLVMTypeKind::LLVMHalfTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMFloatTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMDoubleTypeKind as c_uint
    }
    /// Returns the size of the type in bytes.
    pub fn get_size(&self, target: &TargetData) -> usize {
        unsafe { target::LLVMABISizeOfType(target.into(), self.into()) as usize }
    }
    /// Returns the element of this pointer type.
    pub fn get_element(&self) -> Option<&Type> {
        unsafe { mem::transmute(core::LLVMGetElementType(self.into())) }
    }
}
get_context!(Type, LLVMGetTypeContext);
to_str!(Type, LLVMPrintTypeToString);

/// A structure type, such as a tuple or struct.
pub struct StructType;
native_ref!(&StructType = LLVMTypeRef);
impl StructType {
    /// Make a new struct with the given fields and packed representation.
    pub fn new<'a>(context: &'a Context, fields: &[&'a Type], packed: bool) -> &'a StructType {
        unsafe { core::LLVMStructTypeInContext(context.into(), fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int) }.into()
    }
    /// Make a new named struct with the given fields and packed representation.
    pub fn new_named<'a>(context: &'a Context, name: &str, fields: &[&'a Type], packed: bool) -> &'a StructType {
        util::with_cstr(name, |name| unsafe {
            let ty = core::LLVMStructCreateNamed(context.into(), name);
            core::LLVMStructSetBody(ty, fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int);
            ty.into()
        })
    }
    /// Returns the elements that make up this struct.
    pub fn get_elements(&self) -> Vec<Type> {
        unsafe {
            let size = core::LLVMCountStructElementTypes(self.into());
            let mut els:Vec<_> = (0..size).map(|_| mem::uninitialized()).collect();
            core::LLVMGetStructElementTypes(self.into(), els.as_mut_ptr() as *mut LLVMTypeRef);
            els
        }
    }
}
impl CastFrom for StructType {
    type From = Type;
    fn cast(ty: &Type) -> Option<&StructType> {
        unsafe {
            let kind = core::LLVMGetTypeKind(ty.into());
            if kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint {
                mem::transmute(ty)
            } else {
                None
            }
        }
    }
}
deref!(StructType, Type);
get_context!(StructType, LLVMGetTypeContext);
to_str!(StructType, LLVMPrintTypeToString);

/// A function signature type.
pub struct FunctionType;
native_ref!(&FunctionType = LLVMTypeRef);
deref!(FunctionType, Type);
impl CastFrom for FunctionType {
    type From = Type;
    fn cast(mut ty: &Type) -> Option<&FunctionType> {
        unsafe {
            use libc::c_uint;
            while let Some(elem) = ty.get_element() {
                ty = elem;
            }
            let kind = core::LLVMGetTypeKind(ty.into());
            if kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint {
                mem::transmute(ty)
            } else {
                None
            }
        }
    }
}
impl FunctionType {
    /// Returns the number of parameters this signature takes.
    pub fn num_params(&self) -> usize {
        unsafe { core::LLVMCountParamTypes(self.into()) as usize }
    }
    /// Returns a vector of this signature's parameters' types.
    pub fn get_params(&self) -> Vec<&Type> {
        unsafe {
            let count = core::LLVMCountParamTypes(self.into());
            let mut types:Vec<_> = (0..count).map(|_| mem::uninitialized()).collect();
            core::LLVMGetParamTypes(self.into(), types.as_mut_ptr() as *mut LLVMTypeRef);
            types
        }
    }
    /// Returns the type that this function returns.
    pub fn get_return(&self) -> &Type {
        unsafe { core::LLVMGetReturnType(self.into()).into() }
    }
}
get_context!(FunctionType, LLVMGetTypeContext);
to_str!(FunctionType, LLVMPrintTypeToString);
<commit_msg>fixed function that was causing segfaults<commit_after>use ffi::prelude::LLVMTypeRef;
use ffi::{core, target, LLVMTypeKind};
use libc::{c_int, c_uint};
use compile::Compile;
use context::{Context, GetContext};
use target::TargetData;
use util::{self, CastFrom};
use std::{fmt, mem};
use std::iter::Iterator;
use std::ops::Deref;

/// Defines how a value should be laid out in memory.
pub struct Type;
native_ref!(&Type = LLVMTypeRef);
impl Type {
    #[inline(always)]
    /// Get the type given as an LLVM type descriptor in the context given.
    pub fn get<'a, T>(context:&'a Context) -> &'a Type where T:Compile<'a> {
        T::get_type(context)
    }
    /// Make a new function signature with the return type and arguments given.
    pub fn new_function<'a>(ret: &'a Type, args: &[&'a Type]) -> &'a FunctionType {
        unsafe { core::LLVMFunctionType(ret.into(), args.as_ptr() as *mut LLVMTypeRef, args.len() as c_uint, 0) }.into()
    }
    /// Make a new array with the length given.
    pub fn new_array<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMArrayType(element.into(), length as c_uint) }.into()
    }
    /// Make a new vector with the length given.
    pub fn new_vector<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMVectorType(element.into(), length as c_uint) }.into()
    }
    /// Make a new pointer with the given element type.
    pub fn new_pointer<'a>(elem: &'a Type) -> &'a Type {
        unsafe { core::LLVMPointerType(elem.into(), 0 as c_uint) }.into()
    }
    /// Make a new structure type with the given types.
    pub fn new_struct<'a>(context:&'a Context, elems: &[&'a Type], packed: bool) -> &'a Type {
        unsafe { core::LLVMStructTypeInContext(context.into(), elems.as_ptr() as *mut LLVMTypeRef, elems.len() as c_uint, packed as c_int) }.into()
    }
    /// Returns true if the size of the type is known at compile-time.
    ///
    /// This is equivalent to the type implementing `Sized` in Rust
    pub fn is_sized(&self) -> bool {
        unsafe { core::LLVMTypeIsSized(self.into()) != 0 }
    }
    /// Returns true if this type is a function.
    pub fn is_function(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
    }
    /// Returns true if this type is a struct.
    pub fn is_struct(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint
    }
    /// Returns true if this type is void.
    pub fn is_void(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMVoidTypeKind as c_uint
    }
    /// Returns true if this type is a pointer.
    pub fn is_pointer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMPointerTypeKind as c_uint
    }
    /// Returns true if this type is an integer.
    pub fn is_integer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMIntegerTypeKind as c_uint
    }
    /// Returns true if this type is any floating-point number.
    pub fn is_float(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) } as c_uint;
        kind == LLVMTypeKind::LLVMHalfTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMFloatTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMDoubleTypeKind as c_uint
    }
    /// Returns the size of the type in bytes.
    pub fn get_size(&self, target: &TargetData) -> usize {
        unsafe { target::LLVMABISizeOfType(target.into(), self.into()) as usize }
    }
    /// Returns the element of this pointer type.
    pub fn get_element(&self) -> Option<&Type> {
        unsafe { mem::transmute(core::LLVMGetElementType(self.into())) }
    }
}
get_context!(Type, LLVMGetTypeContext);
to_str!(Type, LLVMPrintTypeToString);

/// A structure type, such as a tuple or struct.
pub struct StructType;
native_ref!(&StructType = LLVMTypeRef);
impl StructType {
    /// Make a new struct with the given fields and packed representation.
    pub fn new<'a>(context: &'a Context, fields: &[&'a Type], packed: bool) -> &'a StructType {
        unsafe { core::LLVMStructTypeInContext(context.into(), fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int) }.into()
    }
    /// Make a new named struct with the given fields and packed representation.
    pub fn new_named<'a>(context: &'a Context, name: &str, fields: &[&'a Type], packed: bool) -> &'a StructType {
        util::with_cstr(name, |name| unsafe {
            let ty = core::LLVMStructCreateNamed(context.into(), name);
            core::LLVMStructSetBody(ty, fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int);
            ty.into()
        })
    }
    /// Returns the elements that make up this struct.
    pub fn get_elements(&self) -> Vec<Type> {
        unsafe {
            let size = core::LLVMCountStructElementTypes(self.into());
            let mut els:Vec<_> = (0..size).map(|_| mem::uninitialized()).collect();
            core::LLVMGetStructElementTypes(self.into(), els.as_mut_ptr() as *mut LLVMTypeRef);
            els
        }
    }
}
impl CastFrom for StructType {
    type From = Type;
    fn cast(ty: &Type) -> Option<&StructType> {
        unsafe {
            let kind = core::LLVMGetTypeKind(ty.into());
            if kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint {
                mem::transmute(ty)
            } else {
                None
            }
        }
    }
}
deref!(StructType, Type);
get_context!(StructType, LLVMGetTypeContext);
to_str!(StructType, LLVMPrintTypeToString);

/// A function signature type.
pub struct FunctionType;
native_ref!(&FunctionType = LLVMTypeRef);
deref!(FunctionType, Type);
impl CastFrom for FunctionType {
    type From = Type;
    fn cast(mut ty: &Type) -> Option<&FunctionType> {
        unsafe {
            use libc::c_uint;
            while let Some(elem) = ty.get_element() {
                ty = elem;
            }
            let kind = core::LLVMGetTypeKind(ty.into());
            if kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint {
                mem::transmute(ty)
            } else {
                None
            }
        }
    }
}
impl FunctionType {
    /// Returns the number of parameters this signature takes.
    pub fn num_params(&self) -> usize {
        unsafe { core::LLVMCountParamTypes(self.into()) as usize }
    }
    /// Returns a vector of this signature's parameters' types.
    pub fn get_params(&self) -> Vec<&Type> {
        unsafe {
            let count = core::LLVMCountParamTypes(self.into());
            let mut types:Vec<_> = (0..count).map(|_| mem::uninitialized()).collect();
            core::LLVMGetParamTypes(self.into(), types.as_mut_ptr() as *mut LLVMTypeRef);
            types
        }
    }
    /// Returns the type that this function returns.
    pub fn get_return(&self) -> &Type {
        unsafe { core::LLVMGetReturnType(self.into()).into() }
    }
}
get_context!(FunctionType, LLVMGetTypeContext);
to_str!(FunctionType, LLVMPrintTypeToString);
<|endoftext|>