<commit_before>use im::HashMap;
use itertools::Itertools;

use crate::{
    builtin_functions::BuiltinFunction,
    compiler::hir::{self, Expression},
    discover::run::run_call,
    input::Input,
};

use super::{
    result::DiscoverResult,
    run::Discover,
    value::{Environment, Value},
};

pub fn run_builtin_function(
    db: &dyn Discover,
    builtin_function: BuiltinFunction,
    arguments: Vec<hir::Id>,
    environment: Environment,
) -> DiscoverResult {
    log::info!(
        "run_builtin_function: builtin{:?} {:?}",
        builtin_function,
        arguments
    );
    // Handle builtin functions that don't need to resolve the arguments.
    match builtin_function {
        BuiltinFunction::IfElse => return if_else(db, arguments, environment),
        _ => {}
    }

    let arguments = arguments
        .iter()
        .map(|it| environment.get(it).transitive())
        .collect::<DiscoverResult<_>>()?;
    match builtin_function {
        BuiltinFunction::Add => add(arguments),
        BuiltinFunction::Equals => equals(arguments),
        BuiltinFunction::GetArgumentCount => get_argument_count(db, arguments),
        BuiltinFunction::Panic => panic(arguments),
        BuiltinFunction::Print => print(arguments),
        BuiltinFunction::StructGet => struct_get(arguments),
        BuiltinFunction::StructGetKeys => struct_get_keys(arguments),
        BuiltinFunction::StructHasKey => struct_has_key(arguments),
        BuiltinFunction::TypeOf => type_of(arguments),
        BuiltinFunction::Use => use_(db, arguments),
        _ => panic!("Unhandled builtin function: {:?}", builtin_function),
    }
}

macro_rules! destructure {
    ($arguments:expr, $enum:pat, $body:block) => {{
        if let $enum = &$arguments[..] {
            $body
        } else {
            DiscoverResult::panic(format!("Invalid arguments").to_owned())
        }
    }};
}

fn add(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [Value::Int(a), Value::Int(b)], {
        Value::Int(a + b).into()
    })
}

fn equals(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [a, b], { Value::bool(a == b).into() })
}

fn get_argument_count(db: &dyn Discover, arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [Value::Lambda(function)], {
        // TODO: support parameter counts > 2^64 on 128-bit systems and better
        let expression = match db.find_expression(function.id.to_owned()).unwrap() {
            Expression::Lambda(lambda) => lambda,
            _ => panic!("Lambda's function"),
        };
        Value::Int(expression.parameters.len() as u64).into()
    })
}

fn if_else(db: &dyn Discover, arguments: Vec<hir::Id>, environment: Environment) -> DiscoverResult {
    if let [condition, then, else_] = &arguments[..] {
        let body_id = match environment.get(condition)? {
            value if value == Value::bool(true) => then,
            value if value == Value::bool(false) => else_,
            value => {
                return DiscoverResult::panic(format!(
                    "Condition must be a boolean, but was {:?}.",
                    value
                ));
            }
        };

        run_call(db, body_id.to_owned(), vec![], environment)
    } else {
        DiscoverResult::panic(format!(
            "Builtin if/else called with wrong number of arguments: {}, expected: {}",
            arguments.len(),
            3
        ))
    }
}

fn panic(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [value], { DiscoverResult::Panic(value.clone()) })
}

fn print(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [value], {
        println!("{:?}", value);
        Value::nothing().into()
    })
}

fn struct_get(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [struct_, key], {
        let struct_ = expect_struct("builtinStructGet".to_owned(), struct_)?;
        struct_
            .get(key)
            .map(|value| value.clone().into())
            .unwrap_or_else(|| {
                DiscoverResult::panic(format!("Struct does not contain key {:?}", key))
            })
    })
}
fn struct_get_keys(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [struct_], {
        let struct_ = expect_struct("builtinStructGetKeys".to_owned(), struct_)?;
        Value::list(struct_.keys().cloned().collect()).into()
    })
}
fn struct_has_key(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [struct_, key], {
        let struct_ = expect_struct("builtinStructHasKey".to_owned(), struct_)?;
        Value::bool(struct_.contains_key(key)).into()
    })
}
fn expect_struct(function_name: String, value: &Value) -> DiscoverResult<&HashMap<Value, Value>> {
    match value {
        Value::Struct(struct_) => struct_.into(),
        _ => {
            return DiscoverResult::panic(format!(
                "`{}` expected a struct as its first parameter, but received: {:?}",
                function_name, value
            ))
        }
    }
}

fn type_of(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [value], {
        match value {
            Value::Int(_) => Value::Symbol("Int".to_owned()).into(),
            Value::Text(_) => Value::Symbol("Text".to_owned()).into(),
            Value::Symbol(_) => Value::Symbol("Symbol".to_owned()).into(),
            Value::Struct(_) => Value::Symbol("Struct".to_owned()).into(),
            Value::Lambda(_) => Value::Symbol("Function".to_owned()).into(),
        }
    })
}

fn use_(db: &dyn Discover, arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [current_path, target], {
        // `current_path` is set by us and not users, hence we don't have to validate it that strictly.
        let current_path_struct = match current_path {
            Value::Struct(value) => value,
            _ => unreachable!(),
        };
        let mut current_path = vec![];
        let mut index = 0;
        loop {
            if let Some(component) = current_path_struct.get(&Value::Int(index)) {
                match component {
                    Value::Text(component) => current_path.push(component.clone()),
                    _ => unreachable!(),
                }
            } else {
                break;
            }
            index += 1;
        }

        let target = match target {
            Value::Text(value) => value,
            it => {
                return DiscoverResult::panic(format!(
                    "`use` expected a text as its second parameter, but received: {:?}",
                    it
                ))
            }
        };
        let target = match UseTarget::parse(target) {
            Ok(target) => target,
            Err(error) => return DiscoverResult::panic(error),
        };

        if target.parent_navigations > current_path.len() {
            return DiscoverResult::panic("Too many parent navigations.".to_owned());
        }

        let inputs = target.resolve(&current_path[..]);
        let input = match inputs
            .iter()
            .filter(|&it| db.get_input(it.to_owned()).is_some())
            .next()
        {
            Some(target) => target,
            None => {
                return DiscoverResult::panic(format!(
                    "Target doesn't exist. Checked the following path(s): {}",
                    inputs.iter().map(|it| format!("{}", it)).join(", ")
                ));
            }
        };

        let (hir, _) = db.hir(input.clone()).unwrap();
        let discover_result = db.run_all(input.to_owned());

        hir.identifiers
            .iter()
            .map(|(id, key)| {
                let mut key = key.to_owned();
                key.get_mut(0..1).unwrap().make_ascii_uppercase();
                let key = Value::Symbol(key.to_owned());

                let value = match discover_result.get(id) {
                    Some(value) => value.to_owned()?,
                    None => return DiscoverResult::ErrorInHir,
                };

                DiscoverResult::Value((key, value))
            })
            .collect::<DiscoverResult<HashMap<Value, Value>>>()
            .map(|it| Value::Struct(it))
    })
}
struct UseTarget {
    parent_navigations: usize,
    path: Vec<String>,
}
impl UseTarget {
    const PARENT_NAVIGATION_CHAR: char = '.';

    fn parse(target: &str) -> Result<Self, String> {
        let mut parent_navigations = 0;
        let mut target = target;
        while target.chars().next() == Some(UseTarget::PARENT_NAVIGATION_CHAR) {
            parent_navigations += 1;
            target = &target[UseTarget::PARENT_NAVIGATION_CHAR.len_utf8()..];
        }

        let mut path = vec![];
        loop {
            let mut chars = vec![];
            while let Some(c) = target.chars().next() {
                if c == UseTarget::PARENT_NAVIGATION_CHAR {
                    break;
                }
                chars.push(c);
                target = &target[c.len_utf8()..];
            }

            if target.is_empty() {
                path.push(chars.into_iter().join(""));
                break;
            }

            if chars.is_empty() {
                return Err("Target contains consecutive dots (`.`) in the path.".to_owned());
            }

            path.push(chars.into_iter().join(""));
        }
        Ok(UseTarget {
            parent_navigations,
            path,
        })
    }

    fn resolve(&self, current_path: &[String]) -> Vec<Input> {
        let mut path = current_path.to_owned();
        if self.parent_navigations == 0 {
            assert!(!path.is_empty());
            let last = path.last_mut().unwrap();
            if last == ".candy" {
                path.pop();
            } else {
                *last = last
                    .strip_suffix(".candy")
                    .expect("File name must end with `.candy`.")
                    .to_owned();
            }
        } else {
            for _ in 0..self.parent_navigations {
                if path.is_empty() {
                    return vec![];
                }
                path.pop();
            }
        }

        for part in &self.path {
            path.push(part.to_owned());
        }

        let mut result = vec![];

        let mut subdirectory = path.clone();
        subdirectory.push(".candy".to_owned());
        result.push(Input::File(subdirectory));

        if path.len() >= 1 {
            let last = path.last_mut().unwrap();
            *last = format!("{}.candy", last);
            result.push(Input::File(path));
        }
        result
    }
}
<commit_msg>change(compiler): change builtin function logging from info trace<commit_after>use im::HashMap;
use itertools::Itertools;

use crate::{
    builtin_functions::BuiltinFunction,
    compiler::hir::{self, Expression},
    discover::run::run_call,
    input::Input,
};

use super::{
    result::DiscoverResult,
    run::Discover,
    value::{Environment, Value},
};

pub fn run_builtin_function(
    db: &dyn Discover,
    builtin_function: BuiltinFunction,
    arguments: Vec<hir::Id>,
    environment: Environment,
) -> DiscoverResult {
    log::trace!(
        "run_builtin_function: builtin{:?} {:?}",
        builtin_function,
        arguments
    );
    // Handle builtin functions that don't need to resolve the arguments.
    match builtin_function {
        BuiltinFunction::IfElse => return if_else(db, arguments, environment),
        _ => {}
    }

    let arguments = arguments
        .iter()
        .map(|it| environment.get(it).transitive())
        .collect::<DiscoverResult<_>>()?;
    match builtin_function {
        BuiltinFunction::Add => add(arguments),
        BuiltinFunction::Equals => equals(arguments),
        BuiltinFunction::GetArgumentCount => get_argument_count(db, arguments),
        BuiltinFunction::Panic => panic(arguments),
        BuiltinFunction::Print => print(arguments),
        BuiltinFunction::StructGet => struct_get(arguments),
        BuiltinFunction::StructGetKeys => struct_get_keys(arguments),
        BuiltinFunction::StructHasKey => struct_has_key(arguments),
        BuiltinFunction::TypeOf => type_of(arguments),
        BuiltinFunction::Use => use_(db, arguments),
        _ => panic!("Unhandled builtin function: {:?}", builtin_function),
    }
}

macro_rules! destructure {
    ($arguments:expr, $enum:pat, $body:block) => {{
        if let $enum = &$arguments[..] {
            $body
        } else {
            DiscoverResult::panic(format!("Invalid arguments").to_owned())
        }
    }};
}

fn add(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [Value::Int(a), Value::Int(b)], {
        Value::Int(a + b).into()
    })
}

fn equals(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [a, b], { Value::bool(a == b).into() })
}

fn get_argument_count(db: &dyn Discover, arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [Value::Lambda(function)], {
        // TODO: support parameter counts > 2^64 on 128-bit systems and better
        let expression = match db.find_expression(function.id.to_owned()).unwrap() {
            Expression::Lambda(lambda) => lambda,
            _ => panic!("Lambda's function"),
        };
        Value::Int(expression.parameters.len() as u64).into()
    })
}

fn if_else(db: &dyn Discover, arguments: Vec<hir::Id>, environment: Environment) -> DiscoverResult {
    if let [condition, then, else_] = &arguments[..] {
        let body_id = match environment.get(condition)? {
            value if value == Value::bool(true) => then,
            value if value == Value::bool(false) => else_,
            value => {
                return DiscoverResult::panic(format!(
                    "Condition must be a boolean, but was {:?}.",
                    value
                ));
            }
        };

        run_call(db, body_id.to_owned(), vec![], environment)
    } else {
        DiscoverResult::panic(format!(
            "Builtin if/else called with wrong number of arguments: {}, expected: {}",
            arguments.len(),
            3
        ))
    }
}

fn panic(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [value], { DiscoverResult::Panic(value.clone()) })
}

fn print(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [value], {
        println!("{:?}", value);
        Value::nothing().into()
    })
}

fn struct_get(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [struct_, key], {
        let struct_ = expect_struct("builtinStructGet".to_owned(), struct_)?;
        struct_
            .get(key)
            .map(|value| value.clone().into())
            .unwrap_or_else(|| {
                DiscoverResult::panic(format!("Struct does not contain key {:?}", key))
            })
    })
}
fn struct_get_keys(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [struct_], {
        let struct_ = expect_struct("builtinStructGetKeys".to_owned(), struct_)?;
        Value::list(struct_.keys().cloned().collect()).into()
    })
}
fn struct_has_key(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [struct_, key], {
        let struct_ = expect_struct("builtinStructHasKey".to_owned(), struct_)?;
        Value::bool(struct_.contains_key(key)).into()
    })
}
fn expect_struct(function_name: String, value: &Value) -> DiscoverResult<&HashMap<Value, Value>> {
    match value {
        Value::Struct(struct_) => struct_.into(),
        _ => {
            return DiscoverResult::panic(format!(
                "`{}` expected a struct as its first parameter, but received: {:?}",
                function_name, value
            ))
        }
    }
}

fn type_of(arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [value], {
        match value {
            Value::Int(_) => Value::Symbol("Int".to_owned()).into(),
            Value::Text(_) => Value::Symbol("Text".to_owned()).into(),
            Value::Symbol(_) => Value::Symbol("Symbol".to_owned()).into(),
            Value::Struct(_) => Value::Symbol("Struct".to_owned()).into(),
            Value::Lambda(_) => Value::Symbol("Function".to_owned()).into(),
        }
    })
}

fn use_(db: &dyn Discover, arguments: Vec<Value>) -> DiscoverResult {
    destructure!(arguments, [current_path, target], {
        // `current_path` is set by us and not users, hence we don't have to validate it that strictly.
        let current_path_struct = match current_path {
            Value::Struct(value) => value,
            _ => unreachable!(),
        };
        let mut current_path = vec![];
        let mut index = 0;
        loop {
            if let Some(component) = current_path_struct.get(&Value::Int(index)) {
                match component {
                    Value::Text(component) => current_path.push(component.clone()),
                    _ => unreachable!(),
                }
            } else {
                break;
            }
            index += 1;
        }

        let target = match target {
            Value::Text(value) => value,
            it => {
                return DiscoverResult::panic(format!(
                    "`use` expected a text as its second parameter, but received: {:?}",
                    it
                ))
            }
        };
        let target = match UseTarget::parse(target) {
            Ok(target) => target,
            Err(error) => return DiscoverResult::panic(error),
        };

        if target.parent_navigations > current_path.len() {
            return DiscoverResult::panic("Too many parent navigations.".to_owned());
        }

        let inputs = target.resolve(&current_path[..]);
        let input = match inputs
            .iter()
            .filter(|&it| db.get_input(it.to_owned()).is_some())
            .next()
        {
            Some(target) => target,
            None => {
                return DiscoverResult::panic(format!(
                    "Target doesn't exist. Checked the following path(s): {}",
                    inputs.iter().map(|it| format!("{}", it)).join(", ")
                ));
            }
        };

        let (hir, _) = db.hir(input.clone()).unwrap();
        let discover_result = db.run_all(input.to_owned());

        hir.identifiers
            .iter()
            .map(|(id, key)| {
                let mut key = key.to_owned();
                key.get_mut(0..1).unwrap().make_ascii_uppercase();
                let key = Value::Symbol(key.to_owned());

                let value = match discover_result.get(id) {
                    Some(value) => value.to_owned()?,
                    None => return DiscoverResult::ErrorInHir,
                };

                DiscoverResult::Value((key, value))
            })
            .collect::<DiscoverResult<HashMap<Value, Value>>>()
            .map(|it| Value::Struct(it))
    })
}
struct UseTarget {
    parent_navigations: usize,
    path: Vec<String>,
}
impl UseTarget {
    const PARENT_NAVIGATION_CHAR: char = '.';

    fn parse(target: &str) -> Result<Self, String> {
        let mut parent_navigations = 0;
        let mut target = target;
        while target.chars().next() == Some(UseTarget::PARENT_NAVIGATION_CHAR) {
            parent_navigations += 1;
            target = &target[UseTarget::PARENT_NAVIGATION_CHAR.len_utf8()..];
        }

        let mut path = vec![];
        loop {
            let mut chars = vec![];
            while let Some(c) = target.chars().next() {
                if c == UseTarget::PARENT_NAVIGATION_CHAR {
                    break;
                }
                chars.push(c);
                target = &target[c.len_utf8()..];
            }

            if target.is_empty() {
                path.push(chars.into_iter().join(""));
                break;
            }

            if chars.is_empty() {
                return Err("Target contains consecutive dots (`.`) in the path.".to_owned());
            }

            path.push(chars.into_iter().join(""));
        }
        Ok(UseTarget {
            parent_navigations,
            path,
        })
    }

    fn resolve(&self, current_path: &[String]) -> Vec<Input> {
        let mut path = current_path.to_owned();
        if self.parent_navigations == 0 {
            assert!(!path.is_empty());
            let last = path.last_mut().unwrap();
            if last == ".candy" {
                path.pop();
            } else {
                *last = last
                    .strip_suffix(".candy")
                    .expect("File name must end with `.candy`.")
                    .to_owned();
            }
        } else {
            for _ in 0..self.parent_navigations {
                if path.is_empty() {
                    return vec![];
                }
                path.pop();
            }
        }

        for part in &self.path {
            path.push(part.to_owned());
        }

        let mut result = vec![];

        let mut subdirectory = path.clone();
        subdirectory.push(".candy".to_owned());
        result.push(Input::File(subdirectory));

        if path.len() >= 1 {
            let last = path.last_mut().unwrap();
            *last = format!("{}.candy", last);
            result.push(Input::File(path));
        }
        result
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Fabian Schuiki

//! LLHD code generation for VHDL.

use moore_common::score::Result;
use score::*;
use konst::*;
use ty::*;
use num::Signed;
use hir;
use llhd;

/// Generates LLHD code.
pub trait Codegen<I,C> {
	fn codegen(&self, id: I, ctx: &mut C) -> Result<()>;
}

/// This macro implements the `Codegen` trait for a specific combination of
/// identifier and context types.
macro_rules! impl_codegen {
	($slf:tt, $id:ident: $id_ty:ty, $ctx:ident: &mut $ctx_ty:ty => $blk:block) => {
		impl<'sb, 'ast, 'ctx> Codegen<$id_ty, $ctx_ty> for ScoreContext<'sb, 'ast, 'ctx> {
			fn codegen(&$slf, $id: $id_ty, $ctx: &mut $ctx_ty) -> Result<()> $blk
		}
	}
}

impl<'sb, 'ast, 'ctx> ScoreContext<'sb, 'ast, 'ctx> {
	/// Map a VHDL type to the corresponding LLHD type.
	pub fn map_type(&self, ty: &Ty) -> Result<llhd::Type> {
		let ty = self.deref_named_type(ty)?;
		Ok(match *ty {
			Ty::Named(..) => unreachable!(),
			Ty::Null => llhd::void_ty(),
			Ty::Int(ref ty) => {
				let diff = match ty.dir {
					hir::Dir::To => &ty.right_bound - &ty.left_bound,
					hir::Dir::Downto => &ty.left_bound - &ty.right_bound,
				};
				if diff.is_negative() {
					llhd::void_ty()
				} else {
					llhd::int_ty(diff.bits())
				}
			}

			Ty::Enum(ref ty) => {
				let hir = self.hir(ty.decl)?;
				match hir.data {
					Some(hir::TypeData::Enum(_, ref lits)) => llhd::enum_ty(lits.len()),
					_ => unreachable!()
				}
			}

			// Unbounded integers cannot be mapped to LLHD. All cases where
			// such an int can leak through to codegen should actually be caught
			// beforehand in the type check.
			Ty::UnboundedInt => unreachable!(),
		})
	}

	/// Map a constant value to the LLHD counterpart.
	pub fn map_const(&self, konst: &Const) -> Result<llhd::ValueRef> {
		Ok(match *konst {
			// TODO: Map this to llhd::const_void once available.
			Const::Null => llhd::const_int(0, 0.into()),
			Const::Int(ref k) => llhd::const_int(999, k.value.clone()),
			Const::Enum(ref k) => {
				let size = match self.hir(k.decl)?.data {
					Some(hir::TypeData::Enum(_, ref lits)) => lits.len(),
					_ => unreachable!(),
				};
				llhd::const_int(size, k.index.into())
			}
			Const::Float(ref _k) => panic!("cannot map float constant"),
			Const::IntRange(_) | Const::FloatRange(_) => panic!("cannot map range constant"),
		}.into())
	}
}

impl_codegen!(self, id: DeclInBlockRef, ctx: &mut llhd::Entity => {
	match id {
		DeclInBlockRef::Pkg(_id)      => Ok(()),
		DeclInBlockRef::PkgInst(_id)  => Ok(()),
		DeclInBlockRef::Type(_id)     => Ok(()),
		DeclInBlockRef::Subtype(_id)  => Ok(()),
		DeclInBlockRef::Const(id)     => self.codegen(id, ctx),
		DeclInBlockRef::Signal(id)    => self.codegen(id, ctx),
		DeclInBlockRef::SharedVar(id) => self.codegen(id, ctx),
		DeclInBlockRef::File(id)      => self.codegen(id, ctx),
	}
});

impl_codegen!(self, _id: ConstDeclRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});

impl_codegen!(self, id: SignalDeclRef, ctx: &mut llhd::Entity => {
	// Determine the type of the signal.
	let hir = self.existing_hir(id)?;
	let ty = self.ty(id)?;

	// Calculate the initial value for the signal, either from the provided
	// expression or implicitly.
	let init = if let Some(init_id) = hir.init {
		self.const_value(init_id)?
	} else {
		self.default_value_for_type(&ty)?
	};

	println!("signal {:?}, type {:?}, init {:?}", id, ty, init);
	// Create the signal instance.
	let inst = llhd::Inst::new(
		Some(hir.name.value.into()),
		llhd::SignalInst(self.map_type(ty)?, Some(self.map_const(init)?))
	);
	ctx.add_inst(inst, llhd::InstPosition::End);
	Ok(())
});

impl_codegen!(self, _id: SharedVarDeclRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});

impl_codegen!(self, _id: FileDeclRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});

impl_codegen!(self, id: ConcStmtRef, ctx: &mut llhd::Entity => {
	match id {
		ConcStmtRef::Block(id)         => self.codegen(id, ctx),
		ConcStmtRef::Process(id)       => self.codegen(id, ctx),
		ConcStmtRef::ConcProcCall(id)  => self.codegen(id, ctx),
		ConcStmtRef::ConcAssert(id)    => self.codegen(id, ctx),
		ConcStmtRef::ConcSigAssign(id) => self.codegen(id, ctx),
		ConcStmtRef::CompInst(id)      => self.codegen(id, ctx),
		ConcStmtRef::ForGen(id)        => self.codegen(id, ctx),
		ConcStmtRef::IfGen(id)         => self.codegen(id, ctx),
		ConcStmtRef::CaseGen(id)       => self.codegen(id, ctx),
	}
});

impl_codegen!(self, _id: BlockStmtRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});

impl_codegen!(self, id: ProcessStmtRef, ctx: &mut llhd::Entity => {
	let hir = self.hir(id)?;
	let name = match hir.label {
		Some(n) => format!("{}_{}", ctx.name(), n.value),
		None => format!("{}_proc", ctx.name()),
	};
	println!("generating process `{}`", name);
	// TODO: Check which signals are actually read and written.
	let ty = llhd::entity_ty(vec![], vec![]);
	let prok = llhd::Process::new(name, ty.clone());
	// TODO: define the process as a local name
	// TOOD: codegen statements
	// TODO: codegen wait statements implied by sensitivity list
	let prok_ref = self.sb.llmod.borrow_mut().add_process(prok);
	// TODO: wire instantiation with signals in the process' port.
	ctx.add_inst(
		llhd::Inst::new(hir.label.map(|l| l.value.into()), llhd::InstKind::InstanceInst(
			ty, prok_ref.into(), vec![], vec![]
		)),
		llhd::InstPosition::End
	);
	Ok(())
});

impl_codegen!(self, _id: ConcProcCallStmtRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});

impl_codegen!(self, _id: ConcAssertStmtRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});

impl_codegen!(self, _id: ConcSigAssignStmtRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});

impl_codegen!(self, _id: CompInstStmtRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});

impl_codegen!(self, _id: ForGenStmtRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});

impl_codegen!(self, _id: IfGenStmtRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});

impl_codegen!(self, _id: CaseGenStmtRef, _ctx: &mut llhd::Entity => {
	unimplemented!();
});
<commit_msg>vhdl: add inst builder for codegen<commit_after>// Copyright (c) 2017 Fabian Schuiki

//! LLHD code generation for VHDL.

use moore_common::score::Result;
use moore_common::errors::*;
use score::*;
use konst::*;
use ty::*;
use num::Signed;
use hir;
use llhd;

/// Generates LLHD code.
pub trait Codegen<I,C> {
	fn codegen(&self, id: I, ctx: &mut C) -> Result<()>;
}

/// This macro implements the `Codegen` trait for a specific combination of
/// identifier and context types.
macro_rules! impl_codegen {
	($slf:tt, $id:ident: $id_ty:ty, $ctx:ident: &mut $ctx_ty:ty => $blk:block) => {
		impl<'sb, 'ast, 'ctx> Codegen<$id_ty, $ctx_ty> for ScoreContext<'sb, 'ast, 'ctx> {
			fn codegen(&$slf, $id: $id_ty, $ctx: &mut $ctx_ty) -> Result<()> $blk
		}
	};

	($slf:tt, $id:ident: $id_ty:ty, $ctx:ident: &$ctx_lt:tt mut $ctx_ty:ty => $blk:block) => {
		impl<'sb, 'ast, 'ctx, $ctx_lt> Codegen<$id_ty, $ctx_ty> for ScoreContext<'sb, 'ast, 'ctx> {
			fn codegen(&$slf, $id: $id_ty, $ctx: &mut $ctx_ty) -> Result<()> $blk
		}
	}
}

macro_rules! unimp {
	($slf:tt, $id:expr) => {{
		$slf.sess.emit(DiagBuilder2::bug(format!("code generation for {:?} not implemented", $id)));
		return Err(());
	}}
}

impl<'sb, 'ast, 'ctx> ScoreContext<'sb, 'ast, 'ctx> {
	/// Map a VHDL type to the corresponding LLHD type.
	pub fn map_type(&self, ty: &Ty) -> Result<llhd::Type> {
		let ty = self.deref_named_type(ty)?;
		Ok(match *ty {
			Ty::Named(..) => unreachable!(),
			Ty::Null => llhd::void_ty(),
			Ty::Int(ref ty) => {
				let diff = match ty.dir {
					hir::Dir::To => &ty.right_bound - &ty.left_bound,
					hir::Dir::Downto => &ty.left_bound - &ty.right_bound,
				};
				if diff.is_negative() {
					llhd::void_ty()
				} else {
					llhd::int_ty(diff.bits())
				}
			}

			Ty::Enum(ref ty) => {
				let hir = self.hir(ty.decl)?;
				match hir.data {
					Some(hir::TypeData::Enum(_, ref lits)) => llhd::enum_ty(lits.len()),
					_ => unreachable!()
				}
			}

			// Unbounded integers cannot be mapped to LLHD. All cases where
			// such an int can leak through to codegen should actually be caught
			// beforehand in the type check.
			Ty::UnboundedInt => unreachable!(),
		})
	}

	/// Map a constant value to the LLHD counterpart.
	pub fn map_const(&self, konst: &Const) -> Result<llhd::ValueRef> {
		Ok(match *konst {
			// TODO: Map this to llhd::const_void once available.
			Const::Null => llhd::const_int(0, 0.into()),
			Const::Int(ref k) => llhd::const_int(999, k.value.clone()),
			Const::Enum(ref k) => {
				let size = match self.hir(k.decl)?.data {
					Some(hir::TypeData::Enum(_, ref lits)) => lits.len(),
					_ => unreachable!(),
				};
				llhd::const_int(size, k.index.into())
			}
			Const::Float(ref _k) => panic!("cannot map float constant"),
			Const::IntRange(_) | Const::FloatRange(_) => panic!("cannot map range constant"),
		}.into())
	}
}

impl_codegen!(self, id: DeclInBlockRef, ctx: &mut llhd::Entity => {
	match id {
		DeclInBlockRef::Pkg(_id)      => Ok(()),
		DeclInBlockRef::PkgInst(_id)  => Ok(()),
		DeclInBlockRef::Type(_id)     => Ok(()),
		DeclInBlockRef::Subtype(_id)  => Ok(()),
		DeclInBlockRef::Const(id)     => self.codegen(id, ctx),
		DeclInBlockRef::Signal(id)    => self.codegen(id, ctx),
		DeclInBlockRef::SharedVar(id) => self.codegen(id, ctx),
		DeclInBlockRef::File(id)      => self.codegen(id, ctx),
	}
});

impl_codegen!(self, id: ConstDeclRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: SignalDeclRef, ctx: &mut llhd::Entity => {
	// Determine the type of the signal.
	let hir = self.existing_hir(id)?;
	let ty = self.ty(id)?;

	// Calculate the initial value for the signal, either from the provided
	// expression or implicitly.
	let init = if let Some(init_id) = hir.init {
		self.const_value(init_id)?
	} else {
		self.default_value_for_type(&ty)?
	};

	println!("signal {:?}, type {:?}, init {:?}", id, ty, init);
	// Create the signal instance.
	let inst = llhd::Inst::new(
		Some(hir.name.value.into()),
		llhd::SignalInst(self.map_type(ty)?, Some(self.map_const(init)?))
	);
	ctx.add_inst(inst, llhd::InstPosition::End);
	Ok(())
});

impl_codegen!(self, id: SharedVarDeclRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: FileDeclRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: ConcStmtRef, ctx: &mut llhd::Entity => {
	match id {
		ConcStmtRef::Block(id)         => self.codegen(id, ctx),
		ConcStmtRef::Process(id)       => self.codegen(id, ctx),
		ConcStmtRef::ConcProcCall(id)  => self.codegen(id, ctx),
		ConcStmtRef::ConcAssert(id)    => self.codegen(id, ctx),
		ConcStmtRef::ConcSigAssign(id) => self.codegen(id, ctx),
		ConcStmtRef::CompInst(id)      => self.codegen(id, ctx),
		ConcStmtRef::ForGen(id)        => self.codegen(id, ctx),
		ConcStmtRef::IfGen(id)         => self.codegen(id, ctx),
		ConcStmtRef::CaseGen(id)       => self.codegen(id, ctx),
	}
});

impl_codegen!(self, id: BlockStmtRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: ProcessStmtRef, ctx: &mut llhd::Entity => {
	let hir = self.hir(id)?;
	let name = match hir.label {
		Some(n) => format!("{}_{}", ctx.name(), n.value),
		None => format!("{}_proc", ctx.name()),
	};
	println!("generating process `{}`", name);
	// TODO: Check which signals are actually read and written.
	let ty = llhd::entity_ty(vec![], vec![]);
	let mut prok = llhd::Process::new(name, ty.clone());
	// TODO: define the process as a local name
	// TOOD: codegen declarations
	// TOOD: codegen statements
	{
		let body = prok.body_mut();
		let entry_blk = body.add_block(llhd::Block::new(Some("entry".into())), llhd::block::BlockPosition::End);
		let mut builder = InstBuilder::new(body, entry_blk);
		for &stmt in &hir.stmts {
			self.codegen(stmt, &mut builder)?;
		}
	}
	// TODO: codegen wait statements implied by sensitivity list
	let prok_ref = self.sb.llmod.borrow_mut().add_process(prok);
	// TODO: wire instantiation with signals in the process' port.
	ctx.add_inst(
		llhd::Inst::new(hir.label.map(|l| l.value.into()), llhd::InstKind::InstanceInst(
			ty, prok_ref.into(), vec![], vec![]
		)),
		llhd::InstPosition::End
	);
	Ok(())
});

impl_codegen!(self, id: ConcProcCallStmtRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: ConcAssertStmtRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: ConcSigAssignStmtRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: CompInstStmtRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: ForGenStmtRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: IfGenStmtRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: CaseGenStmtRef, _ctx: &mut llhd::Entity => {
	unimp!(self, id);
});

impl_codegen!(self, id: SeqStmtRef, _ctx: &'a mut InstBuilder<'a> => {
	unimp!(self, id);
});

/// An helper to build sequences of instructions.
pub struct InstBuilder<'ctx> {
	pub body: &'ctx mut llhd::seq_body::SeqBody,
	pub block: llhd::value::BlockRef,
}

impl<'ctx> InstBuilder<'ctx> {
	/// Create a new instruction builder.
	pub fn new(body: &'ctx mut llhd::seq_body::SeqBody, block: llhd::value::BlockRef) -> InstBuilder<'ctx> {
		InstBuilder {
			body: body,
			block: block,
		}
	}

	/// Add a new instruction.
	pub fn add_inst(&mut self, inst: llhd::Inst) -> llhd::value::InstRef {
		self.body.add_inst(inst, llhd::InstPosition::BlockEnd(self.block))
	}

	/// Add a new block.
	pub fn add_block(&mut self, block: llhd::block::Block) -> llhd::value::BlockRef {
		self.body.add_block(block, llhd::block::BlockPosition::After(self.block))
	}

	/// Change the block at the end of which instructions will be added.
	pub fn set_block(&mut self, block: llhd::value::BlockRef) {
		self.block = block
	}
}
<|endoftext|>


<commit_before><commit_msg>Move comments.<commit_after><|endoftext|>


<commit_before>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
// #![feature(type_ascription)]
// #![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![feature(linkage)]
#![feature(drop_types_in_const)]
#![feature(unboxed_closures)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

extern crate util;

pub use util::*;
use util::unwind_hack::{unw_regnum_t};
use util::llvm_stackmaps::LocationVariant;

use elf::Section;

use std::intrinsics;

const DEMO_ID: i64 = 0;
const SUBCALL1_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

#[no_mangle]
pub fn subcall_1(data: *mut u8) {
    println!("Enter `subcall_1`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL1_ID, 0, subcall_2, data);
        // intrinsics::patchpoint_call(SUBCALL1_ID, 13, subcall_2, data);
    }
    println!("Finis `subcall_1`");
}

#[linkage="external"]
fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
        // intrinsics::patchpoint_call(SUBCALL2_ID, 13, subcall_3, data);

    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

trait StackMapExt {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo;
}

impl StackMapExt for StackMap {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        debug!("");
        debug!("addr: {:?}", addr);

	if let Some(_base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                debug!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

#[no_mangle]
pub fn subcall_3(_data: *mut u8) {
    println!("Start `subcall_3`");

    let map = unsafe { STACK_MAP.get() };
    println!("map:                              {:?}", map);
    unsafe {
        for i in 0..ADDRESS_IDS.len() {
            println!("ADDRESS_IDS[i] 0x{:x}", ADDRESS_IDS[i]);
        }
    }

    let unw = unwind_hack::UnwindContext::new();
    let mut cursor = Some(unw.cursor());

    while let Some(c) = cursor {
        let ip = c.get_reg(unwind_hack::UNW_REG_IP).unwrap();
        let sp = c.get_reg(unwind_hack::UNW_REG_SP).unwrap();
        debug!("ip: 0x{:x} sp: 0x{:x}", ip, sp);
        let opt_fbase = backtrace_hack::dlinfo_fbase(ip as *const libc::c_void);
        debug!("dlinfo_fbase: {:?}", opt_fbase);
        if let Some(fbase) = opt_fbase {
            debug!("dlrel ip: 0x{:x}", ip - (fbase as u64));
        }

        let (offset, name) = {
            let mut buf = Vec::with_capacity(256);
            match c.get_proc_name(&mut buf) {
                Err(e) => {
                    println!("failed to .get_proc_name from subcall_3: {:?}", e);
                    cursor = c.step().unwrap();
                    println!("");
                    continue;
                }
                Ok(offset) => (offset, String::from_utf8(buf).unwrap()),
            }
        };
        debug!("ip: 0x{:08x} name: {} offset: {}", ip, name, offset);
        debug!("start of fn:  0x{:08x}", ip - offset);
        if let Some(fbase) = opt_fbase {
            debug!("rel start of fn:  0x{:08x}", ip - offset - (fbase as u64));
        }
        for (i, rec) in map.records().iter().enumerate() {
            if address_id(rec.patchpoint_id()) == Some((ip - offset) as usize) &&
                rec.instruction_offset() as u64 == offset
            {
                println!("found match at ({}) for `{}`: {:?}", i, name, rec);
                for (j, loc) in rec.locations().iter().enumerate() {
                    let loc_interpreted: i64 = match *loc.variant() {
                        LocationVariant::Register { dwarf_regnum } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64
                        }
                        LocationVariant::Direct { dwarf_regnum, offset } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 + offset as i64
                        }
                        LocationVariant::Indirect { dwarf_regnum, offset } => {
                            unsafe {
                                *((c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 +
                                   offset as i64)
                                  as usize as *const usize) as i64
                            }
                        }
                        LocationVariant::Constant { value } => {
                            value as i64
                        }
                        LocationVariant::ConstIndex { offset } => {
                            unimplemented!()
                        }
                    };
                    println!("rec[{}].loc[{}] {:?} => 0x{:x}",
                             i, j, loc, loc_interpreted);
                }
            }
        }

        cursor = c.step().unwrap();
        println!("");
    }
    println!("Finis `subcall_3`");
}

#[cfg(use_backtrace_hack)]
fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

#[derive(Debug)]
pub struct FnPtrData(i64, *const libc::c_void);

impl FnPtrData {
    const fn new<T, F>(id: i64, f: *const F) -> Self where F: Fn<T> {
        FnPtrData(id, f as *const libc::c_void)
    }
}

unsafe impl Sync for FnPtrData { }

#[link_section = ".fn_id_data"]
pub static DEMO_ID_DATA: FnPtrData = FnPtrData::new(DEMO_ID, &demo);

#[link_section = ".fn_id_data"]
pub static SUBCALL1_ID_DATA: FnPtrData = FnPtrData::new(SUBCALL1_ID, &subcall_1);

#[link_section = ".fn_id_data"]
pub static SUBCALL2_ID_DATA: FnPtrData = FnPtrData::new(SUBCALL2_ID, &subcall_2);

fn my_binary() -> Result<elf::File, elf::ParseError> {
    use std::path::Path;
    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    elf::File::open_path(&path)
}

fn my_section<'a>(file: &'a elf::File, section_name: &str) -> Result<&'a Section, DemoError> {
    let name = section_name.to_string();
    file.get_section(name.clone())
        .ok_or_else(|| DemoError::MissingSection(name))
}

fn fn_ids(file: &elf::File) -> Result<&[FnPtrData], DemoError> {
    Ok(unsafe { ::std::mem::transmute(&my_section(file, ".fn_id_data")?.data[..]) })
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL1_ID as usize] = subcall_1 as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    let file = my_binary()?;
    let fn_id_data = fn_ids(&file)?;
    println!("fn_id_data section: {:?}", fn_id_data);
    unsafe {
        println!("ADDRESS_IDS: 0x{:x} 0x{:x} 0x{:x}", ADDRESS_IDS[0], ADDRESS_IDS[1], ADDRESS_IDS[2]);
    }

    let stackmap_section = my_section(&file, ".llvm_stackmaps")?;
    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall_1, data.as_mut_ptr());
        // intrinsics::patchpoint_call(DEMO_ID, 13, subcall_1, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<commit_msg>sidestep warning in foo.rs<commit_after>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
// #![feature(type_ascription)]
// #![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![feature(linkage)]
#![feature(drop_types_in_const)]
#![feature(unboxed_closures)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

extern crate util;

pub use util::*;
use util::unwind_hack::{unw_regnum_t};
use util::llvm_stackmaps::LocationVariant;

use elf::Section;

use std::intrinsics;

const DEMO_ID: i64 = 0;
const SUBCALL1_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

#[no_mangle]
pub fn subcall_1(data: *mut u8) {
    println!("Enter `subcall_1`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL1_ID, 0, subcall_2, data);
        // intrinsics::patchpoint_call(SUBCALL1_ID, 13, subcall_2, data);
    }
    println!("Finis `subcall_1`");
}

#[linkage="external"]
fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
        // intrinsics::patchpoint_call(SUBCALL2_ID, 13, subcall_3, data);

    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

trait StackMapExt {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo;
}

impl StackMapExt for StackMap {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        debug!("");
        debug!("addr: {:?}", addr);

	if let Some(_base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                debug!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

#[no_mangle]
pub fn subcall_3(_data: *mut u8) {
    println!("Start `subcall_3`");

    let map = unsafe { STACK_MAP.get() };
    println!("map:                              {:?}", map);
    unsafe {
        for i in 0..ADDRESS_IDS.len() {
            println!("ADDRESS_IDS[i] 0x{:x}", ADDRESS_IDS[i]);
        }
    }

    let unw = unwind_hack::UnwindContext::new();
    let mut cursor = Some(unw.cursor());

    while let Some(c) = cursor {
        let ip = c.get_reg(unwind_hack::UNW_REG_IP).unwrap();
        let sp = c.get_reg(unwind_hack::UNW_REG_SP).unwrap();
        debug!("ip: 0x{:x} sp: 0x{:x}", ip, sp);
        let opt_fbase = backtrace_hack::dlinfo_fbase(ip as *const libc::c_void);
        debug!("dlinfo_fbase: {:?}", opt_fbase);
        if let Some(fbase) = opt_fbase {
            debug!("dlrel ip: 0x{:x}", ip - (fbase as u64));
        }

        let (offset, name) = {
            let mut buf = Vec::with_capacity(256);
            match c.get_proc_name(&mut buf) {
                Err(e) => {
                    println!("failed to .get_proc_name from subcall_3: {:?}", e);
                    cursor = c.step().unwrap();
                    println!("");
                    continue;
                }
                Ok(offset) => (offset, String::from_utf8(buf).unwrap()),
            }
        };
        debug!("ip: 0x{:08x} name: {} offset: {}", ip, name, offset);
        debug!("start of fn:  0x{:08x}", ip - offset);
        if let Some(fbase) = opt_fbase {
            debug!("rel start of fn:  0x{:08x}", ip - offset - (fbase as u64));
        }
        for (i, rec) in map.records().iter().enumerate() {
            if address_id(rec.patchpoint_id()) == Some((ip - offset) as usize) &&
                rec.instruction_offset() as u64 == offset
            {
                println!("found match at ({}) for `{}`: {:?}", i, name, rec);
                for (j, loc) in rec.locations().iter().enumerate() {
                    let loc_interpreted: i64 = match *loc.variant() {
                        LocationVariant::Register { dwarf_regnum } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64
                        }
                        LocationVariant::Direct { dwarf_regnum, offset } => {
                            c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 + offset as i64
                        }
                        LocationVariant::Indirect { dwarf_regnum, offset } => {
                            unsafe {
                                *((c.get_reg(dwarf_regnum as unw_regnum_t).unwrap() as i64 +
                                   offset as i64)
                                  as usize as *const usize) as i64
                            }
                        }
                        LocationVariant::Constant { value } => {
                            value as i64
                        }
                        LocationVariant::ConstIndex { offset: _ } => {
                            unimplemented!()
                        }
                    };
                    println!("rec[{}].loc[{}] {:?} => 0x{:x}",
                             i, j, loc, loc_interpreted);
                }
            }
        }

        cursor = c.step().unwrap();
        println!("");
    }
    println!("Finis `subcall_3`");
}

#[cfg(use_backtrace_hack)]
fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

#[derive(Debug)]
pub struct FnPtrData(i64, *const libc::c_void);

impl FnPtrData {
    const fn new<T, F>(id: i64, f: *const F) -> Self where F: Fn<T> {
        FnPtrData(id, f as *const libc::c_void)
    }
}

unsafe impl Sync for FnPtrData { }

#[link_section = ".fn_id_data"]
pub static DEMO_ID_DATA: FnPtrData = FnPtrData::new(DEMO_ID, &demo);

#[link_section = ".fn_id_data"]
pub static SUBCALL1_ID_DATA: FnPtrData = FnPtrData::new(SUBCALL1_ID, &subcall_1);

#[link_section = ".fn_id_data"]
pub static SUBCALL2_ID_DATA: FnPtrData = FnPtrData::new(SUBCALL2_ID, &subcall_2);

fn my_binary() -> Result<elf::File, elf::ParseError> {
    use std::path::Path;
    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    elf::File::open_path(&path)
}

fn my_section<'a>(file: &'a elf::File, section_name: &str) -> Result<&'a Section, DemoError> {
    let name = section_name.to_string();
    file.get_section(name.clone())
        .ok_or_else(|| DemoError::MissingSection(name))
}

fn fn_ids(file: &elf::File) -> Result<&[FnPtrData], DemoError> {
    Ok(unsafe { ::std::mem::transmute(&my_section(file, ".fn_id_data")?.data[..]) })
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL1_ID as usize] = subcall_1 as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    let file = my_binary()?;
    let fn_id_data = fn_ids(&file)?;
    println!("fn_id_data section: {:?}", fn_id_data);
    unsafe {
        println!("ADDRESS_IDS: 0x{:x} 0x{:x} 0x{:x}", ADDRESS_IDS[0], ADDRESS_IDS[1], ADDRESS_IDS[2]);
    }

    let stackmap_section = my_section(&file, ".llvm_stackmaps")?;
    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall_1, data.as_mut_ptr());
        // intrinsics::patchpoint_call(DEMO_ID, 13, subcall_1, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<|endoftext|>


<commit_before>use winapi;

use self::winapi::shared::windef::POINT;
use self::winapi::ctypes::c_int;
use self::winapi::um::winuser::*;

use crate::win::keycodes::*;
use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};
use std::mem::*;

/// The main struct for handling the event emitting
#[derive(Default)]
pub struct Enigo;

fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) {
    let mut input = INPUT {
        type_: INPUT_MOUSE,
        u: unsafe {
            transmute(MOUSEINPUT {
                dx,
                dy,
                mouseData: data,
                dwFlags: flags,
                time: 0,
                dwExtraInfo: 0,
            })
        },
    };
    unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
}

fn keybd_event(flags: u32, vk: u16, scan: u16) {
    let mut input = INPUT {
        type_: INPUT_KEYBOARD,
        u: unsafe {
            transmute_copy(&KEYBDINPUT {
                wVk: vk,
                wScan: scan,
                dwFlags: flags,
                time: 0,
                dwExtraInfo: 0,
            })
        },
    };
    unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
}

impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        mouse_event(
            MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE,
            0,
            x * 65335 / unsafe { GetSystemMetrics(78) },
            y * 65335 / unsafe { GetSystemMetrics(79) },
        );
    }

    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        mouse_event(MOUSEEVENTF_MOVE, 0, x, y);
    }

    fn mouse_down(&mut self, button: MouseButton) {
        mouse_event(
            match button {
                MouseButton::Left => MOUSEEVENTF_LEFTDOWN,
                MouseButton::Middle => MOUSEEVENTF_MIDDLEDOWN,
                MouseButton::Right => MOUSEEVENTF_RIGHTDOWN,
                _ => unimplemented!(),
            },
            0,
            0,
            0,
        );
    }

    fn mouse_up(&mut self, button: MouseButton) {
        mouse_event(
            match button {
                MouseButton::Left => MOUSEEVENTF_LEFTUP,
                MouseButton::Middle => MOUSEEVENTF_MIDDLEUP,
                MouseButton::Right => MOUSEEVENTF_RIGHTUP,
                _ => unimplemented!(),
            },
            0,
            0,
            0,
        );
    }

    fn mouse_click(&mut self, button: MouseButton) {
        self.mouse_down(button);
        self.mouse_up(button);
    }

    fn mouse_scroll_x(&mut self, length: i32) {
        mouse_event(MOUSEEVENTF_HWHEEL, unsafe { transmute(length * 120) }, 0, 0);
    }

    fn mouse_scroll_y(&mut self, length: i32) {
        mouse_event(MOUSEEVENTF_WHEEL, unsafe { transmute(length * 120) }, 0, 0);
    }
}

impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let mut buffer = [0; 2];

        for c in sequence.chars() {
            // Windows uses uft-16 encoding. We need to check
            // for variable length characters. As such some
            // characters can be 32 bit long and those are
            // encoded in such called hight and low surrogates
            // each 16 bit wide that needs to be send after
            // another to the SendInput function without
            // being interrupted by "keyup"
            let result = c.encode_utf16(&mut buffer);
            if result.len() == 1 {
                self.unicode_key_click(result[0]);
            } else {
                for utf16_surrogate in result {
                    self.unicode_key_down(utf16_surrogate.clone());
                }
                // do i need to produce a keyup?
                // self.unicode_key_up(0);
            }
        }
    }

    fn key_click(&mut self, key: Key) {
        let scancode = self.key_to_scancode(key);
        use std::{thread, time};
        keybd_event(KEYEVENTF_SCANCODE, 0, scancode);
        thread::sleep(time::Duration::from_millis(20));
        keybd_event(KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE, 0, scancode);
    }

    fn key_down(&mut self, key: Key) {
        keybd_event(KEYEVENTF_SCANCODE, 0, self.key_to_scancode(key));
    }

    fn key_up(&mut self, key: Key) {
        keybd_event(
            KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE,
            0,
            self.key_to_scancode(key),
        );
    }
}

impl Enigo {
    /// Gets the (width, height) of the main display in screen coordinates (pixels).
    ///
    /// # Example
    ///
    /// ```no_run
    /// use enigo::*;
    /// let mut size = Enigo::main_display_size();
    /// ```
    pub fn main_display_size() -> (usize, usize) {
      let w = unsafe { GetSystemMetrics(SM_CXSCREEN) as usize };
      let h = unsafe { GetSystemMetrics(SM_CYSCREEN) as usize };
      (w, h)
    }

    /// Gets the location of mouse in screen coordinates (pixels).
    ///
    /// # Example
    ///
    /// ```no_run
    /// use enigo::*;
    /// let mut location = Enigo::mouse_location();
    /// ```
    pub fn mouse_location() -> (i32, i32) {
        let mut point = POINT { x: 0, y: 0 };
        let result = unsafe { GetCursorPos(&mut point) };
        if result != 0 {
          (point.x, point.y)
        } else {
          (0, 0)
        }
    }

    fn unicode_key_click(&self, unicode_char: u16) {
        use std::{thread, time};
        self.unicode_key_down(unicode_char);
        thread::sleep(time::Duration::from_millis(20));
        self.unicode_key_up(unicode_char);
    }

    fn unicode_key_down(&self, unicode_char: u16) {
        keybd_event(KEYEVENTF_UNICODE, 0, unicode_char);
    }

    fn unicode_key_up(&self, unicode_char: u16) {
        keybd_event(KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, 0, unicode_char);
    }

    fn key_to_keycode(&self, key: Key) -> u16 {
        // do not use the codes from crate winapi they're
        // wrongly typed with i32 instead of i16 use the
        // ones provided by win/keycodes.rs that are prefixed
        // with an 'E' infront of the original name
        #[allow(deprecated)]
        // I mean duh, we still need to support deprecated keys until they're removed
        match key {
            Key::Alt => EVK_MENU,
            Key::Backspace => EVK_BACK,
            Key::CapsLock => EVK_CAPITAL,
            Key::Control => EVK_LCONTROL,
            Key::Delete => EVK_DELETE,
            Key::DownArrow => EVK_DOWN,
            Key::End => EVK_END,
            Key::Escape => EVK_ESCAPE,
            Key::F1 => EVK_F1,
            Key::F10 => EVK_F10,
            Key::F11 => EVK_F11,
            Key::F12 => EVK_F12,
            Key::F2 => EVK_F2,
            Key::F3 => EVK_F3,
            Key::F4 => EVK_F4,
            Key::F5 => EVK_F5,
            Key::F6 => EVK_F6,
            Key::F7 => EVK_F7,
            Key::F8 => EVK_F8,
            Key::F9 => EVK_F9,
            Key::Home => EVK_HOME,
            Key::LeftArrow => EVK_LEFT,
            Key::Option => EVK_MENU,
            Key::PageDown => EVK_NEXT,
            Key::PageUp => EVK_PRIOR,
            Key::Return => EVK_RETURN,
            Key::RightArrow => EVK_RIGHT,
            Key::Shift => EVK_SHIFT,
            Key::Space => EVK_SPACE,
            Key::Tab => EVK_TAB,
            Key::UpArrow => EVK_UP,

            Key::Raw(raw_keycode) => raw_keycode,
            Key::Layout(c) => self.get_layoutdependent_keycode(c.to_string()),
            //_ => 0,
            Key::Super | Key::Command | Key::Windows | Key::Meta => EVK_LWIN,
        }
    }

    fn key_to_scancode(&self, key: Key) -> u16 {
        let keycode = self.key_to_keycode(key);
        unsafe { MapVirtualKeyW(keycode as u32, 0) as u16 }
    }

    fn get_layoutdependent_keycode(&self, string: String) -> u16 {
        let mut buffer = [0; 2];
        // get the first char from the string ignore the rest
        // ensure its not a multybyte char
        let utf16 = string
            .chars()
            .nth(0)
            .expect("no valid input") //TODO(dustin): no panic here make an error
            .encode_utf16(&mut buffer);
        if utf16.len() != 1 {
            // TODO(dustin) don't panic here use an apropriate errors
            panic!("this char is not allowd");
        }
        // NOTE VkKeyScanW uses the current keyboard layout
        // to specify a layout use VkKeyScanExW and GetKeyboardLayout
        // or load one with LoadKeyboardLayoutW
        let keycode_and_shiftstate = unsafe { VkKeyScanW(utf16[0]) };
        // 0x41 as u16 //key that has the letter 'a' on it on english like keylayout
        keycode_and_shiftstate as u16
    }
}
<commit_msg>Fix move_mouse_to on windows<commit_after>use winapi;

use self::winapi::shared::windef::POINT;
use self::winapi::ctypes::c_int;
use self::winapi::um::winuser::*;

use crate::win::keycodes::*;
use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};
use std::mem::*;

/// The main struct for handling the event emitting
#[derive(Default)]
pub struct Enigo;

fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) {
    let mut input = INPUT {
        type_: INPUT_MOUSE,
        u: unsafe {
            transmute(MOUSEINPUT {
                dx,
                dy,
                mouseData: data,
                dwFlags: flags,
                time: 0,
                dwExtraInfo: 0,
            })
        },
    };
    unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
}

fn keybd_event(flags: u32, vk: u16, scan: u16) {
    let mut input = INPUT {
        type_: INPUT_KEYBOARD,
        u: unsafe {
            transmute_copy(&KEYBDINPUT {
                wVk: vk,
                wScan: scan,
                dwFlags: flags,
                time: 0,
                dwExtraInfo: 0,
            })
        },
    };
    unsafe { SendInput(1, &mut input as LPINPUT, size_of::<INPUT>() as c_int) };
}

impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        mouse_event(
            MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK,
            0,
            (x - unsafe { GetSystemMetrics(SM_XVIRTUALSCREEN) }) * 65535 / unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) },
            (y - unsafe { GetSystemMetrics(SM_YVIRTUALSCREEN) }) * 65535 / unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) },
        );
    }

    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        mouse_event(MOUSEEVENTF_MOVE, 0, x, y);
    }

    fn mouse_down(&mut self, button: MouseButton) {
        mouse_event(
            match button {
                MouseButton::Left => MOUSEEVENTF_LEFTDOWN,
                MouseButton::Middle => MOUSEEVENTF_MIDDLEDOWN,
                MouseButton::Right => MOUSEEVENTF_RIGHTDOWN,
                _ => unimplemented!(),
            },
            0,
            0,
            0,
        );
    }

    fn mouse_up(&mut self, button: MouseButton) {
        mouse_event(
            match button {
                MouseButton::Left => MOUSEEVENTF_LEFTUP,
                MouseButton::Middle => MOUSEEVENTF_MIDDLEUP,
                MouseButton::Right => MOUSEEVENTF_RIGHTUP,
                _ => unimplemented!(),
            },
            0,
            0,
            0,
        );
    }

    fn mouse_click(&mut self, button: MouseButton) {
        self.mouse_down(button);
        self.mouse_up(button);
    }

    fn mouse_scroll_x(&mut self, length: i32) {
        mouse_event(MOUSEEVENTF_HWHEEL, unsafe { transmute(length * 120) }, 0, 0);
    }

    fn mouse_scroll_y(&mut self, length: i32) {
        mouse_event(MOUSEEVENTF_WHEEL, unsafe { transmute(length * 120) }, 0, 0);
    }
}

impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let mut buffer = [0; 2];

        for c in sequence.chars() {
            // Windows uses uft-16 encoding. We need to check
            // for variable length characters. As such some
            // characters can be 32 bit long and those are
            // encoded in such called hight and low surrogates
            // each 16 bit wide that needs to be send after
            // another to the SendInput function without
            // being interrupted by "keyup"
            let result = c.encode_utf16(&mut buffer);
            if result.len() == 1 {
                self.unicode_key_click(result[0]);
            } else {
                for utf16_surrogate in result {
                    self.unicode_key_down(utf16_surrogate.clone());
                }
                // do i need to produce a keyup?
                // self.unicode_key_up(0);
            }
        }
    }

    fn key_click(&mut self, key: Key) {
        let scancode = self.key_to_scancode(key);
        use std::{thread, time};
        keybd_event(KEYEVENTF_SCANCODE, 0, scancode);
        thread::sleep(time::Duration::from_millis(20));
        keybd_event(KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE, 0, scancode);
    }

    fn key_down(&mut self, key: Key) {
        keybd_event(KEYEVENTF_SCANCODE, 0, self.key_to_scancode(key));
    }

    fn key_up(&mut self, key: Key) {
        keybd_event(
            KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE,
            0,
            self.key_to_scancode(key),
        );
    }
}

impl Enigo {
    /// Gets the (width, height) of the main display in screen coordinates (pixels).
    ///
    /// # Example
    ///
    /// ```no_run
    /// use enigo::*;
    /// let mut size = Enigo::main_display_size();
    /// ```
    pub fn main_display_size() -> (usize, usize) {
      let w = unsafe { GetSystemMetrics(SM_CXSCREEN) as usize };
      let h = unsafe { GetSystemMetrics(SM_CYSCREEN) as usize };
      (w, h)
    }

    /// Gets the location of mouse in screen coordinates (pixels).
    ///
    /// # Example
    ///
    /// ```no_run
    /// use enigo::*;
    /// let mut location = Enigo::mouse_location();
    /// ```
    pub fn mouse_location() -> (i32, i32) {
        let mut point = POINT { x: 0, y: 0 };
        let result = unsafe { GetCursorPos(&mut point) };
        if result != 0 {
          (point.x, point.y)
        } else {
          (0, 0)
        }
    }

    fn unicode_key_click(&self, unicode_char: u16) {
        use std::{thread, time};
        self.unicode_key_down(unicode_char);
        thread::sleep(time::Duration::from_millis(20));
        self.unicode_key_up(unicode_char);
    }

    fn unicode_key_down(&self, unicode_char: u16) {
        keybd_event(KEYEVENTF_UNICODE, 0, unicode_char);
    }

    fn unicode_key_up(&self, unicode_char: u16) {
        keybd_event(KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, 0, unicode_char);
    }

    fn key_to_keycode(&self, key: Key) -> u16 {
        // do not use the codes from crate winapi they're
        // wrongly typed with i32 instead of i16 use the
        // ones provided by win/keycodes.rs that are prefixed
        // with an 'E' infront of the original name
        #[allow(deprecated)]
        // I mean duh, we still need to support deprecated keys until they're removed
        match key {
            Key::Alt => EVK_MENU,
            Key::Backspace => EVK_BACK,
            Key::CapsLock => EVK_CAPITAL,
            Key::Control => EVK_LCONTROL,
            Key::Delete => EVK_DELETE,
            Key::DownArrow => EVK_DOWN,
            Key::End => EVK_END,
            Key::Escape => EVK_ESCAPE,
            Key::F1 => EVK_F1,
            Key::F10 => EVK_F10,
            Key::F11 => EVK_F11,
            Key::F12 => EVK_F12,
            Key::F2 => EVK_F2,
            Key::F3 => EVK_F3,
            Key::F4 => EVK_F4,
            Key::F5 => EVK_F5,
            Key::F6 => EVK_F6,
            Key::F7 => EVK_F7,
            Key::F8 => EVK_F8,
            Key::F9 => EVK_F9,
            Key::Home => EVK_HOME,
            Key::LeftArrow => EVK_LEFT,
            Key::Option => EVK_MENU,
            Key::PageDown => EVK_NEXT,
            Key::PageUp => EVK_PRIOR,
            Key::Return => EVK_RETURN,
            Key::RightArrow => EVK_RIGHT,
            Key::Shift => EVK_SHIFT,
            Key::Space => EVK_SPACE,
            Key::Tab => EVK_TAB,
            Key::UpArrow => EVK_UP,

            Key::Raw(raw_keycode) => raw_keycode,
            Key::Layout(c) => self.get_layoutdependent_keycode(c.to_string()),
            //_ => 0,
            Key::Super | Key::Command | Key::Windows | Key::Meta => EVK_LWIN,
        }
    }

    fn key_to_scancode(&self, key: Key) -> u16 {
        let keycode = self.key_to_keycode(key);
        unsafe { MapVirtualKeyW(keycode as u32, 0) as u16 }
    }

    fn get_layoutdependent_keycode(&self, string: String) -> u16 {
        let mut buffer = [0; 2];
        // get the first char from the string ignore the rest
        // ensure its not a multybyte char
        let utf16 = string
            .chars()
            .nth(0)
            .expect("no valid input") //TODO(dustin): no panic here make an error
            .encode_utf16(&mut buffer);
        if utf16.len() != 1 {
            // TODO(dustin) don't panic here use an apropriate errors
            panic!("this char is not allowd");
        }
        // NOTE VkKeyScanW uses the current keyboard layout
        // to specify a layout use VkKeyScanExW and GetKeyboardLayout
        // or load one with LoadKeyboardLayoutW
        let keycode_and_shiftstate = unsafe { VkKeyScanW(utf16[0]) };
        // 0x41 as u16 //key that has the letter 'a' on it on english like keylayout
        keycode_and_shiftstate as u16
    }
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use rand::distributions::{Distribution, Uniform};
use rand::rngs::SmallRng;
use rand::{thread_rng, SeedableRng};
use std::cmp::{max, min};

use crate::miller_rabin::Result::*;
use crate::numeric::*;
use crate::{miller_rabin, Factors};

fn find_divisor<A: Arithmetic>(n: A) -> u64 {
    #![allow(clippy::many_single_char_names)]
    let mut rand = {
        let range = Uniform::new(1, n.modulus());
        let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
        move || n.from_u64(range.sample(&mut rng))
    };

    let quadratic = |a, b| move |x| n.add(n.mul(a, n.mul(x, x)), b);

    loop {
        let f = quadratic(rand(), rand());
        let mut x = rand();
        let mut y = x;

        loop {
            x = f(x);
            y = f(f(y));
            let d = {
                let _x = n.to_u64(x);
                let _y = n.to_u64(y);
                gcd(n.modulus(), max(_x, _y) - min(_x, _y))
            };
            if d == n.modulus() {
                // Failure, retry with a different quadratic
                break;
            } else if d > 1 {
                return d;
            }
        }
    }
}

fn _factor<A: Arithmetic>(mut num: u64) -> Factors {
    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
    let _factor = |n| {
        // TODO: Optimise with 32 and 64b versions
        _factor::<A>(n)
    };

    let mut factors = Factors::new();
    if num == 1 {
        return factors;
    }

    let n = A::new(num);
    match miller_rabin::test::<A>(n) {
        Prime => {
            factors.push(num);
            return factors;
        }

        Composite(d) => {
            num /= d;
            factors *= _factor(d)
        }

        Pseudoprime => {}
    };

    let divisor = find_divisor::<A>(n);
    factors *= _factor(divisor);
    factors *= _factor(num / divisor);
    factors
}

pub(crate) fn factor(n: u64) -> Factors {
    _factor::<Montgomery>(n)
}
<commit_msg>factor::rho: Fix very-unlikely bug (resulting in assertion failure)<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use rand::distributions::{Distribution, Uniform};
use rand::rngs::SmallRng;
use rand::{thread_rng, SeedableRng};
use std::cmp::{max, min};

use crate::miller_rabin::Result::*;
use crate::numeric::*;
use crate::{miller_rabin, Factors};

fn find_divisor<A: Arithmetic>(n: A) -> u64 {
    #![allow(clippy::many_single_char_names)]
    let mut rand = {
        let range = Uniform::new(1, n.modulus());
        let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
        move || n.from_u64(range.sample(&mut rng))
    };

    let quadratic = |a, b| move |x| n.add(n.mul(a, n.mul(x, x)), b);

    loop {
        let f = quadratic(rand(), rand());
        let mut x = rand();
        let mut y = x;

        loop {
            x = f(x);
            y = f(f(y));
            let d = {
                let _x = n.to_u64(x);
                let _y = n.to_u64(y);
                gcd(n.modulus(), max(_x, _y) - min(_x, _y))
            };
            if d == n.modulus() {
                // Failure, retry with a different quadratic
                break;
            } else if d > 1 {
                return d;
            }
        }
    }
}

fn _factor<A: Arithmetic>(num: u64) -> Factors {
    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
    let _factor = |n| {
        // TODO: Optimise with 32 and 64b versions
        _factor::<A>(n)
    };

    let mut factors = Factors::new();
    if num == 1 {
        return factors;
    }

    let n = A::new(num);
    let divisor;
    match miller_rabin::test::<A>(n) {
        Prime => {
            factors.push(num);
            return factors;
        }

        Composite(d) => {
            divisor = d;
        }

        Pseudoprime => {
            divisor = find_divisor::<A>(n);
        }
    };

    factors *= _factor(divisor);
    factors *= _factor(num / divisor);
    factors
}

pub(crate) fn factor(n: u64) -> Factors {
    _factor::<Montgomery>(n)
}
<|endoftext|>