<commit_before>
#![feature(globs)]
#![feature(macro_rules)]
#![allow(dead_code)]
#![allow(unreachable_code)]
#![allow(unused_variable)]
#![allow(non_snake_case)]

extern crate num;
extern crate native;
extern crate libc;

extern crate glfw;
extern crate gl;
extern crate nanovg;

use glfw::Context;
use std::cell::Cell; // for glfw error count
use nanovg::Ctx;

#[link(name = "glfw")]
extern {}

/// evaluate the expression, then check for GL error.
macro_rules! glcheck(
    ($e: expr) => (
        {
            $e;
            assert_eq!(gl::GetError(), 0);
        }
    )
)

mod perf;
mod demo;

#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, main)
}

/// give GLFW a way to report errors, and count them.
fn error_callback(_: glfw::Error, description: String, error_count: &Cell<uint>) {
    println!("GLFW error {}: {}", error_count.get(), description);
    error_count.set(error_count.get() + 1);
}

fn init_gl() {
    glcheck!(gl::FrontFace(gl::CCW));
    glcheck!(gl::Enable(gl::DEPTH_TEST));
    glcheck!(gl::Enable(gl::SCISSOR_TEST));
    glcheck!(gl::DepthFunc(gl::LEQUAL));
    glcheck!(gl::FrontFace(gl::CCW));
    glcheck!(gl::Enable(gl::CULL_FACE));
    glcheck!(gl::CullFace(gl::BACK));
}

static mut blowup: bool = false;
static mut screenshot: bool = false;
static mut premult: bool = false;

fn main()
{
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

	// set up GLFW error callback, with an error-counter
	glfw.set_error_callback(Some(
	    glfw::Callback {
	        f: error_callback,
	        data: Cell::new(0),
	    }
	));

	glfw.window_hint(glfw::ContextVersion(3, 2));
 	glfw.window_hint(glfw::OpenglForwardCompat(true));
 	glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
 	glfw.window_hint(glfw::OpenglDebugContext(true));

    let (window, events) = glfw.create_window(1100, 800, "NanoVG GL3 Rust demo", glfw::Windowed)
        .expect("Failed to create GLFW window.");

	// window.set_key_callback(key);
    window.set_key_polling(true);

    window.make_current();

    // use glfw to load GL function pointers
    glcheck!(gl::load_with(|name| glfw.get_proc_address(name)));
    init_gl();

   	let vg: nanovg::Ctx = nanovg::Ctx::create_gl3(nanovg::ANTIALIAS | nanovg::STENCIL_STROKES);
   	//assert!(!vg.ptr.is_null());

    let data = demo::DemoData::load(&vg, "../../res");

//    return test_linebreaks(vg);

	glfw.set_swap_interval(0);

	glfw.set_time(0.0);
	let mut prevt = glfw.get_time();

	let mut fps = perf::PerfGraph::init(perf::FPS, "Frame Time");

    while !window.should_close()
    {
    	let t: f64 = glfw.get_time();
    	let dt: f64 = t - prevt;
    	prevt = t;
    	fps.update(dt);

        let (mx, my) = window.get_cursor_pos(); // (f64,f64)
        let (winWidth, winHeight) = window.get_size();  // (i32,i32)
        let (fbWidth, fbHeight) = window.get_framebuffer_size();
        // Calculate pixel ration for hi-dpi devices.
        let pxRatio = fbWidth as f32 / winWidth as f32;

        // Update and render
        glcheck!(gl::Viewport(0, 0, fbWidth, fbHeight));
        unsafe {
            if premult {
                glcheck!(gl::ClearColor(0.0, 0.0, 0.0, 0.0));
            } else {
                glcheck!(gl::ClearColor(0.3, 0.3, 0.32, 1.0));
            }
        }
        glcheck!(gl::Clear(gl::COLOR_BUFFER_BIT|gl::DEPTH_BUFFER_BIT|gl::STENCIL_BUFFER_BIT));

        glcheck!(gl::Enable(gl::BLEND));
        glcheck!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
        glcheck!(gl::Enable(gl::CULL_FACE));
        glcheck!(gl::Disable(gl::DEPTH_TEST));

        vg.begin_frame(winWidth, winHeight, pxRatio as f32);

        unsafe { demo::render_demo(&vg, mx as f32,my as f32, winWidth as f32,winHeight as f32, t as f32, blowup, &data); }
        fps.render(&vg, 5.0, 5.0);

        vg.end_frame();

        gl::Enable(gl::DEPTH_TEST);

        unsafe {
	        if screenshot {
	        	screenshot = false;
	        	demo::save_screenshot(fbWidth as u32, fbHeight as u32, premult, "dump.png");
	        }
        }

    	window.swap_buffers();

        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&window, event);
        }
    }
}

fn handle_window_event(window: &glfw::Window, event: glfw::WindowEvent) {
    match event {
        glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) => {
            window.set_should_close(true)
        }
        glfw::KeyEvent(glfw::KeySpace, _, glfw::Press, _) => {
            unsafe {blowup = !blowup};
        }
        glfw::KeyEvent(glfw::KeyS, _, glfw::Press, _) => {
            unsafe {screenshot = true};
        }
        glfw::KeyEvent(glfw::KeyP, _, glfw::Press, _) => {
            unsafe {premult = !premult};
        }
        _ => {}
    }
}

//// think linebreaks api needs some love
//fn test_linebreaks(vg:Ctx) {
//    let x=0.0; let y=0.0;
//    let width = 120.0;
//
//    let text = "This is longer chunk of text.\n  \n  Would have used lorem ipsum but she    was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.";
//    //let text = "01234 6789 1234 6789 1234 6789 123456789012345678901234567890123456789012345678901234567890123456789";
//
//
//    // The text break API can be used to fill a large buffer of rows,
//    // or to iterate over the text just few lines (or just one) at a time.
//    // The "next" variable of the last returned item tells where to continue.
//    let mut start: uint = 0;    // byte pos in utf8 'text' str
//    let end: uint = text.len(); // exclusive
//    'chunks: loop {
//        let text = text.slice(start, end);
//
//println!("{}", text);
//
//        let rows = vg.text_break_lines(text, width, 3);
//        let nrows = rows.len();
//        if nrows == 0 { break 'chunks; }
//        for i in range(0, nrows) {
//            let row = &rows[i];
//            let line = text.slice(row.start_index(), row.end_index());
//
//println!("i: {}  st: {}, en: {}  \t {} \tnext: {}", i, row.start_index(), row.end_index(), line, row.next_index());
//
//        }
//        // Keep going...
//        start += rows[nrows-1].next_index();
//    }
//}<commit_msg>remove old link command<commit_after>
#![feature(globs)]
#![feature(macro_rules)]
#![allow(dead_code)]
#![allow(unreachable_code)]
#![allow(unused_variable)]
#![allow(non_snake_case)]

extern crate num;
extern crate native;
extern crate libc;

extern crate glfw;
extern crate gl;
extern crate nanovg;

use glfw::Context;
use std::cell::Cell; // for glfw error count
use nanovg::Ctx;

//#[link(name = "glfw")]
//extern {}

/// evaluate the expression, then check for GL error.
macro_rules! glcheck(
    ($e: expr) => (
        {
            $e;
            assert_eq!(gl::GetError(), 0);
        }
    )
)

mod perf;
mod demo;

#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, main)
}

/// give GLFW a way to report errors, and count them.
fn error_callback(_: glfw::Error, description: String, error_count: &Cell<uint>) {
    println!("GLFW error {}: {}", error_count.get(), description);
    error_count.set(error_count.get() + 1);
}

fn init_gl() {
    glcheck!(gl::FrontFace(gl::CCW));
    glcheck!(gl::Enable(gl::DEPTH_TEST));
    glcheck!(gl::Enable(gl::SCISSOR_TEST));
    glcheck!(gl::DepthFunc(gl::LEQUAL));
    glcheck!(gl::FrontFace(gl::CCW));
    glcheck!(gl::Enable(gl::CULL_FACE));
    glcheck!(gl::CullFace(gl::BACK));
}

static mut blowup: bool = false;
static mut screenshot: bool = false;
static mut premult: bool = false;

fn main()
{
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

	// set up GLFW error callback, with an error-counter
	glfw.set_error_callback(Some(
	    glfw::Callback {
	        f: error_callback,
	        data: Cell::new(0),
	    }
	));

	glfw.window_hint(glfw::ContextVersion(3, 2));
 	glfw.window_hint(glfw::OpenglForwardCompat(true));
 	glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
 	glfw.window_hint(glfw::OpenglDebugContext(true));

    let (window, events) = glfw.create_window(1100, 800, "NanoVG GL3 Rust demo", glfw::Windowed)
        .expect("Failed to create GLFW window.");

	// window.set_key_callback(key);
    window.set_key_polling(true);

    window.make_current();

    // use glfw to load GL function pointers
    glcheck!(gl::load_with(|name| glfw.get_proc_address(name)));
    init_gl();

   	let vg: nanovg::Ctx = nanovg::Ctx::create_gl3(nanovg::ANTIALIAS | nanovg::STENCIL_STROKES);
   	//assert!(!vg.ptr.is_null());

    let data = demo::DemoData::load(&vg, "../../res");

//    return test_linebreaks(vg);

	glfw.set_swap_interval(0);

	glfw.set_time(0.0);
	let mut prevt = glfw.get_time();

	let mut fps = perf::PerfGraph::init(perf::FPS, "Frame Time");

    while !window.should_close()
    {
    	let t: f64 = glfw.get_time();
    	let dt: f64 = t - prevt;
    	prevt = t;
    	fps.update(dt);

        let (mx, my) = window.get_cursor_pos(); // (f64,f64)
        let (winWidth, winHeight) = window.get_size();  // (i32,i32)
        let (fbWidth, fbHeight) = window.get_framebuffer_size();
        // Calculate pixel ration for hi-dpi devices.
        let pxRatio = fbWidth as f32 / winWidth as f32;

        // Update and render
        glcheck!(gl::Viewport(0, 0, fbWidth, fbHeight));
        unsafe {
            if premult {
                glcheck!(gl::ClearColor(0.0, 0.0, 0.0, 0.0));
            } else {
                glcheck!(gl::ClearColor(0.3, 0.3, 0.32, 1.0));
            }
        }
        glcheck!(gl::Clear(gl::COLOR_BUFFER_BIT|gl::DEPTH_BUFFER_BIT|gl::STENCIL_BUFFER_BIT));

        glcheck!(gl::Enable(gl::BLEND));
        glcheck!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
        glcheck!(gl::Enable(gl::CULL_FACE));
        glcheck!(gl::Disable(gl::DEPTH_TEST));

        vg.begin_frame(winWidth, winHeight, pxRatio as f32);

        unsafe { demo::render_demo(&vg, mx as f32,my as f32, winWidth as f32,winHeight as f32, t as f32, blowup, &data); }
        fps.render(&vg, 5.0, 5.0);

        vg.end_frame();

        gl::Enable(gl::DEPTH_TEST);

        unsafe {
	        if screenshot {
	        	screenshot = false;
	        	demo::save_screenshot(fbWidth as u32, fbHeight as u32, premult, "dump.png");
	        }
        }

    	window.swap_buffers();

        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&window, event);
        }
    }
}

fn handle_window_event(window: &glfw::Window, event: glfw::WindowEvent) {
    match event {
        glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) => {
            window.set_should_close(true)
        }
        glfw::KeyEvent(glfw::KeySpace, _, glfw::Press, _) => {
            unsafe {blowup = !blowup};
        }
        glfw::KeyEvent(glfw::KeyS, _, glfw::Press, _) => {
            unsafe {screenshot = true};
        }
        glfw::KeyEvent(glfw::KeyP, _, glfw::Press, _) => {
            unsafe {premult = !premult};
        }
        _ => {}
    }
}

//// think linebreaks api needs some love
//fn test_linebreaks(vg:Ctx) {
//    let x=0.0; let y=0.0;
//    let width = 120.0;
//
//    let text = "This is longer chunk of text.\n  \n  Would have used lorem ipsum but she    was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.";
//    //let text = "01234 6789 1234 6789 1234 6789 123456789012345678901234567890123456789012345678901234567890123456789";
//
//
//    // The text break API can be used to fill a large buffer of rows,
//    // or to iterate over the text just few lines (or just one) at a time.
//    // The "next" variable of the last returned item tells where to continue.
//    let mut start: uint = 0;    // byte pos in utf8 'text' str
//    let end: uint = text.len(); // exclusive
//    'chunks: loop {
//        let text = text.slice(start, end);
//
//println!("{}", text);
//
//        let rows = vg.text_break_lines(text, width, 3);
//        let nrows = rows.len();
//        if nrows == 0 { break 'chunks; }
//        for i in range(0, nrows) {
//            let row = &rows[i];
//            let line = text.slice(row.start_index(), row.end_index());
//
//println!("i: {}  st: {}, en: {}  \t {} \tnext: {}", i, row.start_index(), row.end_index(), line, row.next_index());
//
//        }
//        // Keep going...
//        start += rows[nrows-1].next_index();
//    }
//}<|endoftext|>


<commit_before>// Copyright (c) 2016-2020 Fabian Schuiki

//! A list of arguments to a function or task, with different styles resolved.
//!
//! This module simplifies the list of arguments of a function or task. This is
//! necessary since SystemVerilog allows for two distinct styles of declaring
//! the function arguments, which are similar to the ANSI and non-ANSI port list
//! styles for modules. Essentially, the arguments can be declared in the
//! function prototype directly, or as part of the function body (at the very
//! top).
//!
//! More concretely, it does the following:
//!
//! - Canonicalize ANSI/non-ANSI style
//! - Fill in implicit argument details (defaults and carried-over from
//!   previous argument)
//!
//! Note that when this module refers to "functions", it generally means both
//! *functions* and *tasks*.

use crate::crate_prelude::*;
use crate::{ast_map::AstNode, common::arenas::Alloc};
use std::borrow::Cow;

/// A list of arguments of a function or task.
#[derive(Debug, PartialEq, Eq)]
pub struct FuncArgList<'a> {
    /// The function or task containing this argument.
    pub func: &'a ast::SubroutineDecl<'a>,
    /// The canonicalized arguments of the function or task.
    pub args: Vec<FuncArg<'a>>,
}

/// An function or task argument.
#[derive(Debug, PartialEq, Eq)]
pub struct FuncArg<'a> {
    /// The node that spawned this argument.
    pub ast: &'a dyn ast::AnyNode<'a>,
    /// The function or task containing this argument.
    pub func: &'a ast::SubroutineDecl<'a>,
    /// Location of the argument declaration in the source file.
    pub span: Span,
    /// Name of the argument. May be `None` if the argument is part of a
    /// prototype declaration.
    pub name: Option<Spanned<Name>>,
    /// Direction of the argument.
    pub dir: ast::SubroutinePortDir,
    /// Data type of the argument.
    pub ty: &'a ast::Type<'a>,
    /// Unpacked dimensions of the argument.
    pub unpacked_dims: &'a [ast::TypeDim<'a>],
    /// Whether an explicit `var` was present.
    pub var: bool,
    /// Optional default value assigned to the argument if left unassigned.
    pub default: Option<&'a ast::Expr<'a>>,
}

/// Resolve the arguments of a function or task a canonical list.
#[moore_derive::query]
pub(crate) fn canonicalize_func_args<'a>(
    cx: &impl Context<'a>,
    node: &'a ast::SubroutineDecl<'a>,
) -> &'a FuncArgList<'a> {
    debug!("Building port list of {:?}", node);
    let next_rib = node.id(); // TODO(fschuiki): Remove once NodeIds no longer needed

    // If an argument list has been provided (`foo(...);`), use that to gather
    // the list of arguments. If not (`foo;`), scan the function body for
    // argument declarations.
    let args = if let Some(ref args) = node.prototype.args {
        trace!("Uses ANSI style");
        gather_from_args(cx, node, args, next_rib)
    } else {
        trace!("Uses non-ANSI style");
        gather_from_items(cx, node, &node.items, next_rib)
    };

    // Package the argument list up.
    let list = FuncArgList { func: node, args };
    trace!("Argument list of {:?} is: {:#?}", node, list);
    cx.gcx().arena.alloc_func_arg_list(list)
}

/// Gather a list of arguments from the arguments in the function declaration.
fn gather_from_args<'a>(
    cx: &impl Context<'a>,
    node: &'a ast::SubroutineDecl<'a>,
    args: &'a [ast::SubroutinePort<'a>],
    next_rib: NodeId,
) -> Vec<FuncArg<'a>> {
    let mut out_args = vec![];
    let first_span = args.get(0).map(|x| x.span()).unwrap_or(node.span());

    // Determine the default direction and data type. These *may* be carried
    // over from argument to argument.
    let mut carry_dir = ast::SubroutinePortDir::Input;
    let mut carry_ty = Cow::Owned(ast::TypeKind::new(
        first_span.begin().into(),
        ast::LogicType,
    ));
    let mut carry_sign = ast::TypeSign::None;
    let mut carry_packed_dims: &[ast::TypeDim] = &[];

    for arg in args {
        // First resolve the ambiguity in the port type and name.
        let (ty, name) = cx.resolve_subroutine_port_ty_name(Ref(arg));

        // If no direction has been provided, use the one carried over from the
        // previous argument.
        let dir = arg.dir.unwrap_or(carry_dir);

        // Explicitly stating the port resets the carried-over data type.
        if arg.dir.is_some() {
            carry_ty = Cow::Owned(ast::TypeKind::new(
                first_span.begin().into(),
                ast::LogicType,
            ));
            carry_sign = ast::TypeSign::None;
            carry_packed_dims = &[];
        }

        // If no data type, sign, or packed dimensions have been provided, use
        // the ones carried over from the previous argument. Otherwise we use
        // the ones provided, filling in an implicit base data type if needed.
        let inherit = ty.kind.data == ast::ImplicitType
            && ty.sign == ast::TypeSign::None
            && ty.dims.is_empty();

        let (ty, sign, packed_dims, ty_span) = if inherit {
            (carry_ty, carry_sign, carry_packed_dims, None)
        } else {
            // If the argument has an implicit data type, use the one carried
            // over from before.
            let kind = if ty.kind.data == ast::ImplicitType {
                carry_ty
            } else {
                Cow::Borrowed(&ty.kind)
            };
            (kind, ty.sign, ty.dims.as_slice(), Some(ty.span()))
        };

        // Keep the direction, type, sign, and packed dimensions around for the
        // next argument in the list, which might want to inherit them.
        carry_dir = dir;
        carry_ty = ty.clone();
        carry_sign = sign;
        carry_packed_dims = packed_dims;

        // Wrap the type up.
        let ty = cx.arena().alloc(ast::Type::new(
            ty_span.unwrap_or(arg.span()),
            ast::TypeData {
                kind: ty.into_owned(),
                sign: sign,
                dims: packed_dims.to_vec(),
            },
        ));
        ty.link_attach(arg, arg.order());
        cx.register_ast(ty);
        cx.map_ast_with_parent(AstNode::Type(ty), next_rib);

        // Extract the name and default value for the argument.
        let (name, unpacked_dims, default): (_, &[_], _) = match name {
            Some(pn) => (Some(pn.name), pn.dims.as_slice(), pn.expr.as_ref()),
            None => (None, &[], None),
        };

        // Add an argument to the list.
        out_args.push(FuncArg {
            ast: arg,
            func: node,
            span: arg.span,
            name,
            dir,
            ty,
            var: arg.var,
            unpacked_dims,
            default,
        });
    }

    out_args
}

/// Gather a list of arguments from the port declarations in a function body.
fn gather_from_items<'a>(
    cx: &impl Context<'a>,
    node: &'a ast::SubroutineDecl<'a>,
    items: &'a [ast::SubroutineItem<'a>],
    next_rib: NodeId,
) -> Vec<FuncArg<'a>> {
    let mut args = vec![];
    let mut non_port = None;
    let mut non_port_reported = false;

    for item in items {
        // Only consider port declarations.
        let port = match item {
            ast::SubroutineItem::PortDecl(x) => x,
            ast::SubroutineItem::Stmt(x) => {
                non_port = Some(non_port.unwrap_or(x));
                continue;
            }
        };

        // Emit a warning if ports and statements are interleaved.
        if let Some(non_port) = non_port {
            if !non_port_reported {
                cx.emit(
                    DiagBuilder2::warning(format!("port after statement"))
                        .span(port.span())
                        .add_note("Port declaration appears after this statement:")
                        .span(non_port.span())
                        .add_note(
                            "This is accepted by moore, but is forbidden according to IEEE \
                             1800-2017 where all ports must appear before regular statements.",
                        ),
                );
                non_port_reported = true;
            }
        }

        // Determine the data type. If it is an implicit type, default to
        // `logic`.
        let ty: &_ = if port.ty.kind.data == ast::ImplicitType {
            let ty = cx.arena().alloc(ast::Type::new(
                port.ty.span(),
                ast::TypeData {
                    kind: ast::TypeKind::new(port.ty.span(), ast::LogicType),
                    sign: port.ty.sign,
                    dims: port.ty.dims.clone(),
                },
            ));
            ty.link_attach(port, port.order());
            cx.register_ast(ty);
            cx.map_ast_with_parent(AstNode::Type(ty), next_rib);
            ty
        } else {
            &port.ty
        };

        // Add an argument to the list for every declared port name.
        for name in &port.names {
            args.push(FuncArg {
                ast: port,
                func: node,
                span: port.span,
                name: Some(Spanned::new(name.name, name.span)),
                dir: port.dir,
                ty,
                var: port.var,
                unpacked_dims: &name.dims,
                default: name.init.as_ref(),
            });
        }
    }

    args
}

/// A visitor that emits diagnostics for canonicalized function argument lists.
pub struct FuncArgsVerbosityVisitor<'cx, C> {
    cx: &'cx C,
}

impl<'cx, C> FuncArgsVerbosityVisitor<'cx, C> {
    /// Create a new name resolution visitor.
    pub fn new(cx: &'cx C) -> Self {
        FuncArgsVerbosityVisitor { cx }
    }
}

impl<'a, 'cx, C> ast::Visitor<'a> for FuncArgsVerbosityVisitor<'cx, C>
where
    C: Context<'a>,
    'a: 'cx,
{
    fn pre_visit_subroutine_decl(&mut self, node: &'a ast::SubroutineDecl<'a>) -> bool {
        let list = self.cx.canonicalize_func_args(node);
        let mut d = DiagBuilder2::note("canonicalized subroutine arguments")
            .span(node.span())
            .add_note(format!(
                "Subroutine `{}` has the following arguments:",
                node.prototype.name
            ));
        for arg in &list.args {
            let name = match arg.name {
                Some(name) => format!(" {}", name),
                None => format!(""),
            };
            let ty = self.cx.unpacked_type_from_ast(
                Ref(arg.ty),
                Ref(arg.unpacked_dims),
                self.cx.default_param_env(),
                None,
            );
            d = d.add_note(format!("{} {}{}", arg.dir, ty, name));
        }
        self.cx.emit(d);
        true
    }
}
<commit_msg>svlog: Use Ref in canonicalize_func_args<commit_after>// Copyright (c) 2016-2020 Fabian Schuiki

//! A list of arguments to a function or task, with different styles resolved.
//!
//! This module simplifies the list of arguments of a function or task. This is
//! necessary since SystemVerilog allows for two distinct styles of declaring
//! the function arguments, which are similar to the ANSI and non-ANSI port list
//! styles for modules. Essentially, the arguments can be declared in the
//! function prototype directly, or as part of the function body (at the very
//! top).
//!
//! More concretely, it does the following:
//!
//! - Canonicalize ANSI/non-ANSI style
//! - Fill in implicit argument details (defaults and carried-over from
//!   previous argument)
//!
//! Note that when this module refers to "functions", it generally means both
//! *functions* and *tasks*.

use crate::crate_prelude::*;
use crate::{ast_map::AstNode, common::arenas::Alloc};
use std::borrow::Cow;

/// A list of arguments of a function or task.
#[derive(Debug, PartialEq, Eq)]
pub struct FuncArgList<'a> {
    /// The function or task containing this argument.
    pub func: &'a ast::SubroutineDecl<'a>,
    /// The canonicalized arguments of the function or task.
    pub args: Vec<FuncArg<'a>>,
}

/// An function or task argument.
#[derive(Debug, PartialEq, Eq)]
pub struct FuncArg<'a> {
    /// The node that spawned this argument.
    pub ast: &'a dyn ast::AnyNode<'a>,
    /// The function or task containing this argument.
    pub func: &'a ast::SubroutineDecl<'a>,
    /// Location of the argument declaration in the source file.
    pub span: Span,
    /// Name of the argument. May be `None` if the argument is part of a
    /// prototype declaration.
    pub name: Option<Spanned<Name>>,
    /// Direction of the argument.
    pub dir: ast::SubroutinePortDir,
    /// Data type of the argument.
    pub ty: &'a ast::Type<'a>,
    /// Unpacked dimensions of the argument.
    pub unpacked_dims: &'a [ast::TypeDim<'a>],
    /// Whether an explicit `var` was present.
    pub var: bool,
    /// Optional default value assigned to the argument if left unassigned.
    pub default: Option<&'a ast::Expr<'a>>,
}

/// Resolve the arguments of a function or task a canonical list.
#[moore_derive::query]
pub(crate) fn canonicalize_func_args<'a>(
    cx: &impl Context<'a>,
    Ref(node): Ref<'a, ast::SubroutineDecl<'a>>,
) -> &'a FuncArgList<'a> {
    debug!("Building port list of {:?}", node);
    let next_rib = node.id(); // TODO(fschuiki): Remove once NodeIds no longer needed

    // If an argument list has been provided (`foo(...);`), use that to gather
    // the list of arguments. If not (`foo;`), scan the function body for
    // argument declarations.
    let args = if let Some(ref args) = node.prototype.args {
        trace!("Uses ANSI style");
        gather_from_args(cx, node, args, next_rib)
    } else {
        trace!("Uses non-ANSI style");
        gather_from_items(cx, node, &node.items, next_rib)
    };

    // Package the argument list up.
    let list = FuncArgList { func: node, args };
    trace!("Argument list of {:?} is: {:#?}", node, list);
    cx.gcx().arena.alloc_func_arg_list(list)
}

/// Gather a list of arguments from the arguments in the function declaration.
fn gather_from_args<'a>(
    cx: &impl Context<'a>,
    node: &'a ast::SubroutineDecl<'a>,
    args: &'a [ast::SubroutinePort<'a>],
    next_rib: NodeId,
) -> Vec<FuncArg<'a>> {
    let mut out_args = vec![];
    let first_span = args.get(0).map(|x| x.span()).unwrap_or(node.span());

    // Determine the default direction and data type. These *may* be carried
    // over from argument to argument.
    let mut carry_dir = ast::SubroutinePortDir::Input;
    let mut carry_ty = Cow::Owned(ast::TypeKind::new(
        first_span.begin().into(),
        ast::LogicType,
    ));
    let mut carry_sign = ast::TypeSign::None;
    let mut carry_packed_dims: &[ast::TypeDim] = &[];

    for arg in args {
        // First resolve the ambiguity in the port type and name.
        let (ty, name) = cx.resolve_subroutine_port_ty_name(Ref(arg));

        // If no direction has been provided, use the one carried over from the
        // previous argument.
        let dir = arg.dir.unwrap_or(carry_dir);

        // Explicitly stating the port resets the carried-over data type.
        if arg.dir.is_some() {
            carry_ty = Cow::Owned(ast::TypeKind::new(
                first_span.begin().into(),
                ast::LogicType,
            ));
            carry_sign = ast::TypeSign::None;
            carry_packed_dims = &[];
        }

        // If no data type, sign, or packed dimensions have been provided, use
        // the ones carried over from the previous argument. Otherwise we use
        // the ones provided, filling in an implicit base data type if needed.
        let inherit = ty.kind.data == ast::ImplicitType
            && ty.sign == ast::TypeSign::None
            && ty.dims.is_empty();

        let (ty, sign, packed_dims, ty_span) = if inherit {
            (carry_ty, carry_sign, carry_packed_dims, None)
        } else {
            // If the argument has an implicit data type, use the one carried
            // over from before.
            let kind = if ty.kind.data == ast::ImplicitType {
                carry_ty
            } else {
                Cow::Borrowed(&ty.kind)
            };
            (kind, ty.sign, ty.dims.as_slice(), Some(ty.span()))
        };

        // Keep the direction, type, sign, and packed dimensions around for the
        // next argument in the list, which might want to inherit them.
        carry_dir = dir;
        carry_ty = ty.clone();
        carry_sign = sign;
        carry_packed_dims = packed_dims;

        // Wrap the type up.
        let ty = cx.arena().alloc(ast::Type::new(
            ty_span.unwrap_or(arg.span()),
            ast::TypeData {
                kind: ty.into_owned(),
                sign: sign,
                dims: packed_dims.to_vec(),
            },
        ));
        ty.link_attach(arg, arg.order());
        cx.register_ast(ty);
        cx.map_ast_with_parent(AstNode::Type(ty), next_rib);

        // Extract the name and default value for the argument.
        let (name, unpacked_dims, default): (_, &[_], _) = match name {
            Some(pn) => (Some(pn.name), pn.dims.as_slice(), pn.expr.as_ref()),
            None => (None, &[], None),
        };

        // Add an argument to the list.
        out_args.push(FuncArg {
            ast: arg,
            func: node,
            span: arg.span,
            name,
            dir,
            ty,
            var: arg.var,
            unpacked_dims,
            default,
        });
    }

    out_args
}

/// Gather a list of arguments from the port declarations in a function body.
fn gather_from_items<'a>(
    cx: &impl Context<'a>,
    node: &'a ast::SubroutineDecl<'a>,
    items: &'a [ast::SubroutineItem<'a>],
    next_rib: NodeId,
) -> Vec<FuncArg<'a>> {
    let mut args = vec![];
    let mut non_port = None;
    let mut non_port_reported = false;

    for item in items {
        // Only consider port declarations.
        let port = match item {
            ast::SubroutineItem::PortDecl(x) => x,
            ast::SubroutineItem::Stmt(x) => {
                non_port = Some(non_port.unwrap_or(x));
                continue;
            }
        };

        // Emit a warning if ports and statements are interleaved.
        if let Some(non_port) = non_port {
            if !non_port_reported {
                cx.emit(
                    DiagBuilder2::warning(format!("port after statement"))
                        .span(port.span())
                        .add_note("Port declaration appears after this statement:")
                        .span(non_port.span())
                        .add_note(
                            "This is accepted by moore, but is forbidden according to IEEE \
                             1800-2017 where all ports must appear before regular statements.",
                        ),
                );
                non_port_reported = true;
            }
        }

        // Determine the data type. If it is an implicit type, default to
        // `logic`.
        let ty: &_ = if port.ty.kind.data == ast::ImplicitType {
            let ty = cx.arena().alloc(ast::Type::new(
                port.ty.span(),
                ast::TypeData {
                    kind: ast::TypeKind::new(port.ty.span(), ast::LogicType),
                    sign: port.ty.sign,
                    dims: port.ty.dims.clone(),
                },
            ));
            ty.link_attach(port, port.order());
            cx.register_ast(ty);
            cx.map_ast_with_parent(AstNode::Type(ty), next_rib);
            ty
        } else {
            &port.ty
        };

        // Add an argument to the list for every declared port name.
        for name in &port.names {
            args.push(FuncArg {
                ast: port,
                func: node,
                span: port.span,
                name: Some(Spanned::new(name.name, name.span)),
                dir: port.dir,
                ty,
                var: port.var,
                unpacked_dims: &name.dims,
                default: name.init.as_ref(),
            });
        }
    }

    args
}

/// A visitor that emits diagnostics for canonicalized function argument lists.
pub struct FuncArgsVerbosityVisitor<'cx, C> {
    cx: &'cx C,
}

impl<'cx, C> FuncArgsVerbosityVisitor<'cx, C> {
    /// Create a new visitor.
    pub fn new(cx: &'cx C) -> Self {
        FuncArgsVerbosityVisitor { cx }
    }
}

impl<'a, 'cx, C> ast::Visitor<'a> for FuncArgsVerbosityVisitor<'cx, C>
where
    C: Context<'a>,
    'a: 'cx,
{
    fn pre_visit_subroutine_decl(&mut self, node: &'a ast::SubroutineDecl<'a>) -> bool {
        let list = self.cx.canonicalize_func_args(Ref(node));
        let mut d = DiagBuilder2::note("canonicalized subroutine arguments")
            .span(node.span())
            .add_note(format!(
                "Subroutine `{}` has the following arguments:",
                node.prototype.name
            ));
        for arg in &list.args {
            let name = match arg.name {
                Some(name) => format!(" {}", name),
                None => format!(""),
            };
            let ty = self.cx.unpacked_type_from_ast(
                Ref(arg.ty),
                Ref(arg.unpacked_dims),
                self.cx.default_param_env(),
                None,
            );
            d = d.add_note(format!("{} {}{}", arg.dir, ty, name));
        }
        self.cx.emit(d);
        true
    }
}
<|endoftext|>


<commit_before>use std::process::{Command, Output};
use std::fs;
use std::io::prelude::*;
use std::fs::File;
use platform;

#[derive(Clone)]
pub struct SystemServices;

pub enum OSType {
    debian,
    redhat,
    unknown
}

pub trait SystemInterface {
    fn file_exists(&self, path: &String) -> bool;
    fn read_file(&self, path: &String) -> Option<String>;
    fn is_package_installed(&self, package_name: &String) -> bool;
    fn install_package(&self, package: &String) -> Output;
    fn get_hostname(&self) -> Option<String>;
    fn set_hostname(&self, new_hostname: &String) -> bool;
    fn os_type(&self) -> OSType;
}

impl SystemInterface for SystemServices {
     fn file_exists(&self, path: &String) -> bool {
        let metadata = fs::metadata(path);

        match metadata {
            Ok(md) => md.is_dir() || md.is_file(),
            Err(_) => false
        }
    }

     fn read_file(&self, path: &String) -> Option<String> {
        let mut file_handle = File::open(path);
        let mut s = String::new();
        match file_handle {
            Ok(mut handle) => {
                handle.read_to_string(&mut s);
                Some(s)
            },
            Err(err)   => None
        }
    }

     fn is_package_installed(&self, package_name: &String) -> bool {
        let platform = platform::for_os_type(self.os_type()).unwrap();
        let command_str = format!("{} {}", platform.package_installed_command, package_name);
        let output = Command::new(command_str).output();
        output.is_ok()
    }

     fn install_package(&self, package: &String) -> Output {
        let platform = platform::for_os_type(self.os_type()).unwrap();
        let cmd_list :Vec<&str> = platform.install_command.split_whitespace().collect();
        let cmd_name :String = cmd_list.first().unwrap().to_string();
        let mut cmd_args = Vec::new();
        cmd_args.extend(cmd_list.iter().skip(1).map(|s| s.to_string()).collect::<Vec<_>>());
        cmd_args.push(package.to_string());

        Command::new(cmd_name)
            .args(&cmd_args[..])
            .output()
            .unwrap()
    }

     fn get_hostname(&self) -> Option<String> {
        let output = Command::new("hostname").output().unwrap();
        if output.status.success() {
            let hostname_with_newline = String::from_utf8(output.stdout).unwrap();
            Some(hostname_with_newline.replace("\n", ""))
        } else {
            None
        }
    }

     fn set_hostname(&self, new_hostname: &String) -> bool {
        let output = Command::new("hostname")
            .arg(new_hostname)
            .output()
            .unwrap();
        output.status.success()
    }

    fn os_type(&self) -> OSType {
        if self.file_exists(&"/etc/redhat-release".to_string()) ||
            self.file_exists(&"/etc/centos-release".to_string()){
                OSType::redhat
            } else {
                OSType::unknown
            }
    }
}
<commit_msg>Fix broken is-package-installed check<commit_after>use std::process::{Command, Output};
use std::fs;
use std::io::prelude::*;
use std::fs::File;
use platform;

#[derive(Clone)]
pub struct SystemServices;

pub enum OSType {
    debian,
    redhat,
    unknown
}

pub trait SystemInterface {
    fn file_exists(&self, path: &String) -> bool;
    fn read_file(&self, path: &String) -> Option<String>;
    fn is_package_installed(&self, package_name: &String) -> bool;
    fn install_package(&self, package: &String) -> Output;
    fn get_hostname(&self) -> Option<String>;
    fn set_hostname(&self, new_hostname: &String) -> bool;
    fn os_type(&self) -> OSType;
}

impl SystemInterface for SystemServices {
     fn file_exists(&self, path: &String) -> bool {
        let metadata = fs::metadata(path);

        match metadata {
            Ok(md) => md.is_dir() || md.is_file(),
            Err(_) => false
        }
    }

     fn read_file(&self, path: &String) -> Option<String> {
        let mut file_handle = File::open(path);
        let mut s = String::new();
        match file_handle {
            Ok(mut handle) => {
                handle.read_to_string(&mut s);
                Some(s)
            },
            Err(err)   => None
        }
    }

     fn is_package_installed(&self, package_name: &String) -> bool {
        let platform = platform::for_os_type(self.os_type()).unwrap();
        let command_str = format!("{} {}", platform.package_installed_command, package_name);
        let cmd_list :Vec<&str> = command_str.split_whitespace().collect();
        let cmd_name :String = cmd_list.first().unwrap().to_string();
        let mut cmd_args = Vec::new();
        cmd_args.extend(cmd_list.iter().skip(1).map(|s| s.to_string()).collect::<Vec<_>>());

        match Command::new(cmd_name).args(&cmd_args[..]).output() {
            Ok(output) => output.status.success(),
            Err(err)   => false
        }
    }

     fn install_package(&self, package: &String) -> Output {
        let platform = platform::for_os_type(self.os_type()).unwrap();
        let cmd_list :Vec<&str> = platform.install_command.split_whitespace().collect();
        let cmd_name :String = cmd_list.first().unwrap().to_string();
        let mut cmd_args = Vec::new();
        cmd_args.extend(cmd_list.iter().skip(1).map(|s| s.to_string()).collect::<Vec<_>>());
        cmd_args.push(package.to_string());

        Command::new(cmd_name)
            .args(&cmd_args[..])
            .output()
            .unwrap()
    }

     fn get_hostname(&self) -> Option<String> {
        let output = Command::new("hostname").output().unwrap();
        if output.status.success() {
            let hostname_with_newline = String::from_utf8(output.stdout).unwrap();
            Some(hostname_with_newline.replace("\n", ""))
        } else {
            None
        }
    }

     fn set_hostname(&self, new_hostname: &String) -> bool {
        let output = Command::new("hostname")
            .arg(new_hostname)
            .output()
            .unwrap();
        output.status.success()
    }

    fn os_type(&self) -> OSType {
        if self.file_exists(&"/etc/redhat-release".to_string()) ||
            self.file_exists(&"/etc/centos-release".to_string()){
                OSType::redhat
            } else {
                OSType::unknown
            }
    }
}
<|endoftext|>


<commit_before>//! This module provides the Blinn Microfacet Distribution
//! TODO: Wikipedia link or something?

use std::f32;

use bxdf;
use linalg::{self, Vector};
use bxdf::microfacet::MicrofacetDistribution;

/// Struct providing the Blinn microfacet distribution
pub struct Blinn {
    exponent: f32,
}

impl Blinn {
    /// Create the Blinn microfacet distribution with some exponent
    pub fn new(e: f32) -> Blinn {
        Blinn { exponent: e }
    }
}

impl MicrofacetDistribution for Blinn {
    fn eval(&self, w_h: &Vector) -> f32 {
        (self.exponent + 2.0) * f32::consts::FRAC_2_PI
            * f32::powf(f32::abs(bxdf::cos_theta(w_h)), self.exponent)
    }
    fn sample(&self, w_o: &Vector, samples: &(f32, f32)) -> (Vector, f32) {
        // Sample a direction on the hemisphere for the half-vector
        let cos_theta = f32::powf(samples.0, 1.0 / (self.exponent + 1.0));
        let sin_theta = f32::sqrt(f32::max(0.0, 1.0 - cos_theta * cos_theta));
        let phi = f32::consts::PI_2 * samples.1;
        let mut w_h = linalg::spherical_dir(sin_theta, cos_theta, phi);
        if !bxdf::same_hemisphere(w_o, &w_h) {
            w_h = -w_h;
        }
        // The sampled incident direction is the outgoing direction reflected about the half-vector
        let w_i = -*w_o + 2.0 * linalg::dot(w_o, &w_h) * w_h;
        if linalg::dot(w_o, &w_h) <= 0.0 {
            (w_i, 0.0)
        } else {
            let pdf_val = ((self.exponent + 1.0) * f32::powf(cos_theta, self.exponent))
                        / (f32::consts::PI_2 * 4.0 * linalg::dot(w_o, &w_h));
            (w_i, pdf_val)
        }
    }
    fn pdf(&self, w_o: &Vector, w_i: &Vector) -> f32 {
        let w_h = (*w_o + *w_i).normalized();
        let cos_theta = f32::abs(bxdf::cos_theta(&w_h));
        if linalg::dot(w_o, &w_h) <= 0.0 {
            0.0
        } else {
            ((self.exponent + 1.0) * f32::powf(cos_theta, self.exponent))
                / (f32::consts::PI_2 * 4.0 * linalg::dot(w_o, &w_h))
        }
    }
}

<commit_msg>Move out some re-computed values<commit_after>//! This module provides the Blinn Microfacet Distribution
//! TODO: Wikipedia link or something?

use std::f32;

use bxdf;
use linalg::{self, Vector};
use bxdf::microfacet::MicrofacetDistribution;

/// Struct providing the Blinn microfacet distribution
pub struct Blinn {
    exponent: f32,
}

impl Blinn {
    /// Create the Blinn microfacet distribution with some exponent
    pub fn new(e: f32) -> Blinn {
        Blinn { exponent: e }
    }
}

impl MicrofacetDistribution for Blinn {
    fn eval(&self, w_h: &Vector) -> f32 {
        (self.exponent + 2.0) * f32::consts::FRAC_2_PI
            * f32::powf(f32::abs(bxdf::cos_theta(w_h)), self.exponent)
    }
    fn sample(&self, w_o: &Vector, samples: &(f32, f32)) -> (Vector, f32) {
        // Sample a direction on the hemisphere for the half-vector
        let cos_theta = f32::powf(samples.0, 1.0 / (self.exponent + 1.0));
        let sin_theta = f32::sqrt(f32::max(0.0, 1.0 - cos_theta * cos_theta));
        let phi = f32::consts::PI_2 * samples.1;
        let mut w_h = linalg::spherical_dir(sin_theta, cos_theta, phi);
        if !bxdf::same_hemisphere(w_o, &w_h) {
            w_h = -w_h;
        }
        // The sampled incident direction is the outgoing direction reflected about the half-vector
        let w_i = -*w_o + 2.0 * linalg::dot(w_o, &w_h) * w_h;
        let d = linalg::dot(w_o, &w_h);
        if d <= 0.0 {
            (w_i, 0.0)
        } else {
            let pdf_val = ((self.exponent + 1.0) * f32::powf(cos_theta, self.exponent))
                        / (f32::consts::PI_2 * 4.0 * d);
            (w_i, pdf_val)
        }
    }
    fn pdf(&self, w_o: &Vector, w_i: &Vector) -> f32 {
        let w_h = (*w_o + *w_i).normalized();
        let cos_theta = f32::abs(bxdf::cos_theta(&w_h));
        let d = linalg::dot(w_o, &w_h);
        if d <= 0.0 {
            0.0
        } else {
            ((self.exponent + 1.0) * f32::powf(cos_theta, self.exponent))
                / (f32::consts::PI_2 * 4.0 * d)
        }
    }
}

<|endoftext|>


<commit_before>use std::old_io::{IoResult, Reader};
use flate;

pub struct DeflateReader<R> {
    reader: R,
    buffer: Option<Vec<u8>>,
}

impl<R: Reader> DeflateReader<R> {
    pub fn new(reader: R) -> DeflateReader<R> {
        DeflateReader {
            reader: reader,
            buffer: None,
        }
    }
}

impl<R: Reader> Reader for DeflateReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        // filling the buffer if we don't have any
        if self.buffer.is_none() {
            let data = try!(self.reader.read_to_end());

            let result = match flate::deflate_bytes(data.as_slice()) {
                Some(d) => d,
                None => {
                    use std::old_io;
                    use std::old_io::InvalidInput;
                    return Err(old_io::standard_error(InvalidInput));
                }
            };

            self.buffer = Some(result.as_slice().to_vec());
        }

        // if our buffer exists but is empty, we reached EOF
        if self.buffer.as_ref().unwrap().len() == 0 {
            use std::old_io;
            use std::old_io::EndOfFile;
            return Err(old_io::standard_error(EndOfFile));
        }

        // copying the buffer to the output
        let qty = {
            buf.clone_from_slice(self.buffer.as_ref().unwrap().as_slice())
        };

        self.buffer = Some((self.buffer.as_ref().unwrap().slice_from(qty)).to_vec());
        Ok(qty)
    }
}
<commit_msg>fix flate usage<commit_after>use std::old_io::{IoResult, Reader};
use flate;

pub struct DeflateReader<R> {
    reader: R,
    buffer: Option<Vec<u8>>,
}

impl<R: Reader> DeflateReader<R> {
    pub fn new(reader: R) -> DeflateReader<R> {
        DeflateReader {
            reader: reader,
            buffer: None,
        }
    }
}

impl<R: Reader> Reader for DeflateReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        // filling the buffer if we don't have any
        if self.buffer.is_none() {
            let data = try!(self.reader.read_to_end());

            let result = flate::deflate_bytes(data.as_slice());

            self.buffer = Some(result.as_slice().to_vec());
        }

        // if our buffer exists but is empty, we reached EOF
        if self.buffer.as_ref().unwrap().len() == 0 {
            use std::old_io;
            use std::old_io::EndOfFile;
            return Err(old_io::standard_error(EndOfFile));
        }

        // copying the buffer to the output
        let qty = {
            buf.clone_from_slice(self.buffer.as_ref().unwrap().as_slice())
        };

        self.buffer = Some((self.buffer.as_ref().unwrap().slice_from(qty)).to_vec());
        Ok(qty)
    }
}
<|endoftext|>


<commit_before>use std::{fmt, iter::FromIterator, sync::Arc};

use hir::{ExpandResult, MacroFile};
use ide_db::base_db::{
    salsa::debug::{DebugQueryTable, TableEntry},
    CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId,
};
use ide_db::{
    symbol_index::{LibrarySymbolsQuery, SymbolIndex},
    RootDatabase,
};
use itertools::Itertools;
use profile::{memory_usage, Bytes};
use rustc_hash::FxHashMap;
use std::env;
use stdx::format_to;
use syntax::{ast, Parse, SyntaxNode};

fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
    ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
}
fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
    hir::db::ParseMacroExpansionQuery.in_db(db).entries::<SyntaxTreeStats>()
}

// Feature: Status
//
// Shows internal statistic about memory usage of rust-analyzer.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Status**
// |===
// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
    let mut buf = String::new();
    let count = profile::countme::get_all();
    format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>());
    format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::<LibrarySymbolsStats>());
    format_to!(buf, "{}\n", syntax_tree_stats(db));
    format_to!(buf, "{} (Macros)\n", macro_syntax_tree_stats(db));
    format_to!(buf, "{} in total\n", memory_usage());
    if env::var("RA_COUNT").is_ok() {
        format_to!(buf, "\nCounts:\n{}", count.to_string());
    }

    if let Some(file_id) = file_id {
        format_to!(buf, "\nFile info:\n");
        let krate = crate::parent_module::crate_for(db, file_id).pop();
        match krate {
            Some(krate) => {
                let crate_graph = db.crate_graph();
                let display_crate = |krate: CrateId| match &crate_graph[krate].display_name {
                    Some(it) => format!("{}({:?})", it, krate),
                    None => format!("{:?}", krate),
                };
                format_to!(buf, "Crate: {}\n", display_crate(krate));
                let deps = crate_graph[krate]
                    .dependencies
                    .iter()
                    .map(|dep| format!("{}={:?}", dep.name, dep.crate_id))
                    .format(", ");
                format_to!(buf, "Dependencies: {}\n", deps);
            }
            None => format_to!(buf, "Does not belong to any crate"),
        }
    }

    buf.trim().to_string()
}

#[derive(Default)]
struct FilesStats {
    total: usize,
    size: Bytes,
}

impl fmt::Display for FilesStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} of files", self.size)
    }
}

impl FromIterator<TableEntry<FileId, Arc<String>>> for FilesStats {
    fn from_iter<T>(iter: T) -> FilesStats
    where
        T: IntoIterator<Item = TableEntry<FileId, Arc<String>>>,
    {
        let mut res = FilesStats::default();
        for entry in iter {
            res.total += 1;
            res.size += entry.value.unwrap().len();
        }
        res
    }
}

#[derive(Default)]
pub(crate) struct SyntaxTreeStats {
    total: usize,
    pub(crate) retained: usize,
}

impl fmt::Display for SyntaxTreeStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} trees, {} preserved", self.total, self.retained)
    }
}

impl FromIterator<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStats {
    fn from_iter<T>(iter: T) -> SyntaxTreeStats
    where
        T: IntoIterator<Item = TableEntry<FileId, Parse<ast::SourceFile>>>,
    {
        let mut res = SyntaxTreeStats::default();
        for entry in iter {
            res.total += 1;
            res.retained += entry.value.is_some() as usize;
        }
        res
    }
}

impl<M> FromIterator<TableEntry<MacroFile, ExpandResult<Option<(Parse<SyntaxNode>, M)>>>>
    for SyntaxTreeStats
{
    fn from_iter<T>(iter: T) -> SyntaxTreeStats
    where
        T: IntoIterator<Item = TableEntry<MacroFile, ExpandResult<Option<(Parse<SyntaxNode>, M)>>>>,
    {
        let mut res = SyntaxTreeStats::default();
        for entry in iter {
            res.total += 1;
            res.retained += entry.value.is_some() as usize;
        }
        res
    }
}

#[derive(Default)]
struct LibrarySymbolsStats {
    total: usize,
    size: Bytes,
}

impl fmt::Display for LibrarySymbolsStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} of index symbols ({})", self.size, self.total)
    }
}

impl FromIterator<TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>
    for LibrarySymbolsStats
{
    fn from_iter<T>(iter: T) -> LibrarySymbolsStats
    where
        T: IntoIterator<Item = TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>,
    {
        let mut res = LibrarySymbolsStats::default();
        for entry in iter {
            let value = entry.value.unwrap();
            for symbols in value.values() {
                res.total += symbols.len();
                res.size += symbols.memory_size();
            }
        }
        res
    }
}
<commit_msg>Update crates/ide/src/status.rs<commit_after>use std::{fmt, iter::FromIterator, sync::Arc};

use hir::{ExpandResult, MacroFile};
use ide_db::base_db::{
    salsa::debug::{DebugQueryTable, TableEntry},
    CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId,
};
use ide_db::{
    symbol_index::{LibrarySymbolsQuery, SymbolIndex},
    RootDatabase,
};
use itertools::Itertools;
use profile::{memory_usage, Bytes};
use rustc_hash::FxHashMap;
use std::env;
use stdx::format_to;
use syntax::{ast, Parse, SyntaxNode};

fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
    ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
}
fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
    hir::db::ParseMacroExpansionQuery.in_db(db).entries::<SyntaxTreeStats>()
}

// Feature: Status
//
// Shows internal statistic about memory usage of rust-analyzer.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Status**
// |===
// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
    let mut buf = String::new();
    let count = profile::countme::get_all();
    format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>());
    format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::<LibrarySymbolsStats>());
    format_to!(buf, "{}\n", syntax_tree_stats(db));
    format_to!(buf, "{} (Macros)\n", macro_syntax_tree_stats(db));
    format_to!(buf, "{} in total\n", memory_usage());
    if env::var("RA_COUNT").is_ok() {
        format_to!(buf, "\nCounts:\n{}", count);
    }

    if let Some(file_id) = file_id {
        format_to!(buf, "\nFile info:\n");
        let krate = crate::parent_module::crate_for(db, file_id).pop();
        match krate {
            Some(krate) => {
                let crate_graph = db.crate_graph();
                let display_crate = |krate: CrateId| match &crate_graph[krate].display_name {
                    Some(it) => format!("{}({:?})", it, krate),
                    None => format!("{:?}", krate),
                };
                format_to!(buf, "Crate: {}\n", display_crate(krate));
                let deps = crate_graph[krate]
                    .dependencies
                    .iter()
                    .map(|dep| format!("{}={:?}", dep.name, dep.crate_id))
                    .format(", ");
                format_to!(buf, "Dependencies: {}\n", deps);
            }
            None => format_to!(buf, "Does not belong to any crate"),
        }
    }

    buf.trim().to_string()
}

#[derive(Default)]
struct FilesStats {
    total: usize,
    size: Bytes,
}

impl fmt::Display for FilesStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} of files", self.size)
    }
}

impl FromIterator<TableEntry<FileId, Arc<String>>> for FilesStats {
    fn from_iter<T>(iter: T) -> FilesStats
    where
        T: IntoIterator<Item = TableEntry<FileId, Arc<String>>>,
    {
        let mut res = FilesStats::default();
        for entry in iter {
            res.total += 1;
            res.size += entry.value.unwrap().len();
        }
        res
    }
}

#[derive(Default)]
pub(crate) struct SyntaxTreeStats {
    total: usize,
    pub(crate) retained: usize,
}

impl fmt::Display for SyntaxTreeStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} trees, {} preserved", self.total, self.retained)
    }
}

impl FromIterator<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStats {
    fn from_iter<T>(iter: T) -> SyntaxTreeStats
    where
        T: IntoIterator<Item = TableEntry<FileId, Parse<ast::SourceFile>>>,
    {
        let mut res = SyntaxTreeStats::default();
        for entry in iter {
            res.total += 1;
            res.retained += entry.value.is_some() as usize;
        }
        res
    }
}

impl<M> FromIterator<TableEntry<MacroFile, ExpandResult<Option<(Parse<SyntaxNode>, M)>>>>
    for SyntaxTreeStats
{
    fn from_iter<T>(iter: T) -> SyntaxTreeStats
    where
        T: IntoIterator<Item = TableEntry<MacroFile, ExpandResult<Option<(Parse<SyntaxNode>, M)>>>>,
    {
        let mut res = SyntaxTreeStats::default();
        for entry in iter {
            res.total += 1;
            res.retained += entry.value.is_some() as usize;
        }
        res
    }
}

#[derive(Default)]
struct LibrarySymbolsStats {
    total: usize,
    size: Bytes,
}

impl fmt::Display for LibrarySymbolsStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} of index symbols ({})", self.size, self.total)
    }
}

impl FromIterator<TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>
    for LibrarySymbolsStats
{
    fn from_iter<T>(iter: T) -> LibrarySymbolsStats
    where
        T: IntoIterator<Item = TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>,
    {
        let mut res = LibrarySymbolsStats::default();
        for entry in iter {
            let value = entry.value.unwrap();
            for symbols in value.values() {
                res.total += symbols.len();
                res.size += symbols.memory_size();
            }
        }
        res
    }
}
<|endoftext|>


<commit_before>use llvm_sys::LLVMThreadLocalMode;
#[llvm_versions(3.6..8.0)]
use llvm_sys::core::{LLVMGetVisibility, LLVMSetVisibility, LLVMGetSection, LLVMSetSection, LLVMIsExternallyInitialized, LLVMSetExternallyInitialized, LLVMDeleteGlobal, LLVMIsGlobalConstant, LLVMSetGlobalConstant, LLVMGetPreviousGlobal, LLVMGetNextGlobal, LLVMIsThreadLocal, LLVMSetThreadLocal, LLVMGetThreadLocalMode, LLVMSetThreadLocalMode, LLVMGetInitializer, LLVMSetInitializer, LLVMIsDeclaration, LLVMGetDLLStorageClass, LLVMSetDLLStorageClass, LLVMGetAlignment, LLVMSetAlignment, LLVMGetLinkage, LLVMSetLinkage};
#[llvm_versions(8.0..=latest)]
use llvm_sys::core::{LLVMGetVisibility, LLVMSetVisibility, LLVMGetSection, LLVMSetSection, LLVMIsExternallyInitialized, LLVMSetExternallyInitialized, LLVMDeleteGlobal, LLVMIsGlobalConstant, LLVMSetGlobalConstant, LLVMGetPreviousGlobal, LLVMGetNextGlobal, LLVMIsThreadLocal, LLVMSetThreadLocal, LLVMGetThreadLocalMode, LLVMSetThreadLocalMode, LLVMGetInitializer, LLVMSetInitializer, LLVMIsDeclaration, LLVMGetDLLStorageClass, LLVMSetDLLStorageClass, LLVMGetAlignment, LLVMSetAlignment, LLVMGetLinkage, LLVMSetLinkage};
#[llvm_versions(3.6..=6.0)]
use llvm_sys::core::{LLVMHasUnnamedAddr, LLVMSetUnnamedAddr};
#[llvm_versions(7.0..=latest)]
use llvm_sys::core::{LLVMGetUnnamedAddress, LLVMSetUnnamedAddress};
#[llvm_versions(7.0..=latest)]
use llvm_sys::LLVMUnnamedAddr;
use llvm_sys::prelude::LLVMValueRef;

use std::ffi::{CString, CStr};

use crate::{GlobalVisibility, ThreadLocalMode, DLLStorageClass};
use crate::module::Linkage;
use crate::support::LLVMString;
#[llvm_versions(7.0..=latest)]
use crate::comdat::Comdat;
use crate::values::traits::AsValueRef;
use crate::values::{BasicValueEnum, BasicValue, PointerValue, Value};

// REVIEW: GlobalValues are always PointerValues. With SubTypes, we should
// compress this into a PointerValue<Global> type
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct GlobalValue<'ctx> {
    global_value: Value<'ctx>,
}

impl<'ctx> GlobalValue<'ctx> {
    pub(crate) fn new(value: LLVMValueRef) -> Self {
        assert!(!value.is_null());

        GlobalValue {
            global_value: Value::new(value),
        }
    }

    pub fn get_previous_global(&self) -> Option<GlobalValue> {
        let value = unsafe {
            LLVMGetPreviousGlobal(self.as_value_ref())
        };

        if value.is_null() {
            return None;
        }

        Some(GlobalValue::new(value))
    }

    pub fn get_next_global(&self) -> Option<GlobalValue> {
        let value = unsafe {
            LLVMGetNextGlobal(self.as_value_ref())
        };

        if value.is_null() {
            return None;
        }

        Some(GlobalValue::new(value))
    }

    pub fn get_dll_storage_class(&self) -> DLLStorageClass {
        let dll_storage_class = unsafe {
            LLVMGetDLLStorageClass(self.as_value_ref())
        };

        DLLStorageClass::new(dll_storage_class)
    }

    pub fn set_dll_storage_class(&self, dll_storage_class: DLLStorageClass) {
        unsafe {
            LLVMSetDLLStorageClass(self.as_value_ref(), dll_storage_class.as_llvm_enum())
        }
    }

    pub fn get_initializer(&self) -> Option<BasicValueEnum<'ctx>> {
        let value = unsafe {
            LLVMGetInitializer(self.as_value_ref())
        };

        if value.is_null() {
            return None;
        }

        Some(BasicValueEnum::new(value))
    }

    // SubType: This input type should be tied to the BasicType
    pub fn set_initializer(&self, value: &dyn BasicValue<'ctx>) {
        unsafe {
            LLVMSetInitializer(self.as_value_ref(), value.as_value_ref())
        }
    }

    pub fn is_thread_local(&self) -> bool {
        unsafe {
            LLVMIsThreadLocal(self.as_value_ref()) == 1
        }
    }

    // TODOC: Setting this to true is the same as setting GeneralDynamicTLSModel
    pub fn set_thread_local(&self, is_thread_local: bool) {
        unsafe {
            LLVMSetThreadLocal(self.as_value_ref(), is_thread_local as i32)
        }
    }

    pub fn get_thread_local_mode(&self) -> Option<ThreadLocalMode> {
        let thread_local_mode = unsafe {
            LLVMGetThreadLocalMode(self.as_value_ref())
        };

        ThreadLocalMode::new(thread_local_mode)
    }

    // REVIEW: Does this have any bad behavior if it isn't thread local or just a noop?
    // or should it call self.set_thread_local(true)?
    pub fn set_thread_local_mode(&self, thread_local_mode: Option<ThreadLocalMode>) {
        let thread_local_mode = match thread_local_mode {
            Some(mode) => mode.as_llvm_mode(),
            None => LLVMThreadLocalMode::LLVMNotThreadLocal,
        };

        unsafe {
            LLVMSetThreadLocalMode(self.as_value_ref(), thread_local_mode)
        }
    }

    // SubType: This should be moved into the type. GlobalValue<Initialized/Uninitialized>
    /// Determines whether or not a `GlobalValue` is a declaration or a definition.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use inkwell::context::Context;
    ///
    /// let context = Context::create();
    /// let builder = context.create_builder();
    /// let module = context.create_module("my_mod");
    /// let void_type = context.void_type();
    /// let fn_type = void_type.fn_type(&[], false);
    /// let fn_value = module.add_function("my_func", fn_type, None);
    ///
    /// assert!(fn_value.as_global_value().is_declaration());
    ///
    /// context.append_basic_block(fn_value, "entry");
    ///
    /// assert!(!fn_value.as_global_value().is_declaration());
    /// ```
    pub fn is_declaration(&self) -> bool {
        unsafe {
            LLVMIsDeclaration(self.as_value_ref()) == 1
        }
    }

    #[llvm_versions(3.6..7.0)]
    pub fn has_unnamed_addr(&self) -> bool {
        unsafe {
            LLVMHasUnnamedAddr(self.as_value_ref()) == 1
        }
    }

    #[llvm_versions(7.0..=latest)]
    pub fn has_unnamed_addr(&self) -> bool {
        unsafe {
            LLVMGetUnnamedAddress(self.as_value_ref()) == LLVMUnnamedAddr::LLVMGlobalUnnamedAddr
        }
    }

    #[llvm_versions(3.6..7.0)]
    pub fn set_unnamed_addr(&self, has_unnamed_addr: bool) {
        unsafe {
            LLVMSetUnnamedAddr(self.as_value_ref(), has_unnamed_addr as i32)
        }
    }

    #[llvm_versions(7.0..=latest)]
    pub fn set_unnamed_addr(&self, has_unnamed_addr: bool) {
        unsafe {
            if has_unnamed_addr {
                LLVMSetUnnamedAddress(self.as_value_ref(), UnnamedAddress::Global.into())
            } else {
                LLVMSetUnnamedAddress(self.as_value_ref(), UnnamedAddress::None.into())
            }
        }
    }

    pub fn is_constant(&self) -> bool {
        unsafe {
            LLVMIsGlobalConstant(self.as_value_ref()) == 1
        }
    }

    pub fn set_constant(&self, is_constant: bool) {
        unsafe {
            LLVMSetGlobalConstant(self.as_value_ref(), is_constant as i32)
        }
    }

    pub fn is_externally_initialized(&self) -> bool {
        unsafe {
            LLVMIsExternallyInitialized(self.as_value_ref()) == 1
        }
    }

    pub fn set_externally_initialized(&self, externally_initialized: bool) {
        unsafe {
            LLVMSetExternallyInitialized(self.as_value_ref(), externally_initialized as i32)
        }
    }

    pub fn set_visibility(&self, visibility: GlobalVisibility) {
        unsafe {
            LLVMSetVisibility(self.as_value_ref(), visibility.as_llvm_enum())
        }
    }

    pub fn get_visibility(&self) -> GlobalVisibility {
        let visibility = unsafe {
            LLVMGetVisibility(self.as_value_ref())
        };

        GlobalVisibility::new(visibility)
    }

    pub fn get_section(&self) -> &CStr {
        unsafe {
            CStr::from_ptr(LLVMGetSection(self.as_value_ref()))
        }
    }

    pub fn set_section(&self, section: &str) {
        let c_string = CString::new(section).expect("Conversion to CString failed unexpectedly");

        unsafe {
            LLVMSetSection(self.as_value_ref(), c_string.as_ptr())
        }
    }

    pub unsafe fn delete(self) {
        LLVMDeleteGlobal(self.as_value_ref())
    }

    pub fn as_pointer_value(&self) -> PointerValue<'ctx> {
        PointerValue::new(self.as_value_ref())
    }

    pub fn get_alignment(&self) -> u32 {
        unsafe {
            LLVMGetAlignment(self.as_value_ref())
        }
    }

    pub fn set_alignment(&self, alignment: u32) {
        unsafe {
            LLVMSetAlignment(self.as_value_ref(), alignment)
        }
    }

    /// Gets a `Comdat` assigned to this `GlobalValue`, if any.
    #[llvm_versions(7.0..=latest)]
    pub fn get_comdat(&self) -> Option<Comdat> {
        use llvm_sys::comdat::LLVMGetComdat;

        let comdat_ptr = unsafe {
            LLVMGetComdat(self.as_value_ref())
        };

        if comdat_ptr.is_null() {
            return None;
        }

        Some(Comdat::new(comdat_ptr))
    }

    /// Assigns a `Comdat` to this `GlobalValue`.
    #[llvm_versions(7.0..=latest)]
    pub fn set_comdat(&self, comdat: Comdat) {
        use llvm_sys::comdat::LLVMSetComdat;

        unsafe {
            LLVMSetComdat(self.as_value_ref(), comdat.0)
        }
    }

    #[llvm_versions(7.0..=latest)]
    pub fn get_unnamed_address(&self) -> UnnamedAddress {
        use llvm_sys::core::LLVMGetUnnamedAddress;

        let unnamed_address = unsafe {
            LLVMGetUnnamedAddress(self.as_value_ref())
        };

        UnnamedAddress::new(unnamed_address)
    }

    #[llvm_versions(7.0..=latest)]
    pub fn set_unnamed_address(&self, address: UnnamedAddress) {
        use llvm_sys::core::LLVMSetUnnamedAddress;

        unsafe {
            LLVMSetUnnamedAddress(self.as_value_ref(), address.into())
        }
    }

    pub fn get_linkage(&self) -> Linkage {
        let linkage = unsafe {
            LLVMGetLinkage(self.as_value_ref())
        };

        Linkage::new(linkage)
    }

    pub fn set_linkage(&self, linkage: Linkage) {
        unsafe {
            LLVMSetLinkage(self.as_value_ref(), linkage.as_llvm_enum())
        }
    }

    pub fn print_to_string(&self) -> LLVMString {
        self.global_value.print_to_string()
    }
}

impl AsValueRef for GlobalValue<'_> {
    fn as_value_ref(&self) -> LLVMValueRef {
        self.global_value.value
    }
}

/// This enum determines the significance of a `GlobalValue`'s address.
#[llvm_versions(7.0..=latest)]
#[llvm_enum(LLVMUnnamedAddr)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum UnnamedAddress {
    /// Address of the `GlobalValue` is significant.
    #[llvm_variant(LLVMNoUnnamedAddr)]
    None,

    /// Address of the `GlobalValue` is locally insignificant.
    #[llvm_variant(LLVMLocalUnnamedAddr)]
    Local,

    /// Address of the `GlobalValue` is globally insignificant.
    #[llvm_variant(LLVMGlobalUnnamedAddr)]
    Global,
}
<commit_msg>Add missing GlobalValue lifetimes<commit_after>use llvm_sys::LLVMThreadLocalMode;
#[llvm_versions(3.6..8.0)]
use llvm_sys::core::{LLVMGetVisibility, LLVMSetVisibility, LLVMGetSection, LLVMSetSection, LLVMIsExternallyInitialized, LLVMSetExternallyInitialized, LLVMDeleteGlobal, LLVMIsGlobalConstant, LLVMSetGlobalConstant, LLVMGetPreviousGlobal, LLVMGetNextGlobal, LLVMIsThreadLocal, LLVMSetThreadLocal, LLVMGetThreadLocalMode, LLVMSetThreadLocalMode, LLVMGetInitializer, LLVMSetInitializer, LLVMIsDeclaration, LLVMGetDLLStorageClass, LLVMSetDLLStorageClass, LLVMGetAlignment, LLVMSetAlignment, LLVMGetLinkage, LLVMSetLinkage};
#[llvm_versions(8.0..=latest)]
use llvm_sys::core::{LLVMGetVisibility, LLVMSetVisibility, LLVMGetSection, LLVMSetSection, LLVMIsExternallyInitialized, LLVMSetExternallyInitialized, LLVMDeleteGlobal, LLVMIsGlobalConstant, LLVMSetGlobalConstant, LLVMGetPreviousGlobal, LLVMGetNextGlobal, LLVMIsThreadLocal, LLVMSetThreadLocal, LLVMGetThreadLocalMode, LLVMSetThreadLocalMode, LLVMGetInitializer, LLVMSetInitializer, LLVMIsDeclaration, LLVMGetDLLStorageClass, LLVMSetDLLStorageClass, LLVMGetAlignment, LLVMSetAlignment, LLVMGetLinkage, LLVMSetLinkage};
#[llvm_versions(3.6..=6.0)]
use llvm_sys::core::{LLVMHasUnnamedAddr, LLVMSetUnnamedAddr};
#[llvm_versions(7.0..=latest)]
use llvm_sys::core::{LLVMGetUnnamedAddress, LLVMSetUnnamedAddress};
#[llvm_versions(7.0..=latest)]
use llvm_sys::LLVMUnnamedAddr;
use llvm_sys::prelude::LLVMValueRef;

use std::ffi::{CString, CStr};

use crate::{GlobalVisibility, ThreadLocalMode, DLLStorageClass};
use crate::module::Linkage;
use crate::support::LLVMString;
#[llvm_versions(7.0..=latest)]
use crate::comdat::Comdat;
use crate::values::traits::AsValueRef;
use crate::values::{BasicValueEnum, BasicValue, PointerValue, Value};

// REVIEW: GlobalValues are always PointerValues. With SubTypes, we should
// compress this into a PointerValue<Global> type
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct GlobalValue<'ctx> {
    global_value: Value<'ctx>,
}

impl<'ctx> GlobalValue<'ctx> {
    pub(crate) fn new(value: LLVMValueRef) -> Self {
        assert!(!value.is_null());

        GlobalValue {
            global_value: Value::new(value),
        }
    }

    pub fn get_previous_global(&self) -> Option<GlobalValue<'ctx>> {
        let value = unsafe {
            LLVMGetPreviousGlobal(self.as_value_ref())
        };

        if value.is_null() {
            return None;
        }

        Some(GlobalValue::new(value))
    }

    pub fn get_next_global(&self) -> Option<GlobalValue<'ctx>> {
        let value = unsafe {
            LLVMGetNextGlobal(self.as_value_ref())
        };

        if value.is_null() {
            return None;
        }

        Some(GlobalValue::new(value))
    }

    pub fn get_dll_storage_class(&self) -> DLLStorageClass {
        let dll_storage_class = unsafe {
            LLVMGetDLLStorageClass(self.as_value_ref())
        };

        DLLStorageClass::new(dll_storage_class)
    }

    pub fn set_dll_storage_class(&self, dll_storage_class: DLLStorageClass) {
        unsafe {
            LLVMSetDLLStorageClass(self.as_value_ref(), dll_storage_class.as_llvm_enum())
        }
    }

    pub fn get_initializer(&self) -> Option<BasicValueEnum<'ctx>> {
        let value = unsafe {
            LLVMGetInitializer(self.as_value_ref())
        };

        if value.is_null() {
            return None;
        }

        Some(BasicValueEnum::new(value))
    }

    // SubType: This input type should be tied to the BasicType
    pub fn set_initializer(&self, value: &dyn BasicValue<'ctx>) {
        unsafe {
            LLVMSetInitializer(self.as_value_ref(), value.as_value_ref())
        }
    }

    pub fn is_thread_local(&self) -> bool {
        unsafe {
            LLVMIsThreadLocal(self.as_value_ref()) == 1
        }
    }

    // TODOC: Setting this to true is the same as setting GeneralDynamicTLSModel
    pub fn set_thread_local(&self, is_thread_local: bool) {
        unsafe {
            LLVMSetThreadLocal(self.as_value_ref(), is_thread_local as i32)
        }
    }

    pub fn get_thread_local_mode(&self) -> Option<ThreadLocalMode> {
        let thread_local_mode = unsafe {
            LLVMGetThreadLocalMode(self.as_value_ref())
        };

        ThreadLocalMode::new(thread_local_mode)
    }

    // REVIEW: Does this have any bad behavior if it isn't thread local or just a noop?
    // or should it call self.set_thread_local(true)?
    pub fn set_thread_local_mode(&self, thread_local_mode: Option<ThreadLocalMode>) {
        let thread_local_mode = match thread_local_mode {
            Some(mode) => mode.as_llvm_mode(),
            None => LLVMThreadLocalMode::LLVMNotThreadLocal,
        };

        unsafe {
            LLVMSetThreadLocalMode(self.as_value_ref(), thread_local_mode)
        }
    }

    // SubType: This should be moved into the type. GlobalValue<Initialized/Uninitialized>
    /// Determines whether or not a `GlobalValue` is a declaration or a definition.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use inkwell::context::Context;
    ///
    /// let context = Context::create();
    /// let builder = context.create_builder();
    /// let module = context.create_module("my_mod");
    /// let void_type = context.void_type();
    /// let fn_type = void_type.fn_type(&[], false);
    /// let fn_value = module.add_function("my_func", fn_type, None);
    ///
    /// assert!(fn_value.as_global_value().is_declaration());
    ///
    /// context.append_basic_block(fn_value, "entry");
    ///
    /// assert!(!fn_value.as_global_value().is_declaration());
    /// ```
    pub fn is_declaration(&self) -> bool {
        unsafe {
            LLVMIsDeclaration(self.as_value_ref()) == 1
        }
    }

    #[llvm_versions(3.6..7.0)]
    pub fn has_unnamed_addr(&self) -> bool {
        unsafe {
            LLVMHasUnnamedAddr(self.as_value_ref()) == 1
        }
    }

    #[llvm_versions(7.0..=latest)]
    pub fn has_unnamed_addr(&self) -> bool {
        unsafe {
            LLVMGetUnnamedAddress(self.as_value_ref()) == LLVMUnnamedAddr::LLVMGlobalUnnamedAddr
        }
    }

    #[llvm_versions(3.6..7.0)]
    pub fn set_unnamed_addr(&self, has_unnamed_addr: bool) {
        unsafe {
            LLVMSetUnnamedAddr(self.as_value_ref(), has_unnamed_addr as i32)
        }
    }

    #[llvm_versions(7.0..=latest)]
    pub fn set_unnamed_addr(&self, has_unnamed_addr: bool) {
        unsafe {
            if has_unnamed_addr {
                LLVMSetUnnamedAddress(self.as_value_ref(), UnnamedAddress::Global.into())
            } else {
                LLVMSetUnnamedAddress(self.as_value_ref(), UnnamedAddress::None.into())
            }
        }
    }

    pub fn is_constant(&self) -> bool {
        unsafe {
            LLVMIsGlobalConstant(self.as_value_ref()) == 1
        }
    }

    pub fn set_constant(&self, is_constant: bool) {
        unsafe {
            LLVMSetGlobalConstant(self.as_value_ref(), is_constant as i32)
        }
    }

    pub fn is_externally_initialized(&self) -> bool {
        unsafe {
            LLVMIsExternallyInitialized(self.as_value_ref()) == 1
        }
    }

    pub fn set_externally_initialized(&self, externally_initialized: bool) {
        unsafe {
            LLVMSetExternallyInitialized(self.as_value_ref(), externally_initialized as i32)
        }
    }

    pub fn set_visibility(&self, visibility: GlobalVisibility) {
        unsafe {
            LLVMSetVisibility(self.as_value_ref(), visibility.as_llvm_enum())
        }
    }

    pub fn get_visibility(&self) -> GlobalVisibility {
        let visibility = unsafe {
            LLVMGetVisibility(self.as_value_ref())
        };

        GlobalVisibility::new(visibility)
    }

    pub fn get_section(&self) -> &CStr {
        unsafe {
            CStr::from_ptr(LLVMGetSection(self.as_value_ref()))
        }
    }

    pub fn set_section(&self, section: &str) {
        let c_string = CString::new(section).expect("Conversion to CString failed unexpectedly");

        unsafe {
            LLVMSetSection(self.as_value_ref(), c_string.as_ptr())
        }
    }

    pub unsafe fn delete(self) {
        LLVMDeleteGlobal(self.as_value_ref())
    }

    pub fn as_pointer_value(&self) -> PointerValue<'ctx> {
        PointerValue::new(self.as_value_ref())
    }

    pub fn get_alignment(&self) -> u32 {
        unsafe {
            LLVMGetAlignment(self.as_value_ref())
        }
    }

    pub fn set_alignment(&self, alignment: u32) {
        unsafe {
            LLVMSetAlignment(self.as_value_ref(), alignment)
        }
    }

    /// Gets a `Comdat` assigned to this `GlobalValue`, if any.
    #[llvm_versions(7.0..=latest)]
    pub fn get_comdat(&self) -> Option<Comdat> {
        use llvm_sys::comdat::LLVMGetComdat;

        let comdat_ptr = unsafe {
            LLVMGetComdat(self.as_value_ref())
        };

        if comdat_ptr.is_null() {
            return None;
        }

        Some(Comdat::new(comdat_ptr))
    }

    /// Assigns a `Comdat` to this `GlobalValue`.
    #[llvm_versions(7.0..=latest)]
    pub fn set_comdat(&self, comdat: Comdat) {
        use llvm_sys::comdat::LLVMSetComdat;

        unsafe {
            LLVMSetComdat(self.as_value_ref(), comdat.0)
        }
    }

    #[llvm_versions(7.0..=latest)]
    pub fn get_unnamed_address(&self) -> UnnamedAddress {
        use llvm_sys::core::LLVMGetUnnamedAddress;

        let unnamed_address = unsafe {
            LLVMGetUnnamedAddress(self.as_value_ref())
        };

        UnnamedAddress::new(unnamed_address)
    }

    #[llvm_versions(7.0..=latest)]
    pub fn set_unnamed_address(&self, address: UnnamedAddress) {
        use llvm_sys::core::LLVMSetUnnamedAddress;

        unsafe {
            LLVMSetUnnamedAddress(self.as_value_ref(), address.into())
        }
    }

    pub fn get_linkage(&self) -> Linkage {
        let linkage = unsafe {
            LLVMGetLinkage(self.as_value_ref())
        };

        Linkage::new(linkage)
    }

    pub fn set_linkage(&self, linkage: Linkage) {
        unsafe {
            LLVMSetLinkage(self.as_value_ref(), linkage.as_llvm_enum())
        }
    }

    pub fn print_to_string(&self) -> LLVMString {
        self.global_value.print_to_string()
    }
}

impl AsValueRef for GlobalValue<'_> {
    fn as_value_ref(&self) -> LLVMValueRef {
        self.global_value.value
    }
}

/// This enum determines the significance of a `GlobalValue`'s address.
#[llvm_versions(7.0..=latest)]
#[llvm_enum(LLVMUnnamedAddr)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum UnnamedAddress {
    /// Address of the `GlobalValue` is significant.
    #[llvm_variant(LLVMNoUnnamedAddr)]
    None,

    /// Address of the `GlobalValue` is locally insignificant.
    #[llvm_variant(LLVMLocalUnnamedAddr)]
    Local,

    /// Address of the `GlobalValue` is globally insignificant.
    #[llvm_variant(LLVMGlobalUnnamedAddr)]
    Global,
}
<|endoftext|>


<commit_before>//! The `print-cfg` sub-command.
//!
//! Read a series of Cretonne IL files and print their control flow graphs
//! in graphviz format.
use std::fs::File;
use std::io::{Read, Write, stdout};

use CommandResult;
use cretonne::repr::Function;
use cretonne::cfg::ControlFlowGraph;
use cretonne::instructions::InstructionData;
use cton_reader::parser::Parser;

pub fn run(files: Vec<String>) -> CommandResult {
    for (i, f) in files.into_iter().enumerate() {
        if i != 0 {
            println!("");
        }
        try!(print_cfg(f))
    }
    Ok(())
}

struct CFGPrinter<T: Write> {
    level: usize,
    writer: T,
    buffer: String,
}

impl<T: Write> CFGPrinter<T> {
    pub fn new(writer: T) -> CFGPrinter<T> {
        CFGPrinter{level: 0, writer: writer, buffer: String::new()}
    }

    pub fn print(&mut self, func: &Function) -> Result<(), String> {
        self.level = 0;
        self.header();
        self.push_indent();
        self.ebb_subgraphs(func);
        let cfg = ControlFlowGraph::new(&func);
        self.cfg_connections(&cfg);
        self.pop_indent();
        self.footer();
        self.write()
    }

    fn write(&mut self) -> Result<(), String> {
        match self.writer.write(self.buffer.as_bytes()) {
            Err(_) => return Err("Write failed!".to_string()),
            _ => (),
        };
        match self.writer.flush() {
            Err(_) => return Err("Flush failed!".to_string()),
            _ => (),
        };
        Ok(())
    }

    fn append(&mut self, s: &str) {
        let mut indent = String::new();
        for _ in 0 .. self.level {
            indent = indent + "    ";
        }
        self.buffer.push_str(&(indent + s));
    }

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

    fn pop_indent(&mut self) {
        if self.level > 0 {
            self.level -= 1;
        }
    }

    fn open_paren(&mut self) {
        self.append("{");
    }

    fn close_paren(&mut self) {
        self.append("}");
    }

    fn newline(&mut self) {
        self.append("\n");
    }

    fn header(&mut self) {
        self.append("digraph ");
        self.open_paren();
        self.newline();
        self.push_indent();
        self.append("{rank=min; ebb0}");
        self.pop_indent();
        self.newline();
    }

    fn footer(&mut self) {
        self.close_paren();
        self.newline();
    }

    fn ebb_subgraphs(&mut self, func: &Function) {
        for ebb in func.ebbs_numerically() {
            let inst_data = func.ebb_insts(ebb)
                .filter(|inst| {
                    match func[*inst] {
                        InstructionData::Branch{ ty: _, opcode: _, data: _ } => true,
                        InstructionData::Jump{ ty: _, opcode: _, data: _ } => true,
                        _ => false
                    }
                })
                .map(|inst| {
                    let op = match func[inst] {
                        InstructionData::Branch{ ty: _, opcode, ref data } => {
                            Some((opcode, data.destination))
                        },
                        InstructionData::Jump{ ty: _, opcode, ref data } => {
                            Some((opcode, data.destination))
                        },
                        _ => None
                    };
                    (inst, op)
                })
                .collect::<Vec<_>>();

            let mut insts = vec![format!("{}", ebb)];
            for (inst, data) in inst_data {
                let (op, dest) = data.unwrap();
                insts.push(format!("<{}>{} {}", inst, op, dest));
            }

            self.append(&format!("{} [shape=record, label=\"{}{}{}\"]",
                                ebb, "{", insts.join(" | "), "}"));
            self.newline();
        }
    }

    fn cfg_connections(&mut self, cfg: &ControlFlowGraph) {
        for (ref ebb, ref predecessors) in cfg.iter() {
            for &(parent, inst) in *predecessors {
                self.append(&format!("{}:{} -> {}", parent, inst, ebb));
                self.newline();
            }
        }
    }

}

fn print_cfg(filename: String) -> CommandResult {
    let mut file = try!(File::open(&filename).map_err(|e| format!("{}: {}", filename, e)));
    let mut buffer = String::new();
    try!(file.read_to_string(&mut buffer)
        .map_err(|e| format!("Couldn't read {}: {}", filename, e)));
    let items = try!(Parser::parse(&buffer).map_err(|e| format!("{}: {}", filename, e)));

    let mut cfg_printer = CFGPrinter::new(stdout());
    for (idx, func) in items.into_iter().enumerate() {
        if idx != 0 {
            println!("");
        }

        try!(cfg_printer.print(&func));
    }

    Ok(())
}
<commit_msg>Id CFG graphs by function name<commit_after>//! The `print-cfg` sub-command.
//!
//! Read a series of Cretonne IL files and print their control flow graphs
//! in graphviz format.
use std::fs::File;
use std::io::{Read, Write, stdout};

use CommandResult;
use cretonne::repr::Function;
use cretonne::cfg::ControlFlowGraph;
use cretonne::instructions::InstructionData;
use cton_reader::parser::Parser;

pub fn run(files: Vec<String>) -> CommandResult {
    for (i, f) in files.into_iter().enumerate() {
        if i != 0 {
            println!("");
        }
        try!(print_cfg(f))
    }
    Ok(())
}

struct CFGPrinter<T: Write> {
    level: usize,
    writer: T,
    buffer: String,
}

impl<T: Write> CFGPrinter<T> {
    pub fn new(writer: T) -> CFGPrinter<T> {
        CFGPrinter{level: 0, writer: writer, buffer: String::new()}
    }

    pub fn print(&mut self, func: &Function) -> Result<(), String> {
        self.level = 0;
        self.header(func);
        self.push_indent();
        self.ebb_subgraphs(func);
        let cfg = ControlFlowGraph::new(&func);
        self.cfg_connections(&cfg);
        self.pop_indent();
        self.footer();
        self.write()
    }

    fn write(&mut self) -> Result<(), String> {
        match self.writer.write(self.buffer.as_bytes()) {
            Err(_) => return Err("Write failed!".to_string()),
            _ => (),
        };
        match self.writer.flush() {
            Err(_) => return Err("Flush failed!".to_string()),
            _ => (),
        };
        Ok(())
    }

    fn append(&mut self, s: &str) {
        let mut indent = String::new();
        for _ in 0 .. self.level {
            indent = indent + "    ";
        }
        self.buffer.push_str(&(indent + s));
    }

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

    fn pop_indent(&mut self) {
        if self.level > 0 {
            self.level -= 1;
        }
    }

    fn open_paren(&mut self) {
        self.append("{");
    }

    fn close_paren(&mut self) {
        self.append("}");
    }

    fn newline(&mut self) {
        self.append("\n");
    }

    fn header(&mut self, func: &Function) {
        self.append(&format!("digraph {} ", func.name));
        self.open_paren();
        self.newline();
        self.push_indent();
        self.append("{rank=min; ebb0}");
        self.pop_indent();
        self.newline();
    }

    fn footer(&mut self) {
        self.close_paren();
        self.newline();
    }

    fn ebb_subgraphs(&mut self, func: &Function) {
        for ebb in func.ebbs_numerically() {
            let inst_data = func.ebb_insts(ebb)
                .filter(|inst| {
                    match func[*inst] {
                        InstructionData::Branch{ ty: _, opcode: _, data: _ } => true,
                        InstructionData::Jump{ ty: _, opcode: _, data: _ } => true,
                        _ => false
                    }
                })
                .map(|inst| {
                    let op = match func[inst] {
                        InstructionData::Branch{ ty: _, opcode, ref data } => {
                            Some((opcode, data.destination))
                        },
                        InstructionData::Jump{ ty: _, opcode, ref data } => {
                            Some((opcode, data.destination))
                        },
                        _ => None
                    };
                    (inst, op)
                })
                .collect::<Vec<_>>();

            let mut insts = vec![format!("{}", ebb)];
            for (inst, data) in inst_data {
                let (op, dest) = data.unwrap();
                insts.push(format!("<{}>{} {}", inst, op, dest));
            }

            self.append(&format!("{} [shape=record, label=\"{}{}{}\"]",
                                ebb, "{", insts.join(" | "), "}"));
            self.newline();
        }
    }

    fn cfg_connections(&mut self, cfg: &ControlFlowGraph) {
        for (ref ebb, ref predecessors) in cfg.iter() {
            for &(parent, inst) in *predecessors {
                self.append(&format!("{}:{} -> {}", parent, inst, ebb));
                self.newline();
            }
        }
    }

}

fn print_cfg(filename: String) -> CommandResult {
    let mut file = try!(File::open(&filename).map_err(|e| format!("{}: {}", filename, e)));
    let mut buffer = String::new();
    try!(file.read_to_string(&mut buffer)
        .map_err(|e| format!("Couldn't read {}: {}", filename, e)));
    let items = try!(Parser::parse(&buffer).map_err(|e| format!("{}: {}", filename, e)));

    let mut cfg_printer = CFGPrinter::new(stdout());
    for (idx, func) in items.into_iter().enumerate() {
        if idx != 0 {
            println!("");
        }

        try!(cfg_printer.print(&func));
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::path::*;
use std::io::{Result, Write};

use analysis::rust_type::AsStr;
use env::Env;
use file_saver::*;
use library;
use nameutil::*;
use super::ffi_type::*;
use super::statics;
use super::super::general;

pub fn generate(env: &Env) {
    println!("generating sys for {}", env.config.library_name);

    let path =  PathBuf::from(&env.config.target_path)
        .join(file_name_sys(&env.config.library_name, "lib"));
    println!("Generating file {:?}", path);

    save_to_file(path, &mut |w| generate_funcs(w, env));
}

fn generate_funcs<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));

    try!(statics::generate(w));

    let ns_id = library::MAIN_NAMESPACE;
    let ns = env.library.namespace(ns_id);

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(generate_classes_funcs(w, env, ns_id, ns));

    //TODO: other functions
    try!(writeln!(w, "\n}}"));

    Ok(())
}
fn generate_classes_funcs<W: Write>(w: &mut W, env: &Env, ns_id: u16, ns:&library::Namespace) -> Result<()> {
    let mut vec: Vec<(library::TypeId, &library::Class)> = Vec::with_capacity(ns.types.len());
    for id in 0..ns.types.len() {
        let tid = library::TypeId { ns_id: ns_id, id: id as u32 };
        if let &library::Type::Class(ref klass) = env.library.type_(tid) {
            vec.push((tid, klass));
        }
    }
    vec.sort_by(|&(_, klass1), &(_, klass2)| klass1.glib_type_name.cmp(&klass2.glib_type_name));

    for (_, ref klass) in vec {
        try!(generate_class_funcs(w, env, klass));
    }

    Ok(())
}

fn generate_class_funcs<W: Write>(w: &mut W, env: &Env, klass: &library::Class) -> Result<()> {
    try!(writeln!(w, ""));
    try!(writeln!(w, "    //========================================================================="));
    try!(writeln!(w, "    // {}", klass.glib_type_name));
    try!(writeln!(w, "    //========================================================================="));
    try!(writeln!(w, "    pub fn {:<36}() -> GType;", klass.glib_get_type));

    for func in &klass.functions {
        let decl = function_declaration(env, func);
        try!(writeln!(w, "    {}", decl));
    }

    Ok(())
}

fn function_declaration(env: &Env, func: &library::Function) -> String {
    let ret_str = function_return_value(env, func);

    format!("pub fn {:<36}(){};", func.c_identifier, ret_str)
}

fn function_return_value(env: &Env, func: &library::Function) -> String {
    if func.ret.typ == Default::default() { return String::new(); }
    let ffi_type = ffi_type(env, func.ret.typ);
    format!(" -> {}", ffi_type.as_str())
}
<commit_msg>Comment functions with bad return types<commit_after>use std::path::*;
use std::io::{Result, Write};

use analysis::rust_type::AsStr;
use env::Env;
use file_saver::*;
use library;
use nameutil::*;
use super::ffi_type::*;
use super::statics;
use super::super::general;

pub fn generate(env: &Env) {
    println!("generating sys for {}", env.config.library_name);

    let path =  PathBuf::from(&env.config.target_path)
        .join(file_name_sys(&env.config.library_name, "lib"));
    println!("Generating file {:?}", path);

    save_to_file(path, &mut |w| generate_funcs(w, env));
}

fn generate_funcs<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));

    try!(statics::generate(w));

    let ns_id = library::MAIN_NAMESPACE;
    let ns = env.library.namespace(ns_id);

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(generate_classes_funcs(w, env, ns_id, ns));

    //TODO: other functions
    try!(writeln!(w, "\n}}"));

    Ok(())
}
fn generate_classes_funcs<W: Write>(w: &mut W, env: &Env, ns_id: u16, ns:&library::Namespace) -> Result<()> {
    let mut vec: Vec<(library::TypeId, &library::Class)> = Vec::with_capacity(ns.types.len());
    for id in 0..ns.types.len() {
        let tid = library::TypeId { ns_id: ns_id, id: id as u32 };
        if let &library::Type::Class(ref klass) = env.library.type_(tid) {
            vec.push((tid, klass));
        }
    }
    vec.sort_by(|&(_, klass1), &(_, klass2)| klass1.glib_type_name.cmp(&klass2.glib_type_name));

    for (_, ref klass) in vec {
        try!(generate_class_funcs(w, env, klass));
    }

    Ok(())
}

fn generate_class_funcs<W: Write>(w: &mut W, env: &Env, klass: &library::Class) -> Result<()> {
    try!(writeln!(w, ""));
    try!(writeln!(w, "    //========================================================================="));
    try!(writeln!(w, "    // {}", klass.glib_type_name));
    try!(writeln!(w, "    //========================================================================="));
    try!(writeln!(w, "    pub fn {:<36}() -> GType;", klass.glib_get_type));

    for func in &klass.functions {
        let decl = function_declaration(env, func);
        try!(writeln!(w, "    {}", decl));
    }

    Ok(())
}

fn function_declaration(env: &Env, func: &library::Function) -> String {
    let (commented, ret_str) = function_return_value(env, func);

    let commented_str = if commented { "//" } else { "" };
    format!("{}pub fn {:<36}(){};", commented_str, func.c_identifier, ret_str)
}

fn function_return_value(env: &Env, func: &library::Function) -> (bool, String) {
    if func.ret.typ == Default::default() { return (false, String::new()) }
    let ffi_type = ffi_type(env, func.ret.typ);
    let commented = ffi_type.is_err();
    (commented, format!(" -> {}", ffi_type.as_str()))
}
<|endoftext|>