<commit_before>
use std::fs::File;
use std::io::Read;
use std::str::FromStr;

#[derive(Debug,PartialEq,Eq,Clone,Copy)]
enum Register {
    A = 0,
    B = 1,
    C = 2,
    D = 3,
}
impl FromStr for Register {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Register, &'static str> {
        match s {
            "a" => Ok(Register::A),
            "b" => Ok(Register::B),
            "c" => Ok(Register::C),
            "d" => Ok(Register::D),
            _ => Err("Unknown register string"),
        }
    }
}

// -----------------------------------------------------------------------------

#[derive(Debug,PartialEq,Eq,Clone,Copy)]
enum Source {
    Reg (Register),
    Val (i32),
}
impl FromStr for Source {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Source, &'static str> {

        //s.parse::<Register>().or_else(Source::Val(s.parse::<i32>())?)

        if let Ok(reg) = s.parse::<Register>() {
            Ok(Source::Reg(reg))
        } else {
            s.parse::<i32>().map(|i| Source::Val(i))
                .map_err(|_| "Failed to parse int")
        }
    }
}

// -----------------------------------------------------------------------------

// cpy x y copies x (either an integer or the value of a register) into register y.
// inc x increases the value of register x by one.
// dec x decreases the value of register x by one.
// jnz x y jumps to an instruction y away (positive means forward; negative means backward),
//      but only if x is not zero.
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
enum Instruction {
    Cpy {src: Source, dst: Register},
    Inc {dst: Register},
    Dec {dst: Register},
    Jnz {src: Source, offset: i32},
}
impl FromStr for Instruction {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Instruction, &'static str> {
        let tokens: Vec<_> = s.split(' ').collect();
        match tokens[0] {
            "cpy" => Ok(Instruction::Cpy{ src: tokens[1].parse()?, dst: tokens[2].parse()? }),
            "inc" => Ok(Instruction::Inc{dst: tokens[1].parse()?}),
            "dec" => Ok(Instruction::Dec{dst: tokens[1].parse()?}),
            "jnz" => Ok(Instruction::Jnz{
                src: tokens[1].parse()?,
                offset: tokens[2].parse().expect("Failed to parse int")
            }),
            _ => Err("Unable to parse instruction"),
        }
    }
}

// -----------------------------------------------------------------------------

fn main() {
    let mut input_string = String::new();
    let mut file = File::open("input.txt").unwrap();
    let _ = file.read_to_string(&mut input_string);

    //input_string = "cpy 41 a\ninc a\ninc a\ndec a\njnz a 2\ndec a".to_owned();

    let instructions: Vec<_> = input_string
        .lines()
        .map(|line| line.parse::<Instruction>().expect("parse failure"))
        .collect();

//    for ins in instructions {
//        println!("{:?}", ins);
//    }

    let mut pc = 0;
    let mut registers = [0i32; 4];
    while pc < instructions.len() {
        //std::thread::sleep_ms(500);
        let ins = instructions[pc];
        //println!("{},  {:32?},  {:?}", pc, ins, registers);
        match ins {
            Instruction::Cpy{src, dst} => {
                match src {
                    Source::Reg(src) => {registers[dst as usize] = registers[src as usize]},
                    Source::Val(i) => {registers[dst as usize] = i},
                };
                pc += 1;
            },
            Instruction::Inc{dst} => {registers[dst as usize] += 1; pc += 1;},
            Instruction::Dec{dst} => {registers[dst as usize] -= 1; pc += 1;},
            Instruction::Jnz{src, offset} => {
                let src_val = match src {
                    Source::Reg(src) => {registers[src as usize]},
                    Source::Val(i) => i,
                };
                if src_val != 0 {
                    let new_pc = pc as i32 + offset;
                    pc = new_pc as usize;
                } else { pc += 1;}
                //pc += 1;
            },
        }
    }

    println!("Registers: {:?}", registers);
    assert!(registers[Register::A as usize] == 318007);
}
<commit_msg>Day 12, part 2.<commit_after>
use std::fs::File;
use std::io::Read;
use std::str::FromStr;

#[derive(Debug,PartialEq,Eq,Clone,Copy)]
enum Register {
    A = 0,
    B = 1,
    C = 2,
    D = 3,
}
impl FromStr for Register {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Register, &'static str> {
        match s {
            "a" => Ok(Register::A),
            "b" => Ok(Register::B),
            "c" => Ok(Register::C),
            "d" => Ok(Register::D),
            _ => Err("Unknown register string"),
        }
    }
}

// -----------------------------------------------------------------------------

#[derive(Debug,PartialEq,Eq,Clone,Copy)]
enum Source {
    Reg (Register),
    Val (i32),
}
impl FromStr for Source {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Source, &'static str> {

        //s.parse::<Register>().or_else(Source::Val(s.parse::<i32>())?)

        if let Ok(reg) = s.parse::<Register>() {
            Ok(Source::Reg(reg))
        } else {
            s.parse::<i32>().map(|i| Source::Val(i))
                .map_err(|_| "Failed to parse int")
        }
    }
}

// -----------------------------------------------------------------------------

// cpy x y copies x (either an integer or the value of a register) into register y.
// inc x increases the value of register x by one.
// dec x decreases the value of register x by one.
// jnz x y jumps to an instruction y away (positive means forward; negative means backward),
//      but only if x is not zero.
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
enum Instruction {
    Cpy {src: Source, dst: Register},
    Inc {dst: Register},
    Dec {dst: Register},
    Jnz {src: Source, offset: i32},
}
impl FromStr for Instruction {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Instruction, &'static str> {
        let tokens: Vec<_> = s.split(' ').collect();
        match tokens[0] {
            "cpy" => Ok(Instruction::Cpy{ src: tokens[1].parse()?, dst: tokens[2].parse()? }),
            "inc" => Ok(Instruction::Inc{dst: tokens[1].parse()?}),
            "dec" => Ok(Instruction::Dec{dst: tokens[1].parse()?}),
            "jnz" => Ok(Instruction::Jnz{
                src: tokens[1].parse()?,
                offset: tokens[2].parse().expect("Failed to parse int")
            }),
            _ => Err("Unable to parse instruction"),
        }
    }
}

// -----------------------------------------------------------------------------

fn run_until_halt(instructions: &Vec<Instruction>, starting_registers: [i32; 4]) -> [i32; 4] {

    let mut pc = 0;
    let mut registers = starting_registers;

    while pc < instructions.len() {
        //std::thread::sleep_ms(500);
        let ins = instructions[pc];
        //println!("{},  {:32?},  {:?}", pc, ins, registers);
        match ins {
            Instruction::Cpy{src, dst} => {
                match src {
                    Source::Reg(src) => {registers[dst as usize] = registers[src as usize]},
                    Source::Val(i) => {registers[dst as usize] = i},
                };
                pc += 1;
            },
            Instruction::Inc{dst} => {registers[dst as usize] += 1; pc += 1;},
            Instruction::Dec{dst} => {registers[dst as usize] -= 1; pc += 1;},
            Instruction::Jnz{src, offset} => {
                let src_val = match src {
                    Source::Reg(src) => {registers[src as usize]},
                    Source::Val(i) => i,
                };
                if src_val != 0 {
                    let new_pc = pc as i32 + offset;
                    pc = new_pc as usize;
                } else {
                    pc += 1;
                }
            },
        }
    }
    registers
}

// -----------------------------------------------------------------------------

fn main() {
    let mut input_string = String::new();
    let mut file = File::open("input.txt").unwrap();
    let _ = file.read_to_string(&mut input_string);

    let instructions: Vec<_> = input_string
        .lines()
        .map(|line| line.parse::<Instruction>().expect("parse failure"))
        .collect();

    {
        let mut registers1 = [0i32; 4];
        registers1 = run_until_halt(&instructions, registers1);

        println!("Part 1: registers: {:?}", registers1);
        assert!(registers1[Register::A as usize] == 318007);
    }

    {
        // part 2
        let mut registers2 = [0, 0, 1, 0];
        registers2 = run_until_halt(&instructions, registers2);

        println!("Part 2: registers: {:?}", registers2);
        assert!(registers2[Register::A as usize] == 9227661);
    }
}
<|endoftext|>


<commit_before>#![feature(inclusive_range_syntax, plugin)]
#![plugin(clippy)]

#![deny(indexing_slicing)]
#![deny(out_of_bounds_indexing)]
#![allow(no_effect, unnecessary_operation)]

fn main() {
    let x = [1,2,3,4];
    x[0];
    x[3];
    x[4]; //~ERROR: const index is out of bounds
    x[1 << 3]; //~ERROR: const index is out of bounds
    &x[1..5]; //~ERROR: range is out of bounds
    &x[0..3];
    &x[0...4]; //~ERROR: range is out of bounds
    &x[..];
    &x[1..];
    &x[4..];
    &x[5..]; //~ERROR: range is out of bounds
    &x[..4];
    &x[..5]; //~ERROR: range is out of bounds

    let y = &x;
    y[0]; //~ERROR: indexing may panic
    &y[1..2]; //~ERROR: slicing may panic
    &y[..];
    &y[0...4]; //~ERROR: slicing may panic

    let empty: [i8; 0] = [];
    empty[0]; //~ERROR: const index is out of bounds
    &empty[1..5]; //~ERROR: range is out of bounds
    &empty[0...4]; //~ERROR: range is out of bounds
    &empty[..];
    &empty[0..];
    &empty[0..0];
    &empty[0...0]; //~ERROR: range is out of bounds
    &empty[..0];
    &empty[1..]; //~ERROR: range is out of bounds
    &empty[..4]; //~ERROR: range is out of bounds
}
<commit_msg>Add missing tests for `...` and array indexing<commit_after>#![feature(inclusive_range_syntax, plugin)]
#![plugin(clippy)]

#![deny(indexing_slicing)]
#![deny(out_of_bounds_indexing)]
#![allow(no_effect, unnecessary_operation)]

fn main() {
    let x = [1,2,3,4];
    x[0];
    x[3];
    x[4]; //~ERROR: const index is out of bounds
    x[1 << 3]; //~ERROR: const index is out of bounds
    &x[1..5]; //~ERROR: range is out of bounds
    &x[0..3];
    &x[0...4]; //~ERROR: range is out of bounds
    &x[...4]; //~ERROR: range is out of bounds
    &x[..];
    &x[1..];
    &x[4..];
    &x[5..]; //~ERROR: range is out of bounds
    &x[..4];
    &x[..5]; //~ERROR: range is out of bounds

    let y = &x;
    y[0]; //~ERROR: indexing may panic
    &y[1..2]; //~ERROR: slicing may panic
    &y[..];
    &y[0...4]; //~ERROR: slicing may panic
    &y[...4]; //~ERROR: slicing may panic

    let empty: [i8; 0] = [];
    empty[0]; //~ERROR: const index is out of bounds
    &empty[1..5]; //~ERROR: range is out of bounds
    &empty[0...4]; //~ERROR: range is out of bounds
    &empty[...4]; //~ERROR: range is out of bounds
    &empty[..];
    &empty[0..];
    &empty[0..0];
    &empty[0...0]; //~ERROR: range is out of bounds
    &empty[...0]; //~ERROR: range is out of bounds
    &empty[..0];
    &empty[1..]; //~ERROR: range is out of bounds
    &empty[..4]; //~ERROR: range is out of bounds
}
<|endoftext|>


<commit_before>

#[warn(eq_op)]
#[allow(identity_op, double_parens, many_single_char_names)]
#[allow(no_effect, unused_variables, unnecessary_operation, short_circuit_statement)]
#[warn(nonminimal_bool)]
fn main() {
    // simple values and comparisons
    1 == 1;
    "no" == "no";
    // even though I agree that no means no ;-)
    false != false;
    1.5 < 1.5;
    1u64 >= 1u64;

    // casts, methods, parentheses
    (1 as u64) & (1 as u64);
    1 ^ ((((((1))))));

    // unary and binary operators
    (-(2) < -(2));
    ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
    (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;

    // various other things
    ([1] != [1]);
    ((1, 2) != (1, 2));
    vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros

    // const folding
    1 + 1 == 2;
    1 - 1 == 0;

    1 - 1;
    1 / 1;
    true && true;

    true || true;

    let a: u32 = 0;
    let b: u32 = 0;

    a == b && b == a;
    a != b && b != a;
    a < b && b > a;
    a <= b && b >= a;

    let mut a = vec![1];
    a == a;
    2*a.len() == 2*a.len(); // ok, functions
    a.pop() == a.pop(); // ok, functions

    use std::ops::BitAnd;
    struct X(i32);
    impl BitAnd for X {
        type Output = X;
        fn bitand(self, rhs: X) -> X {
            X(self.0 & rhs.0)
        }
    }
    impl<'a> BitAnd<&'a X> for X {
        type Output = X;
        fn bitand(self, rhs: &'a X) -> X {
            X(self.0 & rhs.0)
        }
    }
    let x = X(1);
    let y = X(2);
    let z = x & &y;

    #[derive(Copy, Clone)]
    struct Y(i32);
    impl BitAnd for Y {
        type Output = Y;
        fn bitand(self, rhs: Y) -> Y {
            Y(self.0 & rhs.0)
        }
    }
    impl<'a> BitAnd<&'a Y> for Y {
        type Output = Y;
        fn bitand(self, rhs: &'a Y) -> Y {
            Y(self.0 & rhs.0)
        }
    }
    let x = Y(1);
    let y = Y(2);
    let z = x & &y;
}
<commit_msg>Create failing test for equal inside macro<commit_after>

#[warn(eq_op)]
#[allow(identity_op, double_parens, many_single_char_names)]
#[allow(no_effect, unused_variables, unnecessary_operation, short_circuit_statement)]
#[warn(nonminimal_bool)]
fn main() {
    // simple values and comparisons
    1 == 1;
    "no" == "no";
    // even though I agree that no means no ;-)
    false != false;
    1.5 < 1.5;
    1u64 >= 1u64;

    // casts, methods, parentheses
    (1 as u64) & (1 as u64);
    1 ^ ((((((1))))));

    // unary and binary operators
    (-(2) < -(2));
    ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
    (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;

    // various other things
    ([1] != [1]);
    ((1, 2) != (1, 2));
    vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros

    // const folding
    1 + 1 == 2;
    1 - 1 == 0;

    1 - 1;
    1 / 1;
    true && true;

    true || true;

    let a: u32 = 0;
    let b: u32 = 0;

    a == b && b == a;
    a != b && b != a;
    a < b && b > a;
    a <= b && b >= a;

    let mut a = vec![1];
    a == a;
    2*a.len() == 2*a.len(); // ok, functions
    a.pop() == a.pop(); // ok, functions

    use std::ops::BitAnd;
    struct X(i32);
    impl BitAnd for X {
        type Output = X;
        fn bitand(self, rhs: X) -> X {
            X(self.0 & rhs.0)
        }
    }
    impl<'a> BitAnd<&'a X> for X {
        type Output = X;
        fn bitand(self, rhs: &'a X) -> X {
            X(self.0 & rhs.0)
        }
    }
    let x = X(1);
    let y = X(2);
    let z = x & &y;

    #[derive(Copy, Clone)]
    struct Y(i32);
    impl BitAnd for Y {
        type Output = Y;
        fn bitand(self, rhs: Y) -> Y {
            Y(self.0 & rhs.0)
        }
    }
    impl<'a> BitAnd<&'a Y> for Y {
        type Output = Y;
        fn bitand(self, rhs: &'a Y) -> Y {
            Y(self.0 & rhs.0)
        }
    }
    let x = Y(1);
    let y = Y(2);
    let z = x & &y;

    check_ignore_macro();
}

macro_rules! check_if_named_foo {
    ($expression:expr) => (
        if stringify!($expression) == "foo" {
            println!("foo!");
        } else {
            println!("not foo.");
        }
    )
}

fn check_ignore_macro() {
    check_if_named_foo!(foo);
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;
extern crate hyper;

#[macro_use]
extern crate serde_derive;

use std::process::{Command};
use std::io::Read;
use hyper::header::ContentType;
use hyper::client::Client;
use serde_json::Value;

#[derive(Serialize, Deserialize)]
struct RPCRequest {
    jsonrpc: String,
    method: String,
    params: Vec<String>,
    id: usize,
}

#[derive(Serialize, Deserialize)]
struct RPCResponse<T> {
    jsonrpc: String,
    result: T,
    id: usize,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCTransaction {
    pub hash: String,
    pub nonce: String,
    pub blockHash: String,
    pub blockNumber: String,
    pub transactionIndex: String,
    pub from: String,
    pub to: String,
    pub value: String,
    pub gas: String,
    pub gasPrice: String,
    pub input: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCBlock {
    pub number: String,
    pub hash: String,
    pub parentHash: String,
    pub nonce: String,
    pub sha3Uncles: String,
    pub logsBloom: String,
    pub transactionsRoot: String,
    pub stateRoot: String,
    pub miner: String,
    pub difficulty: String,
    pub totalDifficulty: String,
    pub extraData: String,
    pub size: String,
    pub gasLimit: String,
    pub gasUsed: String,
    pub timestamp: String,
    pub transactions: Vec<String>,
    pub uncles: Vec<String>
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum RPCSyncStatus {
    NotSync(bool),
    Sync {
        startingBlock: String,
        currentBlock: String,
        highestBlock: String,
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCTransactionReceipt {
    pub transactionHash: String,
    pub transactionIndex: String,
    pub blockHash: String,
    pub blockNumber: String,
    pub cumulativeGasUsed: String,
    pub gasUsed: String,
    pub contractAddress: String,
    pub logs: Vec<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCFilter {
    pub fromBlock: String,
    pub toBlock: String,
    pub address: String,
    pub topics: Vec<String>,
}

pub struct GethRPCClient {
    endpoint: String,
    free_id: usize,
}

impl GethRPCClient {
    pub fn new(endpoint: &str) -> Self {
        GethRPCClient {
            endpoint: endpoint.to_string(),
            free_id: 1,
        }
    }

    fn rpc_request<T: serde::Deserialize>(&mut self, method: &str, params: Vec<String>) -> T {
        let request = RPCRequest {
            jsonrpc: "2.0".to_string(),
            method: method.to_string(),
            params: params,
            id: self.free_id,
        };
        self.free_id = self.free_id + 1;

        let client = Client::new();
        let mut response_raw = client.post(&self.endpoint)
            .header(ContentType::json())
            .body(&serde_json::to_string(&request).unwrap())
            .send().unwrap();
        let mut buffer = String::new();
        response_raw.read_to_string(&mut buffer).unwrap();

        let response: RPCResponse<T> = serde_json::from_str(&buffer).unwrap();
        response.result
    }

    pub fn client_version(&mut self) -> String {
        self.rpc_request::<String>("web3_clientVersion", vec![])
    }

    pub fn net_version(&mut self) -> String {
        self.rpc_request::<String>("net_version", vec![])
    }

    pub fn net_listening(&mut self) -> bool {
        self.rpc_request::<bool>("net_listening", vec![])
    }

    pub fn net_peer_count(&mut self) -> String {
        self.rpc_request::<String>("net_peerCount", vec![])
    }

    pub fn sha3(&mut self, data: &str) -> String {
        self.rpc_request::<String>("web3_sha3", vec![])
    }

    pub fn protocol_version(&mut self) -> String {
        self.rpc_request::<String>("eth_protocolVersion", vec![])
    }

    pub fn syncing(&mut self) -> RPCSyncStatus {
        self.rpc_request::<RPCSyncStatus>("eth_syncing", vec![])
    }

    pub fn coinbase(&mut self) -> String {
        self.rpc_request::<String>("eth_coinbase", vec![])
    }

    pub fn mining(&mut self) -> bool {
        self.rpc_request::<bool>("eth_mining", vec![])
    }

    pub fn hashrate(&mut self) -> String {
        self.rpc_request::<String>("eth_hashrate", vec![])
    }

    pub fn gas_price(&mut self) -> String {
        self.rpc_request::<String>("eth_gasPrice", vec![])
    }

    pub fn accounts(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_accounts", vec![])
    }

    pub fn block_number(&mut self) -> String {
        self.rpc_request::<String>("eth_blockNumber", vec![])
    }

    pub fn get_balance(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getBalance",
                                   vec![address.to_string(), number.to_string()])
    }

    pub fn get_storage_at(&mut self, address: &str, index: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getStorageAt",
                                   vec![address.to_string(), index.to_string(), number.to_string()])
    }

    pub fn get_transaction_count(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getTransactionCount",
                                   vec![address.to_string(), number.to_string()])
    }

    pub fn get_block_transaction_count_by_hash(&mut self, hash: &str) -> String {
        self.rpc_request::<String>("eth_getBlockTransactionCountByHash",
                                   vec![hash.to_string()])
    }

    pub fn get_block_transaction_count_by_number(&mut self, number: &str) -> String {
        self.rpc_request::<String>("eth_getBlockTransactionCountByNumber",
                                   vec![number.to_string()])
    }

    pub fn get_uncle_count_by_block_hash(&mut self, hash: &str) -> String {
        self.rpc_request::<String>("eth_getUncleCountByBlockHash",
                                   vec![hash.to_string()])
    }

    pub fn get_uncle_count_by_block_number(&mut self, number: &str) -> String {
        self.rpc_request::<String>("eth_getUncleCountByBlockNumber",
                                   vec![number.to_string()])
    }

    pub fn get_code(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getCode", vec![address.to_string(), number.to_string()])
    }

    pub fn sign(&mut self, address: &str, message: &str) -> String {
        self.rpc_request::<String>("eth_sign", vec![address.to_string(), message.to_string()])
    }

    pub fn send_transaction(&mut self, transaction: RPCTransaction) -> String {
        unimplemented!()
    }

    pub fn send_raw_transaction(&mut self, data: &str) -> String {
        self.rpc_request::<String>("eth_sendRawTransaction", vec![data.to_string()])
    }

    pub fn call(&mut self, transaction: RPCTransaction) -> String {
        unimplemented!()
    }

    pub fn estimate_gas(&mut self, transaction: RPCTransaction) -> String {
        unimplemented!()
    }

    pub fn get_block_by_hash(&mut self, hash: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getBlockByHash",
                                     vec![hash.to_string(), "false".to_string()])
    }

    pub fn get_block_by_number(&mut self, number: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getBlockByNumber",
                                     vec![number.to_string(), "false".to_string()])
    }

    pub fn get_transaction_by_hash(&mut self, hash: &str) -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByHash",
                                           vec![hash.to_string()])
    }

    pub fn get_transaction_by_block_hash_and_index(&mut self, hash: &str, index: &str) -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByBlockHashAndIndex",
                                           vec![hash.to_string(), index.to_string()])
    }

    pub fn get_transaction_by_block_number_and_index(&mut self, number: &str, index: &str)
                                                 -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByBlockNumberAndIndex",
                                           vec![number.to_string(), index.to_string()])
    }

    pub fn get_transaction_receipt(&mut self, hash: &str) -> RPCTransactionReceipt {
        self.rpc_request::<RPCTransactionReceipt>("eth_getTransactionReceipt",
                                                 vec![hash.to_string()])
    }

    pub fn get_uncle_by_block_hash_and_index(&mut self, hash: &str, index: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getUncleByBlockHashAndIndex",
                                     vec![hash.to_string(), index.to_string()])
    }

    pub fn get_uncle_by_block_number_and_index(&mut self, number: &str, index: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getUncleByBlockNumberAndIndex",
                                     vec![number.to_string(), index.to_string()])
    }

    pub fn get_compilers(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_getCompilers", vec![])
    }

    pub fn compile_solidity(&mut self, source: &str) -> String {
        unimplemented!()
    }

    pub fn compile_lll(&mut self, source: &str) -> String {
        self.rpc_request::<String>("eth_compileLLL", vec![source.to_string()])
    }

    pub fn compile_serpent(&mut self, source: &str) -> String {
        self.rpc_request::<String>("eth_compileSerpent", vec![source.to_string()])
    }

    pub fn new_filter(&mut self, filter: RPCFilter) -> String {
        unimplemented!()
    }

    pub fn new_block_filter(&mut self) -> String {
        self.rpc_request::<String>("eth_newBlockFilter", vec![])
    }

    pub fn new_pending_transaction_filter(&mut self) -> String {
        self.rpc_request::<String>("eth_newPendingTransactionFilter", vec![])
    }

    pub fn uninstall_filter(&mut self, id: &str) -> bool {
        self.rpc_request::<bool>("eth_uninstallFilter", vec![id.to_string()])
    }

    pub fn get_filter_changes(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_filter_logs(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_logs(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_work(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_getWork", vec![])
    }

    pub fn submit_work(&mut self, nonce: &str, pow: &str, mix: &str) -> bool {
        self.rpc_request::<bool>("eth_submitWork",
                                 vec![nonce.to_string(), pow.to_string(), mix.to_string()])
    }

    pub fn submit_hashrate(&mut self, hashrate: &str, id: &str) -> bool {
        self.rpc_request::<bool>("eth_submitHashrate",
                                 vec![hashrate.to_string(), id.to_string()])
    }

    pub fn put_string(&mut self, db: &str, key: &str, value: &str) -> bool {
        self.rpc_request::<bool>("db_putString",
                                 vec![db.to_string(), key.to_string(), value.to_string()])
    }

    pub fn get_string(&mut self, db: &str, key: &str) -> String {
        self.rpc_request::<String>("db_getString",
                                   vec![db.to_string(), key.to_string()])
    }

    pub fn put_hex(&mut self, db: &str, key: &str, value: &str) -> bool {
        self.rpc_request::<bool>("db_putHex",
                                 vec![db.to_string(), key.to_string(), value.to_string()])
    }

    pub fn get_hex(&mut self, db: &str, key: &str) -> String {
        self.rpc_request::<String>("db_getHex",
                                   vec![db.to_string(), key.to_string()])
    }
}

pub fn regression(address: &str) -> bool {
    let mut client = GethRPCClient::new("http://localhost:8545");
    let height = usize::from_str_radix(&client.block_number(), 16).unwrap();
    println!("height: {}", height);

    for blk_no in 49439..height {
        let block = client.get_block_by_number(format!("0x{:x}", blk_no).as_str());
        println!("{:?}", block);
    }
    false
}
<commit_msg>Problem: gethrpc does not handle non-string parameters in request<commit_after>extern crate serde;
extern crate serde_json;
extern crate hyper;

#[macro_use]
extern crate serde_derive;

use std::process::{Command};
use std::io::Read;
use hyper::header::ContentType;
use hyper::client::Client;
use serde_json::Value;

#[derive(Serialize, Deserialize)]
struct RPCRequest {
    jsonrpc: String,
    method: String,
    params: Vec<String>,
    id: usize,
}

#[derive(Serialize, Deserialize)]
struct RPCObjectRequest<T> {
    jsonrpc: String,
    method: String,
    params: T,
    id: usize,
}

#[derive(Serialize, Deserialize)]
struct RPCObjectResponse<T> {
    jsonrpc: String,
    result: T,
    id: usize,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCTransaction {
    pub hash: String,
    pub nonce: String,
    pub blockHash: String,
    pub blockNumber: String,
    pub transactionIndex: String,
    pub from: String,
    pub to: String,
    pub value: String,
    pub gas: String,
    pub gasPrice: String,
    pub input: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCBlock {
    pub number: String,
    pub hash: String,
    pub parentHash: String,
    pub nonce: String,
    pub sha3Uncles: String,
    pub logsBloom: String,
    pub transactionsRoot: String,
    pub stateRoot: String,
    pub miner: String,
    pub difficulty: String,
    pub totalDifficulty: String,
    pub extraData: String,
    pub size: String,
    pub gasLimit: String,
    pub gasUsed: String,
    pub timestamp: String,
    pub transactions: Vec<String>,
    pub uncles: Vec<String>
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum RPCSyncStatus {
    NotSync(bool),
    Sync {
        startingBlock: String,
        currentBlock: String,
        highestBlock: String,
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCTransactionReceipt {
    pub transactionHash: String,
    pub transactionIndex: String,
    pub blockHash: String,
    pub blockNumber: String,
    pub cumulativeGasUsed: String,
    pub gasUsed: String,
    pub contractAddress: String,
    pub logs: Vec<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCFilter {
    pub fromBlock: String,
    pub toBlock: String,
    pub address: String,
    pub topics: Vec<String>,
}

pub struct GethRPCClient {
    endpoint: String,
    free_id: usize,
}

impl GethRPCClient {
    pub fn new(endpoint: &str) -> Self {
        GethRPCClient {
            endpoint: endpoint.to_string(),
            free_id: 1,
        }
    }

    fn rpc_request<T: serde::Deserialize>(&mut self, method: &str, params: Vec<String>) -> T {
        self.rpc_object_request::<Vec<String>, T>(method, params)
    }

    fn rpc_object_request<Req: serde::Serialize, Res: serde::Deserialize>(&mut self, method: &str, params: Req) -> Res {
        let request = RPCObjectRequest {
            jsonrpc: "2.0".to_string(),
            method: method.to_string(),
            params: params,
            id: self.free_id,
        };
        self.free_id = self.free_id + 1;

        let client = Client::new();
        let mut response_raw = client.post(&self.endpoint)
            .header(ContentType::json())
            .body(&serde_json::to_string(&request).unwrap())
            .send().unwrap();
        let mut buffer = String::new();
        response_raw.read_to_string(&mut buffer).unwrap();

        let response: RPCObjectResponse<Res> = serde_json::from_str(&buffer).unwrap();
        response.result
    }

    pub fn client_version(&mut self) -> String {
        self.rpc_request::<String>("web3_clientVersion", vec![])
    }

    pub fn net_version(&mut self) -> String {
        self.rpc_request::<String>("net_version", vec![])
    }

    pub fn net_listening(&mut self) -> bool {
        self.rpc_request::<bool>("net_listening", vec![])
    }

    pub fn net_peer_count(&mut self) -> String {
        self.rpc_request::<String>("net_peerCount", vec![])
    }

    pub fn sha3(&mut self, data: &str) -> String {
        self.rpc_request::<String>("web3_sha3", vec![])
    }

    pub fn protocol_version(&mut self) -> String {
        self.rpc_request::<String>("eth_protocolVersion", vec![])
    }

    pub fn syncing(&mut self) -> RPCSyncStatus {
        self.rpc_request::<RPCSyncStatus>("eth_syncing", vec![])
    }

    pub fn coinbase(&mut self) -> String {
        self.rpc_request::<String>("eth_coinbase", vec![])
    }

    pub fn mining(&mut self) -> bool {
        self.rpc_request::<bool>("eth_mining", vec![])
    }

    pub fn hashrate(&mut self) -> String {
        self.rpc_request::<String>("eth_hashrate", vec![])
    }

    pub fn gas_price(&mut self) -> String {
        self.rpc_request::<String>("eth_gasPrice", vec![])
    }

    pub fn accounts(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_accounts", vec![])
    }

    pub fn block_number(&mut self) -> String {
        self.rpc_request::<String>("eth_blockNumber", vec![])
    }

    pub fn get_balance(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getBalance",
                                   vec![address.to_string(), number.to_string()])
    }

    pub fn get_storage_at(&mut self, address: &str, index: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getStorageAt",
                                   vec![address.to_string(), index.to_string(), number.to_string()])
    }

    pub fn get_transaction_count(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getTransactionCount",
                                   vec![address.to_string(), number.to_string()])
    }

    pub fn get_block_transaction_count_by_hash(&mut self, hash: &str) -> String {
        self.rpc_request::<String>("eth_getBlockTransactionCountByHash",
                                   vec![hash.to_string()])
    }

    pub fn get_block_transaction_count_by_number(&mut self, number: &str) -> String {
        self.rpc_request::<String>("eth_getBlockTransactionCountByNumber",
                                   vec![number.to_string()])
    }

    pub fn get_uncle_count_by_block_hash(&mut self, hash: &str) -> String {
        self.rpc_request::<String>("eth_getUncleCountByBlockHash",
                                   vec![hash.to_string()])
    }

    pub fn get_uncle_count_by_block_number(&mut self, number: &str) -> String {
        self.rpc_request::<String>("eth_getUncleCountByBlockNumber",
                                   vec![number.to_string()])
    }

    pub fn get_code(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getCode", vec![address.to_string(), number.to_string()])
    }

    pub fn sign(&mut self, address: &str, message: &str) -> String {
        self.rpc_request::<String>("eth_sign", vec![address.to_string(), message.to_string()])
    }

    pub fn send_transaction(&mut self, transaction: RPCTransaction) -> String {
        unimplemented!()
    }

    pub fn send_raw_transaction(&mut self, data: &str) -> String {
        self.rpc_request::<String>("eth_sendRawTransaction", vec![data.to_string()])
    }

    pub fn call(&mut self, transaction: RPCTransaction) -> String {
        unimplemented!()
    }

    pub fn estimate_gas(&mut self, transaction: RPCTransaction) -> String {
        unimplemented!()
    }

    pub fn get_block_by_hash(&mut self, hash: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getBlockByHash",
                                     vec![hash.to_string(), "false".to_string()])
    }

    pub fn get_block_by_number(&mut self, number: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getBlockByNumber",
                                     vec![number.to_string(), "false".to_string()])
    }

    pub fn get_transaction_by_hash(&mut self, hash: &str) -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByHash",
                                           vec![hash.to_string()])
    }

    pub fn get_transaction_by_block_hash_and_index(&mut self, hash: &str, index: &str) -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByBlockHashAndIndex",
                                           vec![hash.to_string(), index.to_string()])
    }

    pub fn get_transaction_by_block_number_and_index(&mut self, number: &str, index: &str)
                                                 -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByBlockNumberAndIndex",
                                           vec![number.to_string(), index.to_string()])
    }

    pub fn get_transaction_receipt(&mut self, hash: &str) -> RPCTransactionReceipt {
        self.rpc_request::<RPCTransactionReceipt>("eth_getTransactionReceipt",
                                                 vec![hash.to_string()])
    }

    pub fn get_uncle_by_block_hash_and_index(&mut self, hash: &str, index: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getUncleByBlockHashAndIndex",
                                     vec![hash.to_string(), index.to_string()])
    }

    pub fn get_uncle_by_block_number_and_index(&mut self, number: &str, index: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getUncleByBlockNumberAndIndex",
                                     vec![number.to_string(), index.to_string()])
    }

    pub fn get_compilers(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_getCompilers", vec![])
    }

    pub fn compile_solidity(&mut self, source: &str) -> String {
        unimplemented!()
    }

    pub fn compile_lll(&mut self, source: &str) -> String {
        self.rpc_request::<String>("eth_compileLLL", vec![source.to_string()])
    }

    pub fn compile_serpent(&mut self, source: &str) -> String {
        self.rpc_request::<String>("eth_compileSerpent", vec![source.to_string()])
    }

    pub fn new_filter(&mut self, filter: RPCFilter) -> String {
        unimplemented!()
    }

    pub fn new_block_filter(&mut self) -> String {
        self.rpc_request::<String>("eth_newBlockFilter", vec![])
    }

    pub fn new_pending_transaction_filter(&mut self) -> String {
        self.rpc_request::<String>("eth_newPendingTransactionFilter", vec![])
    }

    pub fn uninstall_filter(&mut self, id: &str) -> bool {
        self.rpc_request::<bool>("eth_uninstallFilter", vec![id.to_string()])
    }

    pub fn get_filter_changes(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_filter_logs(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_logs(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_work(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_getWork", vec![])
    }

    pub fn submit_work(&mut self, nonce: &str, pow: &str, mix: &str) -> bool {
        self.rpc_request::<bool>("eth_submitWork",
                                 vec![nonce.to_string(), pow.to_string(), mix.to_string()])
    }

    pub fn submit_hashrate(&mut self, hashrate: &str, id: &str) -> bool {
        self.rpc_request::<bool>("eth_submitHashrate",
                                 vec![hashrate.to_string(), id.to_string()])
    }

    pub fn put_string(&mut self, db: &str, key: &str, value: &str) -> bool {
        self.rpc_request::<bool>("db_putString",
                                 vec![db.to_string(), key.to_string(), value.to_string()])
    }

    pub fn get_string(&mut self, db: &str, key: &str) -> String {
        self.rpc_request::<String>("db_getString",
                                   vec![db.to_string(), key.to_string()])
    }

    pub fn put_hex(&mut self, db: &str, key: &str, value: &str) -> bool {
        self.rpc_request::<bool>("db_putHex",
                                 vec![db.to_string(), key.to_string(), value.to_string()])
    }

    pub fn get_hex(&mut self, db: &str, key: &str) -> String {
        self.rpc_request::<String>("db_getHex",
                                   vec![db.to_string(), key.to_string()])
    }
}

pub fn regression(address: &str) -> bool {
    let mut client = GethRPCClient::new("http://localhost:8545");
    let height = usize::from_str_radix(&client.block_number(), 16).unwrap();
    println!("height: {}", height);

    for blk_no in 49439..height {
        let block = client.get_block_by_number(format!("0x{:x}", blk_no).as_str());
        println!("{:?}", block);
    }
    false
}
<|endoftext|>


<commit_before>use sdl2;
use sdl2::AudioSubsystem;
use sdl2::EventPump;
use sdl2::event::Event;
use sdl2::render::Renderer;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::image::LoadTexture;
use sdl2::mixer;
use sdl2::mixer::Sdl2MixerContext;
use sdl2::mixer::Channel;
use sdl2::mixer::Chunk;
use OptionAway;
use input_private;
use input::Input;
use game_object::GameObject;
use component::Message;
use game_object;
use texture::Texture;
use texture;
use PolarCoords;
use Vector;
use transform::Transform;
use camera::Camera;
use nphysics2d::world::World;
use std::mem::replace;
use std::collections::HashMap;
use std::borrow::Borrow;
use std::path::PathBuf;
use std::f32;
use std::time::Instant;
use chrono::Duration;

pub struct App {
    exit: bool,
    renderer: Renderer<'static>,
    _audio: AudioSubsystem,
    _mixer: Sdl2MixerContext,
    event_pump: EventPump,
    game_objects: HashMap<u64, Option<Box<GameObject>>>,
    sound_cache: HashMap<String, Chunk>,
    next_game_object_id: u64,
    pub input: Input,
    pub camera: Camera,
    pub world: World<f32>,
}

impl App {
    ///Constructs a new App using the given name for the window title.
    pub fn new(name: &str) -> App {
        let sdl_context = sdl2::init().expect("Failed to initialize SDL2.");
        let video_subsystem = sdl_context.video().expect("Failed to initialize video subsystem");
        let window = video_subsystem.window(name, 800, 600)
            .position_centered()
            .fullscreen_desktop()
            .opengl()
            .build()
            .unwrap();
        let renderer = window.renderer().build().expect("Failed to initialize renderer");
        let audio = sdl_context.audio().expect("Failed to initialize audio");
        let mixer = mixer::init(mixer::INIT_OGG).expect("Failed to initialize mixer");
        mixer::open_audio(mixer::DEFAULT_FREQUENCY, mixer::DEFAULT_FORMAT, 2, 1024)
            .expect("Failed to open audio");
        mixer::allocate_channels(256);
        mixer::reserve_channels(128);
        App {
            exit: false,
            next_game_object_id: 0,
            game_objects: HashMap::new(),
            input: Input::new(),
            renderer: renderer,
            sound_cache: HashMap::new(),
            _audio: audio,
            _mixer: mixer,
            event_pump: sdl_context.event_pump().expect("Failed to initalize event pump."),
            camera: Camera { transform: Transform::new() },
            world: World::new(),
        }
    }

    /// Called every frame to paint the scene. Do not put game logic here, that goes in update.
    fn render(&mut self) {
        use std::f32;
        let game_objs = &self.game_objects;
        let camera_transform = self.camera.transform;
        // Clear the screen with grey.
        self.renderer.set_draw_color(Color::RGB(240, 240, 240));
        self.renderer.clear();
        // Reset the draw color to white so subsequent draw calls are correct.
        self.renderer.set_draw_color(Color::RGB(255, 255, 255));
        let (screen_width, screen_height) = self.renderer.window().unwrap().size();
        for game_obj in game_objs.values() {
            if let Some(ref game_obj) = *game_obj {
                let mut render_transform = game_obj.transform;
                *render_transform.mut_x() -= *camera_transform.x();
                *render_transform.mut_y() -= *camera_transform.y();
                let mut polar = PolarCoords::from(render_transform.position().clone());
                polar.rotation -= *camera_transform.rotation();
                *render_transform.mut_position() = Vector::from(polar);
                *render_transform.mut_x() += (screen_width / 2) as f32;
                *render_transform.mut_y() += (screen_height / 2) as f32;
                *render_transform.mut_rotation() -= *camera_transform.rotation();
                let (tex_width, tex_height) = texture::size(&game_obj.texture);
                let render_rect =
                    Rect::new(((*render_transform.x()) as i32) - (tex_width as i32 / 2),
                              ((*render_transform.y()) as i32) - (tex_height as i32 / 2),
                              tex_width,
                              tex_height);
                if let &Some(ref texture) = texture::get_raw(&game_obj.texture) {
                    let result = self.renderer.copy_ex(&texture,
                                                       None,
                                                       Some(render_rect),
                                                       (*game_obj.transform.rotation() * 180.0 /
                                                        f32::consts::PI) as
                                                       f64,
                                                       None,
                                                       false,
                                                       false);
                    if let Err(err) = result {
                        println!("Unable to draw texture, Error: {:?}", err);
                    }
                }
            }
        }
        self.renderer.present();
    }

    /// Called every frame to simulate the game. Do not put rendering here, that goes in render.
    fn update(&mut self, delta_time: f32) {
        //Copy game_object to the physics world, step, then copy from physics to game_object
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_to_physics(game_object);
            }
        }
        self.world.step(delta_time);
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_from_physics(game_object);
            }
        }

        //Send update messages
        let keys = self.game_objects.keys().map(|x| *x).collect::<Vec<u64>>();
        for key in keys {
            let mut game_obj_option = None;
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                game_obj_option = replace(game_obj_ref, None);
            }
            if let Some(ref mut game_obj) = game_obj_option {
                game_obj.update(self, delta_time);
                *game_obj.transform.mut_rotation() %= 2.0 * f32::consts::PI;
            }
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                replace(game_obj_ref, game_obj_option);
            }
        }

        // Drop any game objects that need to be dropped.
        let mut dropped_keys = Vec::new();
        for (key, game_obj) in self.game_objects.iter() {
            if let Some(ref game_obj) = *game_obj {
                if game_object::was_dropped(game_obj.borrow()) {
                    dropped_keys.push(*key);
                }
            } else {
                dropped_keys.push(*key);
            }
        }
        for key in dropped_keys {
            let removed = self.game_objects.remove(&key);
            if let Some(Some(mut game_obj)) = removed {
                game_obj.receive_message(self, &Message::OnDestroy);
            }
        }

        input_private::input::shift_frame(&mut self.input);
    }

    /// Begin execution of the game.
    ///
    /// This function won't return until the game has been quit.
    pub fn run(&mut self) {
        mixer::allocate_channels(128);
        let mut last_frame_instant = Instant::now();
        while !self.exit {
            while let Some(e) = self.event_pump.poll_event() {
                if let Event::Quit { .. } = e {
                    self.exit = true;
                }
                input_private::input::process_event(&mut self.input, &e);
            }
            self.update(Duration::from_std(last_frame_instant.elapsed())
                .unwrap()
                .num_microseconds()
                .unwrap() as f32 / 1000000.0);
            last_frame_instant = Instant::now();
            self.render();
        }
    }

    /// Exit the game
    ///
    /// Signals that it's time to quit. Execution will stop at the end of the current frame.
    pub fn quit(&mut self) {
        self.exit = true;
    }

    pub fn camera(&self) -> &Camera {
        &self.camera
    }

    pub fn camera_mut(&mut self) -> &mut Camera {
        &mut self.camera
    }

    /// Plays a sound at a volume between 1.0 and 0.0
    ///
    /// path is a filename relative to assets/sounds (assets\sounds on Windows)
    pub fn play_sound(&mut self, path: &str, volume: f32) -> Result<(), String> {
        if let Some(chunk) = self.sound_cache.get(path) {
            let channel = Channel::all().play(chunk, 0)?;
            channel.set_volume((volume * 128.0) as i32);
            return Ok(());
        }
        let mut file_path = PathBuf::from("assets");
        file_path.push("sounds");
        file_path.push(path);
        let chunk = Chunk::from_file(file_path)?;
        let channel = Channel::all().play(&chunk, 0)?;
        channel.set_volume((volume * 128.0) as i32);
        self.sound_cache.insert(path.to_owned(), chunk);
        Ok(())
    }

    /// Play a sound on a user sound channel.
    ///
    /// There are 128 user sound channels available at indices 0-127. You may use them as you
    /// please.
    pub fn play_sound_on_channel(&mut self, channel: i32, path: &str) -> Result<(), String> {
        if channel >= 0 && channel < 128 {
            if let Some(chunk) = self.sound_cache.get(path) {
                mixer::channel(channel).play(chunk, 0)?;
                return Ok(());
            }
            let mut file_path = PathBuf::from("assets");
            file_path.push("sounds");
            file_path.push(path);
            let chunk = Chunk::from_file(file_path)?;
            Channel::all().play(&chunk, 0)?;
            self.sound_cache.insert(path.to_owned(), chunk);
            return Ok(());
        }
        Err("Channel out of range.".to_string())
    }

    /// Set the volume for a user sound channel. Volume is between 0.0 and 1.0
    ///
    /// There are 128 user sound channels available at indices 0-127. You may use them as you
    /// please.
    pub fn set_channel_volume(&mut self, channel: i32, volume: f32) -> Result<(), String> {
       if channel >= 0 && channel < 128 {
            mixer::channel(channel).set_volume((volume * 128.0) as i32);
            return Ok(());
       }
       Err("Channel out of range.".to_string())
    }

    pub fn get_channel_volume(&self, channel: i32) -> Result<f32, String> {
        if channel >= 0 && channel < 128 {
            return Ok((mixer::channel(channel).get_volume() as f32)/128.0);
        }
        Err("Channel out of range.".to_string())
    }

    pub fn pause_channel(&mut self, channel: i32) -> Result<(), String> {
        if channel >= 0 && channel < 128 {
            mixer::channel(channel).pause();
            return Ok(());
        }
        Err("Channel out of range.".to_string())
    }

    pub fn resume_channel(&mut self, channel: i32) -> Result<(), String> {
        if channel >= 0 && channel < 128 {
            mixer::channel(channel).resume();
            return Ok(());
        }
        Err("Channel out of range.".to_string())
    }

    /// Creates a new GameObject
    ///
    /// GameObjects are typically physical objects in your game world, such as characters or
    /// decorative objects.
    ///
    /// Parameter f will be called on the newly created GameObject, allowing you to initialize it.
    /// Returns the id of the new GameObject, which can be used to retrieve this GameObject later.
    pub fn new_gameobject<F>(&mut self, f: F) -> u64
        where F: FnOnce(&mut App, &mut GameObject)
    {
        let mut game_object = Box::new(game_object::new(self));
        f(self, &mut game_object);
        let id = game_object.id();
        self.game_objects.insert(id, Some(game_object));
        id
    }

    /// Retrieves a reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id(&self, id: u64) -> OptionAway<&GameObject> {
        OptionAway::from(self.game_objects.get(&id))
    }

    /// Retrieves a mutable reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id_mut(&mut self, id: u64) -> OptionAway<&mut GameObject> {
        OptionAway::from(self.game_objects.get_mut(&id))
    }

    /// Loads a texture and returns it for use.
    ///
    /// texture_name is the file name of the texture relative to assets/textures
    /// (assets\textures on Windows)
    pub fn fetch_texture(&mut self, texture_name: &str) -> Result<Texture, String> {
        let mut texture_path = PathBuf::from("assets");
        texture_path.push("textures");
        texture_path.push(texture_name);
        let sdl_texture = self.renderer.load_texture(texture_path.as_path())?;
        let mut nitro_texture = Texture::new();
        texture::set_raw(&mut nitro_texture, sdl_texture);
        Ok(nitro_texture)
    }
}

// This function will never return 0.  0 can now be used as a null value.
pub fn next_game_object_id(app: &mut App) -> u64 {
    app.next_game_object_id += 1;
    app.next_game_object_id
}
<commit_msg>Documented audio API<commit_after>use sdl2;
use sdl2::AudioSubsystem;
use sdl2::EventPump;
use sdl2::event::Event;
use sdl2::render::Renderer;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::image::LoadTexture;
use sdl2::mixer;
use sdl2::mixer::Sdl2MixerContext;
use sdl2::mixer::Channel;
use sdl2::mixer::Chunk;
use OptionAway;
use input_private;
use input::Input;
use game_object::GameObject;
use component::Message;
use game_object;
use texture::Texture;
use texture;
use PolarCoords;
use Vector;
use transform::Transform;
use camera::Camera;
use nphysics2d::world::World;
use std::mem::replace;
use std::collections::HashMap;
use std::borrow::Borrow;
use std::path::PathBuf;
use std::f32;
use std::time::Instant;
use chrono::Duration;

pub struct App {
    exit: bool,
    renderer: Renderer<'static>,
    _audio: AudioSubsystem,
    _mixer: Sdl2MixerContext,
    event_pump: EventPump,
    game_objects: HashMap<u64, Option<Box<GameObject>>>,
    sound_cache: HashMap<String, Chunk>,
    next_game_object_id: u64,
    pub input: Input,
    pub camera: Camera,
    pub world: World<f32>,
}

impl App {
    ///Constructs a new App using the given name for the window title.
    pub fn new(name: &str) -> App {
        let sdl_context = sdl2::init().expect("Failed to initialize SDL2.");
        let video_subsystem = sdl_context.video().expect("Failed to initialize video subsystem");
        let window = video_subsystem.window(name, 800, 600)
            .position_centered()
            .fullscreen_desktop()
            .opengl()
            .build()
            .unwrap();
        let renderer = window.renderer().build().expect("Failed to initialize renderer");
        let audio = sdl_context.audio().expect("Failed to initialize audio");
        let mixer = mixer::init(mixer::INIT_OGG).expect("Failed to initialize mixer");
        mixer::open_audio(mixer::DEFAULT_FREQUENCY, mixer::DEFAULT_FORMAT, 2, 1024)
            .expect("Failed to open audio");
        mixer::allocate_channels(256);
        mixer::reserve_channels(128);
        App {
            exit: false,
            next_game_object_id: 0,
            game_objects: HashMap::new(),
            input: Input::new(),
            renderer: renderer,
            sound_cache: HashMap::new(),
            _audio: audio,
            _mixer: mixer,
            event_pump: sdl_context.event_pump().expect("Failed to initalize event pump."),
            camera: Camera { transform: Transform::new() },
            world: World::new(),
        }
    }

    /// Called every frame to paint the scene. Do not put game logic here, that goes in update.
    fn render(&mut self) {
        use std::f32;
        let game_objs = &self.game_objects;
        let camera_transform = self.camera.transform;
        // Clear the screen with grey.
        self.renderer.set_draw_color(Color::RGB(240, 240, 240));
        self.renderer.clear();
        // Reset the draw color to white so subsequent draw calls are correct.
        self.renderer.set_draw_color(Color::RGB(255, 255, 255));
        let (screen_width, screen_height) = self.renderer.window().unwrap().size();
        for game_obj in game_objs.values() {
            if let Some(ref game_obj) = *game_obj {
                let mut render_transform = game_obj.transform;
                *render_transform.mut_x() -= *camera_transform.x();
                *render_transform.mut_y() -= *camera_transform.y();
                let mut polar = PolarCoords::from(render_transform.position().clone());
                polar.rotation -= *camera_transform.rotation();
                *render_transform.mut_position() = Vector::from(polar);
                *render_transform.mut_x() += (screen_width / 2) as f32;
                *render_transform.mut_y() += (screen_height / 2) as f32;
                *render_transform.mut_rotation() -= *camera_transform.rotation();
                let (tex_width, tex_height) = texture::size(&game_obj.texture);
                let render_rect =
                    Rect::new(((*render_transform.x()) as i32) - (tex_width as i32 / 2),
                              ((*render_transform.y()) as i32) - (tex_height as i32 / 2),
                              tex_width,
                              tex_height);
                if let &Some(ref texture) = texture::get_raw(&game_obj.texture) {
                    let result = self.renderer.copy_ex(&texture,
                                                       None,
                                                       Some(render_rect),
                                                       (*game_obj.transform.rotation() * 180.0 /
                                                        f32::consts::PI) as
                                                       f64,
                                                       None,
                                                       false,
                                                       false);
                    if let Err(err) = result {
                        println!("Unable to draw texture, Error: {:?}", err);
                    }
                }
            }
        }
        self.renderer.present();
    }

    /// Called every frame to simulate the game. Do not put rendering here, that goes in render.
    fn update(&mut self, delta_time: f32) {
        //Copy game_object to the physics world, step, then copy from physics to game_object
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_to_physics(game_object);
            }
        }
        self.world.step(delta_time);
        for mut game_object in self.game_objects.values_mut() {
            if let Some(game_object) = game_object.as_mut() {
                game_object::copy_from_physics(game_object);
            }
        }

        //Send update messages
        let keys = self.game_objects.keys().map(|x| *x).collect::<Vec<u64>>();
        for key in keys {
            let mut game_obj_option = None;
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                game_obj_option = replace(game_obj_ref, None);
            }
            if let Some(ref mut game_obj) = game_obj_option {
                game_obj.update(self, delta_time);
                *game_obj.transform.mut_rotation() %= 2.0 * f32::consts::PI;
            }
            if let Some(game_obj_ref) = self.game_objects.get_mut(&key) {
                replace(game_obj_ref, game_obj_option);
            }
        }

        // Drop any game objects that need to be dropped.
        let mut dropped_keys = Vec::new();
        for (key, game_obj) in self.game_objects.iter() {
            if let Some(ref game_obj) = *game_obj {
                if game_object::was_dropped(game_obj.borrow()) {
                    dropped_keys.push(*key);
                }
            } else {
                dropped_keys.push(*key);
            }
        }
        for key in dropped_keys {
            let removed = self.game_objects.remove(&key);
            if let Some(Some(mut game_obj)) = removed {
                game_obj.receive_message(self, &Message::OnDestroy);
            }
        }

        input_private::input::shift_frame(&mut self.input);
    }

    /// Begin execution of the game.
    ///
    /// This function won't return until the game has been quit.
    pub fn run(&mut self) {
        mixer::allocate_channels(128);
        let mut last_frame_instant = Instant::now();
        while !self.exit {
            while let Some(e) = self.event_pump.poll_event() {
                if let Event::Quit { .. } = e {
                    self.exit = true;
                }
                input_private::input::process_event(&mut self.input, &e);
            }
            self.update(Duration::from_std(last_frame_instant.elapsed())
                .unwrap()
                .num_microseconds()
                .unwrap() as f32 / 1000000.0);
            last_frame_instant = Instant::now();
            self.render();
        }
    }

    /// Exit the game
    ///
    /// Signals that it's time to quit. Execution will stop at the end of the current frame.
    pub fn quit(&mut self) {
        self.exit = true;
    }

    pub fn camera(&self) -> &Camera {
        &self.camera
    }

    pub fn camera_mut(&mut self) -> &mut Camera {
        &mut self.camera
    }

    /// Plays a sound at a volume between 1.0 and 0.0
    ///
    /// path is a filename relative to assets/sounds (assets\sounds on Windows)
    pub fn play_sound(&mut self, path: &str, volume: f32) -> Result<(), String> {
        if let Some(chunk) = self.sound_cache.get(path) {
            let channel = Channel::all().play(chunk, 0)?;
            channel.set_volume((volume * 128.0) as i32);
            return Ok(());
        }
        let mut file_path = PathBuf::from("assets");
        file_path.push("sounds");
        file_path.push(path);
        let chunk = Chunk::from_file(file_path)?;
        let channel = Channel::all().play(&chunk, 0)?;
        channel.set_volume((volume * 128.0) as i32);
        self.sound_cache.insert(path.to_owned(), chunk);
        Ok(())
    }

    /// Play a sound on a user sound channel.
    ///
    /// There are 128 user sound channels available at indices 0-127. You may use them as you
    /// please.
    pub fn play_sound_on_channel(&mut self, channel: i32, path: &str) -> Result<(), String> {
        if channel >= 0 && channel < 128 {
            if let Some(chunk) = self.sound_cache.get(path) {
                mixer::channel(channel).play(chunk, 0)?;
                return Ok(());
            }
            let mut file_path = PathBuf::from("assets");
            file_path.push("sounds");
            file_path.push(path);
            let chunk = Chunk::from_file(file_path)?;
            Channel::all().play(&chunk, 0)?;
            self.sound_cache.insert(path.to_owned(), chunk);
            return Ok(());
        }
        Err("Channel out of range.".to_string())
    }

    /// Set the volume for a user sound channel. Volume is between 0.0 and 1.0
    ///
    /// There are 128 user sound channels available at indices 0-127. You may use them as you
    /// please.
    pub fn set_channel_volume(&mut self, channel: i32, volume: f32) -> Result<(), String> {
       if channel >= 0 && channel < 128 {
            mixer::channel(channel).set_volume((volume * 128.0) as i32);
            return Ok(());
       }
       Err("Channel out of range.".to_string())
    }

    /// Get the volume for a user sound channel. Volume is between 0.0 and 1.0
    ///
    /// There are 128 user sound channels available at indices 0-127. You may use them as you
    /// please.
    pub fn get_channel_volume(&self, channel: i32) -> Result<f32, String> {
        if channel >= 0 && channel < 128 {
            return Ok((mixer::channel(channel).get_volume() as f32)/128.0);
        }
        Err("Channel out of range.".to_string())
    }

    /// Pause audio output on a user sound channel.
    ///
    /// There are 128 user sound channels available at indices 0-127. You may use them as you
    /// please.
    pub fn pause_channel(&mut self, channel: i32) -> Result<(), String> {
        if channel >= 0 && channel < 128 {
            mixer::channel(channel).pause();
            return Ok(());
        }
        Err("Channel out of range.".to_string())
    }

    /// Resume paused audio output on a user sound channel.
    ///
    /// There are 128 user sound channels available at indices 0-127. You may use them as you
    /// please.
    pub fn resume_channel(&mut self, channel: i32) -> Result<(), String> {
        if channel >= 0 && channel < 128 {
            mixer::channel(channel).resume();
            return Ok(());
        }
        Err("Channel out of range.".to_string())
    }

    /// Returns true if a channel is not playing anything. This will still return false if the
    /// channel has a sound to play but is paused.
    ///
    /// There are 128 user sound channels available at indices 0-127. You may use them as you
    /// please.
    pub fn channel_idle(&mut self, channel: i32) -> Option<bool> {
        if channel >= 0 && channel < 128 {
            return Some(mixer::channel(channel).is_playing());
        }
        None
    }

    /// Creates a new GameObject
    ///
    /// GameObjects are typically physical objects in your game world, such as characters or
    /// decorative objects.
    ///
    /// Parameter f will be called on the newly created GameObject, allowing you to initialize it.
    /// Returns the id of the new GameObject, which can be used to retrieve this GameObject later.
    pub fn new_gameobject<F>(&mut self, f: F) -> u64
        where F: FnOnce(&mut App, &mut GameObject)
    {
        let mut game_object = Box::new(game_object::new(self));
        f(self, &mut game_object);
        let id = game_object.id();
        self.game_objects.insert(id, Some(game_object));
        id
    }

    /// Retrieves a reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id(&self, id: u64) -> OptionAway<&GameObject> {
        OptionAway::from(self.game_objects.get(&id))
    }

    /// Retrieves a mutable reference to an existing GameObject by the GameObject's id.
    ///
    /// Returns Away if and only if the GameObject exists but is currently loaned out
    /// in another borrow.
    ///
    /// Hint: That borrow is most likely in the game_object parameter of the receive_message
    /// function.
    pub fn game_object_by_id_mut(&mut self, id: u64) -> OptionAway<&mut GameObject> {
        OptionAway::from(self.game_objects.get_mut(&id))
    }

    /// Loads a texture and returns it for use.
    ///
    /// texture_name is the file name of the texture relative to assets/textures
    /// (assets\textures on Windows)
    pub fn fetch_texture(&mut self, texture_name: &str) -> Result<Texture, String> {
        let mut texture_path = PathBuf::from("assets");
        texture_path.push("textures");
        texture_path.push(texture_name);
        let sdl_texture = self.renderer.load_texture(texture_path.as_path())?;
        let mut nitro_texture = Texture::new();
        texture::set_raw(&mut nitro_texture, sdl_texture);
        Ok(nitro_texture)
    }
}

// This function will never return 0.  0 can now be used as a null value.
pub fn next_game_object_id(app: &mut App) -> u64 {
    app.next_game_object_id += 1;
    app.next_game_object_id
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

use crate::bytecode;
use crate::language::error::msg::ErrorMessage;
use crate::language::sem_analysis::{
    FctDefinition, SemAnalysis, SourceFileId, TypeParamDefinition, TypeParamId,
};
use crate::language::sym::{NestedSymTable, Sym};
use crate::language::ty::SourceType;
use dora_parser::ast;
use dora_parser::interner::Name;
use dora_parser::lexer::position::Position;

pub use program_parser::should_file_be_parsed;
pub use readty::{read_type, read_type_unchecked, AllowSelf, TypeParamContext};

pub(crate) mod access;
mod clsdefck;
mod constdefck;
mod enumck;
pub mod error;
mod extensiondefck;
mod fctbodyck;
mod fctdefck;
pub mod generator;
#[cfg(test)]
mod generator_tests;
mod globaldefck;
mod implck;
mod impldefck;
mod program_parser;
mod readty;
mod returnck;
pub mod sem_analysis;
mod specialize;
mod stdlib;
mod structdefck;
pub(crate) mod sym;
#[cfg(test)]
mod test;
mod traitdefck;
pub(crate) mod ty;
mod type_params;
mod typeparamck;
mod useck;

macro_rules! return_on_error {
    ($vm: ident) => {{
        if $vm.diag.lock().has_errors() {
            return false;
        }
    }};
}

pub fn check(sa: &mut SemAnalysis) -> bool {
    // This phase loads and parses all files. Also creates top-level-elements.
    if let Err(_) = program_parser::parse(sa) {
        return false;
    }
    return_on_error!(sa);

    // add internal annotations early
    stdlib::resolve_internal_annotations(sa);

    // define internal classes
    stdlib::resolve_internal_classes(sa);

    // discover all enum variants
    enumck::check_variants(sa);

    // fill prelude with important types and functions
    stdlib::fill_prelude(sa);

    // discover all types
    useck::check(sa);
    return_on_error!(sa);

    type_params::check(sa);
    return_on_error!(sa);

    // find all trait implementations for classes
    impldefck::check(sa);

    // checks class/struct/trait/enum definitions
    clsdefck::check(sa);
    structdefck::check(sa);
    traitdefck::check(sa);
    enumck::check(sa);
    return_on_error!(sa);

    globaldefck::check(sa);
    constdefck::check(sa);
    extensiondefck::check(sa);
    return_on_error!(sa);

    // check type definitions of params and return types in functions
    fctdefck::check(sa);
    return_on_error!(sa);

    // check impl methods against trait definition
    implck::check(sa);
    return_on_error!(sa);

    // define internal functions & methods
    stdlib::resolve_internal_functions(sa);
    stdlib::discover_known_methods(sa);
    stdlib::create_lambda_class(sa);

    // check for internal functions or classes
    internalck(sa);
    return_on_error!(sa);

    // check function body
    fctbodyck::check(sa);
    return_on_error!(sa);

    true
}

pub fn emit_ast(sa: &SemAnalysis) {
    if sa.args.flag_emit_ast.is_none() {
        return;
    }

    for fct in sa.fcts.iter() {
        let fct = fct.read();

        if should_emit_ast(sa, &*fct) {
            ast::dump::dump_fct(&fct.ast, &sa.interner);
        }
    }
}

fn should_emit_ast(sa: &SemAnalysis, fct: &FctDefinition) -> bool {
    if let Some(ref dbg_names) = sa.args.flag_emit_ast {
        fct_pattern_match(sa, fct, dbg_names)
    } else {
        false
    }
}

pub fn generate_bytecode(sa: &SemAnalysis) {
    for fct in sa.fcts.iter() {
        let bc = {
            let fct = fct.read();

            if !fct.has_body() {
                continue;
            }

            let analysis = fct.analysis();
            generator::generate(sa, &*fct, analysis)
        };

        fct.write().bytecode = Some(bc);

        {
            let fct = fct.read();

            if fct.module_id == sa.program_module_id && should_emit_bytecode(sa, &*fct) {
                bytecode::dump(sa, Some(&*fct), fct.bytecode.as_ref().unwrap());
            }
        }
    }
}

fn should_emit_bytecode(sa: &SemAnalysis, fct: &FctDefinition) -> bool {
    if let Some(ref dbg_names) = sa.args.flag_emit_bytecode {
        fct_pattern_match(sa, fct, dbg_names)
    } else {
        false
    }
}

fn fct_pattern_match(sa: &SemAnalysis, fct: &FctDefinition, pattern: &str) -> bool {
    if pattern == "all" {
        return true;
    }

    let fct_name = fct.display_name(sa);

    for part in pattern.split(',') {
        if fct_name.contains(part) {
            return true;
        }
    }

    false
}

fn internalck(sa: &SemAnalysis) {
    for fct in sa.fcts.iter() {
        let fct = fct.read();

        if fct.internal && !fct.internal_resolved && !fct.has_body() {
            sa.diag
                .lock()
                .report(fct.file_id, fct.pos, ErrorMessage::UnresolvedInternal);
        }

        if !fct.has_body() && !fct.in_trait() && !fct.internal {
            sa.diag
                .lock()
                .report(fct.file_id, fct.pos, ErrorMessage::MissingFctBody);
        }
    }

    for struct_ in sa.structs.iter() {
        let struct_ = struct_.read();

        if struct_.internal && !struct_.internal_resolved {
            sa.diag.lock().report(
                struct_.file_id,
                struct_.pos,
                ErrorMessage::UnresolvedInternal,
            );
        }
    }

    for cls in sa.classes.iter() {
        let cls = cls.read();

        if cls.internal && !cls.internal_resolved {
            sa.diag
                .lock()
                .report(cls.file_id(), cls.pos(), ErrorMessage::UnresolvedInternal);
        }
    }
}

pub fn always_returns(s: &ast::Stmt) -> bool {
    returnck::returns_value(s).is_ok()
}

pub fn expr_always_returns(e: &ast::Expr) -> bool {
    returnck::expr_returns_value(e).is_ok()
}

pub fn expr_block_always_returns(e: &ast::ExprBlockType) -> bool {
    returnck::expr_block_returns_value(e).is_ok()
}

pub fn report_sym_shadow(
    sa: &SemAnalysis,
    name: Name,
    file: SourceFileId,
    pos: Position,
    sym: Sym,
) {
    let name = sa.interner.str(name).to_string();

    let msg = match sym {
        Sym::Class(_) => ErrorMessage::ShadowClass(name),
        Sym::Struct(_) => ErrorMessage::ShadowStruct(name),
        Sym::Trait(_) => ErrorMessage::ShadowTrait(name),
        Sym::Enum(_) => ErrorMessage::ShadowEnum(name),
        Sym::Fct(_) => ErrorMessage::ShadowFunction(name),
        Sym::Global(_) => ErrorMessage::ShadowGlobal(name),
        Sym::Const(_) => ErrorMessage::ShadowConst(name),
        Sym::Var(_) => ErrorMessage::ShadowParam(name),
        Sym::Module(_) => ErrorMessage::ShadowModule(name),
        Sym::TypeParam(_) => ErrorMessage::ShadowTypeParam(name),
        _ => unreachable!(),
    };

    sa.diag.lock().report(file, pos, msg);
}

fn check_type_params(
    sa: &SemAnalysis,
    ast_type_params: &[ast::TypeParam],
    type_params: &mut TypeParamDefinition,
    symtable: &mut NestedSymTable,
    file_id: SourceFileId,
    pos: Position,
) -> Vec<SourceType> {
    if ast_type_params.len() == 0 {
        let msg = ErrorMessage::TypeParamsExpected;
        sa.diag.lock().report(file_id, pos, msg);

        return Vec::new();
    }

    let mut names = HashSet::new();
    let mut params = Vec::new();

    for (type_param_id, type_param) in ast_type_params.iter().enumerate() {
        if !names.insert(type_param.name) {
            let name = sa.interner.str(type_param.name).to_string();
            let msg = ErrorMessage::TypeParamNameNotUnique(name);
            sa.diag.lock().report(file_id, type_param.pos, msg);
        }

        params.push(SourceType::TypeParam(TypeParamId(type_param_id)));

        for bound in &type_param.bounds {
            let ty = read_type(
                sa,
                symtable,
                file_id,
                bound,
                TypeParamContext::None,
                AllowSelf::No,
            );

            if let Some(ty) = ty {
                if ty.is_trait() {
                    if !type_params.add_bound(TypeParamId(type_param_id), ty) {
                        let msg = ErrorMessage::DuplicateTraitBound;
                        sa.diag.lock().report(file_id, type_param.pos, msg);
                    }
                } else {
                    let msg = ErrorMessage::BoundExpected;
                    sa.diag.lock().report(file_id, bound.pos(), msg);
                }
            } else {
                // unknown type, error is already thrown
            }
        }

        let sym = Sym::TypeParam(TypeParamId(type_param_id));
        symtable.insert(type_param.name, sym);
    }

    params
}

#[cfg(test)]
pub mod tests {
    use crate::language::error::msg::ErrorMessage;
    use crate::language::sem_analysis::SemAnalysis;
    use crate::language::test;
    use dora_parser::lexer::position::Position;

    pub fn ok(code: &'static str) {
        test::check(code, |vm| {
            let diag = vm.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);
            println!();

            for e in errors {
                println!("{}", e.message(vm));
            }

            assert!(!diag.has_errors());
        });
    }

    pub fn ok_with_test<F, R>(code: &'static str, f: F) -> R
    where
        F: FnOnce(&SemAnalysis) -> R,
    {
        test::check(code, |vm| {
            let diag = vm.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);

            for e in errors {
                println!("{}", e.message(vm));
            }

            assert!(!diag.has_errors());

            f(vm)
        })
    }

    pub fn err(code: &'static str, pos: Position, msg: ErrorMessage) {
        test::check(code, |vm| {
            let diag = vm.diag.lock();
            let errors = diag.errors();

            if errors.len() != 1 || errors[0].pos != pos || errors[0].msg != msg {
                println!("expected:");
                println!("\t{:?} at {}", msg, pos);
                println!();
                if errors.is_empty() {
                    println!("but got no error.");
                    println!();
                } else {
                    println!("but got:");
                    for error in errors {
                        println!("\t{:?} at {}", error.msg, error.pos);
                        println!();
                    }
                }
            }

            assert_eq!(1, errors.len(), "found {} errors instead", errors.len());
            assert_eq!(pos, errors[0].pos);
            assert_eq!(msg, errors[0].msg);
        });
    }

    pub fn errors(code: &'static str, vec: &[(Position, ErrorMessage)]) {
        test::check(code, |vm| {
            let diag = vm.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);
            assert_eq!(vec.len(), errors.len());

            for (ind, error) in errors.iter().enumerate() {
                assert_eq!(vec[ind].0, error.pos);
                assert_eq!(vec[ind].1, error.msg);
            }
        });
    }

    pub fn pos(line: u32, col: u32) -> Position {
        Position::new(line, col)
    }
}
<commit_msg>improve reporting for unit test errors<commit_after>use std::collections::HashSet;

use crate::bytecode;
use crate::language::error::msg::ErrorMessage;
use crate::language::sem_analysis::{
    FctDefinition, SemAnalysis, SourceFileId, TypeParamDefinition, TypeParamId,
};
use crate::language::sym::{NestedSymTable, Sym};
use crate::language::ty::SourceType;
use dora_parser::ast;
use dora_parser::interner::Name;
use dora_parser::lexer::position::Position;

pub use program_parser::should_file_be_parsed;
pub use readty::{read_type, read_type_unchecked, AllowSelf, TypeParamContext};

pub(crate) mod access;
mod clsdefck;
mod constdefck;
mod enumck;
pub mod error;
mod extensiondefck;
mod fctbodyck;
mod fctdefck;
pub mod generator;
#[cfg(test)]
mod generator_tests;
mod globaldefck;
mod implck;
mod impldefck;
mod program_parser;
mod readty;
mod returnck;
pub mod sem_analysis;
mod specialize;
mod stdlib;
mod structdefck;
pub(crate) mod sym;
#[cfg(test)]
mod test;
mod traitdefck;
pub(crate) mod ty;
mod type_params;
mod typeparamck;
mod useck;

macro_rules! return_on_error {
    ($vm: ident) => {{
        if $vm.diag.lock().has_errors() {
            return false;
        }
    }};
}

pub fn check(sa: &mut SemAnalysis) -> bool {
    // This phase loads and parses all files. Also creates top-level-elements.
    if let Err(_) = program_parser::parse(sa) {
        return false;
    }
    return_on_error!(sa);

    // add internal annotations early
    stdlib::resolve_internal_annotations(sa);

    // define internal classes
    stdlib::resolve_internal_classes(sa);

    // discover all enum variants
    enumck::check_variants(sa);

    // fill prelude with important types and functions
    stdlib::fill_prelude(sa);

    // discover all types
    useck::check(sa);
    return_on_error!(sa);

    type_params::check(sa);
    return_on_error!(sa);

    // find all trait implementations for classes
    impldefck::check(sa);

    // checks class/struct/trait/enum definitions
    clsdefck::check(sa);
    structdefck::check(sa);
    traitdefck::check(sa);
    enumck::check(sa);
    return_on_error!(sa);

    globaldefck::check(sa);
    constdefck::check(sa);
    extensiondefck::check(sa);
    return_on_error!(sa);

    // check type definitions of params and return types in functions
    fctdefck::check(sa);
    return_on_error!(sa);

    // check impl methods against trait definition
    implck::check(sa);
    return_on_error!(sa);

    // define internal functions & methods
    stdlib::resolve_internal_functions(sa);
    stdlib::discover_known_methods(sa);
    stdlib::create_lambda_class(sa);

    // check for internal functions or classes
    internalck(sa);
    return_on_error!(sa);

    // check function body
    fctbodyck::check(sa);
    return_on_error!(sa);

    true
}

pub fn emit_ast(sa: &SemAnalysis) {
    if sa.args.flag_emit_ast.is_none() {
        return;
    }

    for fct in sa.fcts.iter() {
        let fct = fct.read();

        if should_emit_ast(sa, &*fct) {
            ast::dump::dump_fct(&fct.ast, &sa.interner);
        }
    }
}

fn should_emit_ast(sa: &SemAnalysis, fct: &FctDefinition) -> bool {
    if let Some(ref dbg_names) = sa.args.flag_emit_ast {
        fct_pattern_match(sa, fct, dbg_names)
    } else {
        false
    }
}

pub fn generate_bytecode(sa: &SemAnalysis) {
    for fct in sa.fcts.iter() {
        let bc = {
            let fct = fct.read();

            if !fct.has_body() {
                continue;
            }

            let analysis = fct.analysis();
            generator::generate(sa, &*fct, analysis)
        };

        fct.write().bytecode = Some(bc);

        {
            let fct = fct.read();

            if fct.module_id == sa.program_module_id && should_emit_bytecode(sa, &*fct) {
                bytecode::dump(sa, Some(&*fct), fct.bytecode.as_ref().unwrap());
            }
        }
    }
}

fn should_emit_bytecode(sa: &SemAnalysis, fct: &FctDefinition) -> bool {
    if let Some(ref dbg_names) = sa.args.flag_emit_bytecode {
        fct_pattern_match(sa, fct, dbg_names)
    } else {
        false
    }
}

fn fct_pattern_match(sa: &SemAnalysis, fct: &FctDefinition, pattern: &str) -> bool {
    if pattern == "all" {
        return true;
    }

    let fct_name = fct.display_name(sa);

    for part in pattern.split(',') {
        if fct_name.contains(part) {
            return true;
        }
    }

    false
}

fn internalck(sa: &SemAnalysis) {
    for fct in sa.fcts.iter() {
        let fct = fct.read();

        if fct.internal && !fct.internal_resolved && !fct.has_body() {
            sa.diag
                .lock()
                .report(fct.file_id, fct.pos, ErrorMessage::UnresolvedInternal);
        }

        if !fct.has_body() && !fct.in_trait() && !fct.internal {
            sa.diag
                .lock()
                .report(fct.file_id, fct.pos, ErrorMessage::MissingFctBody);
        }
    }

    for struct_ in sa.structs.iter() {
        let struct_ = struct_.read();

        if struct_.internal && !struct_.internal_resolved {
            sa.diag.lock().report(
                struct_.file_id,
                struct_.pos,
                ErrorMessage::UnresolvedInternal,
            );
        }
    }

    for cls in sa.classes.iter() {
        let cls = cls.read();

        if cls.internal && !cls.internal_resolved {
            sa.diag
                .lock()
                .report(cls.file_id(), cls.pos(), ErrorMessage::UnresolvedInternal);
        }
    }
}

pub fn always_returns(s: &ast::Stmt) -> bool {
    returnck::returns_value(s).is_ok()
}

pub fn expr_always_returns(e: &ast::Expr) -> bool {
    returnck::expr_returns_value(e).is_ok()
}

pub fn expr_block_always_returns(e: &ast::ExprBlockType) -> bool {
    returnck::expr_block_returns_value(e).is_ok()
}

pub fn report_sym_shadow(
    sa: &SemAnalysis,
    name: Name,
    file: SourceFileId,
    pos: Position,
    sym: Sym,
) {
    let name = sa.interner.str(name).to_string();

    let msg = match sym {
        Sym::Class(_) => ErrorMessage::ShadowClass(name),
        Sym::Struct(_) => ErrorMessage::ShadowStruct(name),
        Sym::Trait(_) => ErrorMessage::ShadowTrait(name),
        Sym::Enum(_) => ErrorMessage::ShadowEnum(name),
        Sym::Fct(_) => ErrorMessage::ShadowFunction(name),
        Sym::Global(_) => ErrorMessage::ShadowGlobal(name),
        Sym::Const(_) => ErrorMessage::ShadowConst(name),
        Sym::Var(_) => ErrorMessage::ShadowParam(name),
        Sym::Module(_) => ErrorMessage::ShadowModule(name),
        Sym::TypeParam(_) => ErrorMessage::ShadowTypeParam(name),
        _ => unreachable!(),
    };

    sa.diag.lock().report(file, pos, msg);
}

fn check_type_params(
    sa: &SemAnalysis,
    ast_type_params: &[ast::TypeParam],
    type_params: &mut TypeParamDefinition,
    symtable: &mut NestedSymTable,
    file_id: SourceFileId,
    pos: Position,
) -> Vec<SourceType> {
    if ast_type_params.len() == 0 {
        let msg = ErrorMessage::TypeParamsExpected;
        sa.diag.lock().report(file_id, pos, msg);

        return Vec::new();
    }

    let mut names = HashSet::new();
    let mut params = Vec::new();

    for (type_param_id, type_param) in ast_type_params.iter().enumerate() {
        if !names.insert(type_param.name) {
            let name = sa.interner.str(type_param.name).to_string();
            let msg = ErrorMessage::TypeParamNameNotUnique(name);
            sa.diag.lock().report(file_id, type_param.pos, msg);
        }

        params.push(SourceType::TypeParam(TypeParamId(type_param_id)));

        for bound in &type_param.bounds {
            let ty = read_type(
                sa,
                symtable,
                file_id,
                bound,
                TypeParamContext::None,
                AllowSelf::No,
            );

            if let Some(ty) = ty {
                if ty.is_trait() {
                    if !type_params.add_bound(TypeParamId(type_param_id), ty) {
                        let msg = ErrorMessage::DuplicateTraitBound;
                        sa.diag.lock().report(file_id, type_param.pos, msg);
                    }
                } else {
                    let msg = ErrorMessage::BoundExpected;
                    sa.diag.lock().report(file_id, bound.pos(), msg);
                }
            } else {
                // unknown type, error is already thrown
            }
        }

        let sym = Sym::TypeParam(TypeParamId(type_param_id));
        symtable.insert(type_param.name, sym);
    }

    params
}

#[cfg(test)]
pub mod tests {
    use crate::language::error::msg::ErrorMessage;
    use crate::language::sem_analysis::SemAnalysis;
    use crate::language::test;
    use dora_parser::lexer::position::Position;

    pub fn ok(code: &'static str) {
        test::check(code, |vm| {
            let diag = vm.diag.lock();
            let errors = diag.errors();

            for e in errors {
                println!("{}", e.message(vm));
                println!("{:?}", e);
                println!();
            }

            assert!(!diag.has_errors(), "program should not have errors.");
        });
    }

    pub fn ok_with_test<F, R>(code: &'static str, f: F) -> R
    where
        F: FnOnce(&SemAnalysis) -> R,
    {
        test::check(code, |vm| {
            let diag = vm.diag.lock();
            let errors = diag.errors();

            for e in errors {
                println!("{}", e.message(vm));
                println!("{:?}", e);
                println!();
            }

            assert!(!diag.has_errors());

            f(vm)
        })
    }

    pub fn err(code: &'static str, pos: Position, msg: ErrorMessage) {
        test::check(code, |vm| {
            let diag = vm.diag.lock();
            let errors = diag.errors();

            if errors.len() != 1 || errors[0].pos != pos || errors[0].msg != msg {
                println!("expected:");
                println!("\t{:?} at {}", msg, pos);
                println!();
                if errors.is_empty() {
                    println!("but got no error.");
                    println!();
                } else {
                    println!("but got:");
                    for error in errors {
                        println!("\t{:?} at {}", error.msg, error.pos);
                        println!();
                    }
                }
            }

            assert_eq!(1, errors.len(), "found {} errors instead", errors.len());
            assert_eq!(pos, errors[0].pos);
            assert_eq!(msg, errors[0].msg);
        });
    }

    pub fn errors(code: &'static str, vec: &[(Position, ErrorMessage)]) {
        test::check(code, |vm| {
            let diag = vm.diag.lock();
            let errors = diag.errors();

            println!("errors = {:?}", errors);
            assert_eq!(vec.len(), errors.len());

            for (ind, error) in errors.iter().enumerate() {
                assert_eq!(vec[ind].0, error.pos);
                assert_eq!(vec[ind].1, error.msg);
            }
        });
    }

    pub fn pos(line: u32, col: u32) -> Position {
        Position::new(line, col)
    }
}
<|endoftext|>