<commit_before>use mio::{Evented,Poll,PollOpt,Ready,Token};
use mio_uds::UnixStream;
use std::fmt::Debug;
use std::iter::Iterator;
use std::str::from_utf8;
use std::marker::PhantomData;
use std::io::{self,Read,Write,ErrorKind};
use std::os::unix::net;
use std::os::unix::io::{AsRawFd,FromRawFd,IntoRawFd,RawFd};
use std::cmp::min;
use serde_json;
use serde::ser::Serialize;
use serde::de::DeserializeOwned;

use network::buffer::Buffer;

#[derive(Debug,PartialEq)]
pub enum ConnError {
  Continue,
  ParseError,
  SocketError,
}

pub struct Channel<Tx,Rx> {
  pub sock:        UnixStream,
  front_buf:       Buffer,
  back_buf:        Buffer,
  max_buffer_size: usize,
  pub readiness:   Ready,
  pub interest:    Ready,
  blocking:        bool,
  phantom_tx:      PhantomData<Tx>,
  phantom_rx:      PhantomData<Rx>,
}

impl<Tx: Debug+Serialize, Rx: Debug+DeserializeOwned> Channel<Tx,Rx> {
  pub fn new(sock: UnixStream, buffer_size: usize, max_buffer_size: usize) -> Channel<Tx,Rx> {
    Channel {
      sock:            sock,
      front_buf:       Buffer::with_capacity(buffer_size),
      back_buf:        Buffer::with_capacity(buffer_size),
      max_buffer_size: max_buffer_size,
      readiness:       Ready::empty(),
      interest:        Ready::readable(),
      blocking:        false,
      phantom_tx:      PhantomData,
      phantom_rx:      PhantomData,
    }
  }

  pub fn into<Tx2: Debug+Serialize, Rx2: Debug+DeserializeOwned>(self) -> Channel<Tx2,Rx2> {
    Channel {
      sock:            self.sock,
      front_buf:       self.front_buf,
      back_buf:        self.back_buf,
      max_buffer_size: self.max_buffer_size,
      readiness:       self.readiness,
      interest:        self.interest,
      blocking:        self.blocking,
      phantom_tx:      PhantomData,
      phantom_rx:      PhantomData,
    }
  }

  pub fn set_nonblocking(&mut self, nonblocking: bool) {
    unsafe {
      let fd = self.sock.as_raw_fd();
      let stream = net::UnixStream::from_raw_fd(fd);
      stream.set_nonblocking(nonblocking);
      let fd = stream.into_raw_fd();
    }
    self.blocking = !nonblocking;
  }

  pub fn set_blocking(&mut self, blocking: bool) {
    self.set_nonblocking(!blocking)
  }

  pub fn fd(&self) -> RawFd {
    self.sock.as_raw_fd()
  }

  pub fn handle_events(&mut self, events: Ready) {
    self.readiness = self.readiness | events;
  }

  pub fn readiness(&self) -> Ready {
    self.readiness & self.interest
  }

  pub fn run(&mut self) {
    let interest = self.interest & self.readiness;

    if interest.is_readable() {
      self.readable();
    }

    if interest.is_writable() {
      self.writable();
    }
  }

  pub fn readable(&mut self) -> Result<usize,ConnError> {
    if !(self.interest & self.readiness).is_readable() {
      return Err(ConnError::Continue);
    }

    let mut count = 0usize;
    loop {
      let size = self.front_buf.available_space();
      if size == 0 {
        self.interest.remove(Ready::readable());
        break;
      }

      match self.sock.read(self.front_buf.space()) {
        Ok(0) => {
          break;
        },
        Err(e) => {
          match e.kind() {
            ErrorKind::WouldBlock => {
              self.readiness.remove(Ready::readable());
              break;
            },
            _ => {
              //log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error (kind: {:?}): {:?}", tok.0, code, e);
              self.interest  = Ready::empty();
              self.readiness = Ready::empty();
              return Err(ConnError::SocketError);
            }
          }
        },
        Ok(r) => {
          count += r;
          self.front_buf.fill(r);
          //debug!("UNIX CLIENT[{}] sent {} bytes: {:?}", tok.0, r, from_utf8(self.buf.data()));
        },
      };
    }

    Ok(count)
  }

  pub fn writable(&mut self) -> Result<usize,ConnError> {
    if !(self.interest & self.readiness).is_writable() {
      return Err(ConnError::Continue);
    }

    let mut count = 0usize;
    loop {
      let size = self.back_buf.available_data();
      if size == 0 {
        self.interest.remove(Ready::writable());
        break;
      }

      match self.sock.write(self.back_buf.data()) {
        Ok(0) => {
          break;
        },
        Ok(r) => {
          count += r;
          self.back_buf.consume(r);
        },
        Err(e) => {
          match e.kind() {
            ErrorKind::WouldBlock => {
              self.interest.remove(Ready::writable());
              break;
            },
            e => {
              error!("channel write error: {:?}", e);
              self.interest  = Ready::empty();
              self.readiness = Ready::empty();
              return Err(ConnError::SocketError);
            }
          }
        }
      }
    }

    Ok(count)
  }

  pub fn read_message(&mut self) -> Option<Rx> {
    if self.blocking {
      self.read_message_blocking()
    } else {
      self.read_message_nonblocking()
    }
  }

  pub fn read_message_nonblocking(&mut self) -> Option<Rx> {
    if let Some(pos) = self.front_buf.data().iter().position(|&x| x == 0) {
      let mut res = None;

      if let Ok(s) = from_utf8(&self.front_buf.data()[..pos]) {
        match serde_json::from_str(s) {
          Ok(message) => res = Some(message),
          Err(e) => error!("could not parse message (error={:?}), ignoring:\n{}", e, s),
        }
      } else {
        error!("invalid utf-8 encoding in command message, ignoring");
      }

      self.front_buf.consume(pos+1);
      res
    } else {
      if self.front_buf.available_space() == 0 {
        if self.front_buf.capacity() == self.max_buffer_size {
          error!("command buffer full, cannot grow more, ignoring");
        } else {
          let new_size = min(self.front_buf.capacity()+5000, self.max_buffer_size);
          self.front_buf.grow(new_size);
        }
      }

      self.interest.insert(Ready::readable());
      None
    }
  }

  pub fn read_message_blocking(&mut self) -> Option<Rx> {
    loop {
      if let Some(pos) = self.front_buf.data().iter().position(|&x| x == 0) {
        let mut res = None;

        if let Ok(s) = from_utf8(&self.front_buf.data()[..pos]) {
          match serde_json::from_str(s) {
            Ok(message) => res = Some(message),
            Err(e) => error!("could not parse message (error={:?}), ignoring:\n{}", e, s),
          }
        } else {
          error!("invalid utf-8 encoding in command message, ignoring");
        }

        self.front_buf.consume(pos+1);
        return res;
      } else {
        if self.front_buf.available_space() == 0 {
          if self.front_buf.capacity() == self.max_buffer_size {
            error!("command buffer full, cannot grow more, ignoring");
            return None;
          } else {
            let new_size = min(self.front_buf.capacity()+5000, self.max_buffer_size);
            self.front_buf.grow(new_size);
          }
        }

        match self.sock.read(self.front_buf.space()) {
          Ok(0) => {
          },
          Err(_) => { return None; },
          Ok(r) => {
            self.front_buf.fill(r);
          },
        };
      }
    }
  }

  pub fn write_message(&mut self, message: &Tx) -> bool {
    if self.blocking {
      self.write_message_blocking(message)
    } else {
      self.write_message_nonblocking(message)
    }
  }

  pub fn write_message_nonblocking(&mut self, message: &Tx) -> bool {
    let message = &serde_json::to_string(message).map(|s| s.into_bytes()).unwrap_or(vec!());

    let msg_len = message.len() + 1;
    if msg_len > self.back_buf.available_space() {
      self.back_buf.shift();
    }

    if msg_len > self.back_buf.available_space() {
      if msg_len - self.back_buf.available_space() + self.back_buf.capacity() > self.max_buffer_size {
        error!("message is too large to write to back buffer. Consider increasing proxy channel buffer size, current value is {}", self.back_buf.capacity());
        return false;
      }

      let new_len = msg_len - self.back_buf.available_space() + self.back_buf.capacity();
      self.back_buf.grow( new_len );
    }

    self.back_buf.write(message);
    self.back_buf.write(&b"\0"[..]);
    self.interest.insert(Ready::writable());

    true
  }

  pub fn write_message_blocking(&mut self, message: &Tx) -> bool {
    let message = &serde_json::to_string(message).map(|s| s.into_bytes()).unwrap_or(vec!());

    let msg_len = message.len() + 1;
    if msg_len > self.back_buf.available_space() {
      self.back_buf.shift();
    }

    if msg_len > self.back_buf.available_space() {
      if msg_len - self.back_buf.available_space() + self.back_buf.capacity() > self.max_buffer_size {
        error!("message is too large to write to back buffer. Consider increasing proxy channel buffer size, current value is {}", self.back_buf.capacity());
        return false;
      }

      let new_len = msg_len - self.back_buf.available_space() + self.back_buf.capacity();
      self.back_buf.grow( new_len );
    }

    self.back_buf.write(message);
    self.back_buf.write(&b"\0"[..]);

    loop {
      let size = self.back_buf.available_data();
      if size == 0 {
        break;
      }

      match self.sock.write(self.back_buf.data()) {
        Ok(r) => {
          self.back_buf.consume(r);
        },
        Err(_) => {
          return true;
        }
      }
    }
    true
  }
}

impl<Tx: Debug+DeserializeOwned+Serialize, Rx: Debug+DeserializeOwned+Serialize> Channel<Tx,Rx> {
  pub fn generate(buffer_size: usize, max_buffer_size: usize) -> io::Result<(Channel<Tx,Rx>, Channel<Rx,Tx>)> {
    let     (command,proxy) = try!(UnixStream::pair());
    let     proxy_channel   = Channel::new(proxy, buffer_size, max_buffer_size);
    let mut command_channel = Channel::new(command, buffer_size, max_buffer_size);
    command_channel.set_nonblocking(false);
    Ok((command_channel, proxy_channel))
  }

  pub fn generate_nonblocking(buffer_size: usize, max_buffer_size: usize) -> io::Result<(Channel<Tx,Rx>, Channel<Rx,Tx>)> {
    let (command,proxy) = try!(UnixStream::pair());
    let proxy_channel   = Channel::new(proxy, buffer_size, max_buffer_size);
    let command_channel = Channel::new(command, buffer_size, max_buffer_size);
    Ok((command_channel, proxy_channel))
  }
}

impl<Tx: Debug+Serialize, Rx: Debug+DeserializeOwned> Iterator for Channel<Tx,Rx> {
  type Item = Rx;
  fn next(&mut self) -> Option<Self::Item> {
    self.read_message()
  }
}

impl<Tx,Rx> Evented for Channel<Tx,Rx> {
  fn register(&self,
              poll: &Poll,
              token: Token,
              interest: Ready,
              opts: PollOpt)
              -> io::Result<()> {
    self.sock.register(poll, token, interest, opts)
  }

  fn reregister(&self,
                poll: &Poll,
                token: Token,
                interest: Ready,
                opts: PollOpt)
                -> io::Result<()> {
    self.sock.reregister(poll, token, interest, opts)
  }

  fn deregister(&self, poll: &Poll) -> io::Result<()> {
    self.sock.deregister(poll)
  }
}
<commit_msg>update readiness, not interest, when we get WouldBlock<commit_after>use mio::{Evented,Poll,PollOpt,Ready,Token};
use mio_uds::UnixStream;
use std::fmt::Debug;
use std::iter::Iterator;
use std::str::from_utf8;
use std::marker::PhantomData;
use std::io::{self,Read,Write,ErrorKind};
use std::os::unix::net;
use std::os::unix::io::{AsRawFd,FromRawFd,IntoRawFd,RawFd};
use std::cmp::min;
use serde_json;
use serde::ser::Serialize;
use serde::de::DeserializeOwned;

use network::buffer::Buffer;

#[derive(Debug,PartialEq)]
pub enum ConnError {
  Continue,
  ParseError,
  SocketError,
}

pub struct Channel<Tx,Rx> {
  pub sock:        UnixStream,
  front_buf:       Buffer,
  back_buf:        Buffer,
  max_buffer_size: usize,
  pub readiness:   Ready,
  pub interest:    Ready,
  blocking:        bool,
  phantom_tx:      PhantomData<Tx>,
  phantom_rx:      PhantomData<Rx>,
}

impl<Tx: Debug+Serialize, Rx: Debug+DeserializeOwned> Channel<Tx,Rx> {
  pub fn new(sock: UnixStream, buffer_size: usize, max_buffer_size: usize) -> Channel<Tx,Rx> {
    Channel {
      sock:            sock,
      front_buf:       Buffer::with_capacity(buffer_size),
      back_buf:        Buffer::with_capacity(buffer_size),
      max_buffer_size: max_buffer_size,
      readiness:       Ready::empty(),
      interest:        Ready::readable(),
      blocking:        false,
      phantom_tx:      PhantomData,
      phantom_rx:      PhantomData,
    }
  }

  pub fn into<Tx2: Debug+Serialize, Rx2: Debug+DeserializeOwned>(self) -> Channel<Tx2,Rx2> {
    Channel {
      sock:            self.sock,
      front_buf:       self.front_buf,
      back_buf:        self.back_buf,
      max_buffer_size: self.max_buffer_size,
      readiness:       self.readiness,
      interest:        self.interest,
      blocking:        self.blocking,
      phantom_tx:      PhantomData,
      phantom_rx:      PhantomData,
    }
  }

  pub fn set_nonblocking(&mut self, nonblocking: bool) {
    unsafe {
      let fd = self.sock.as_raw_fd();
      let stream = net::UnixStream::from_raw_fd(fd);
      stream.set_nonblocking(nonblocking);
      let fd = stream.into_raw_fd();
    }
    self.blocking = !nonblocking;
  }

  pub fn set_blocking(&mut self, blocking: bool) {
    self.set_nonblocking(!blocking)
  }

  pub fn fd(&self) -> RawFd {
    self.sock.as_raw_fd()
  }

  pub fn handle_events(&mut self, events: Ready) {
    self.readiness = self.readiness | events;
  }

  pub fn readiness(&self) -> Ready {
    self.readiness & self.interest
  }

  pub fn run(&mut self) {
    let interest = self.interest & self.readiness;

    if interest.is_readable() {
      self.readable();
    }

    if interest.is_writable() {
      self.writable();
    }
  }

  pub fn readable(&mut self) -> Result<usize,ConnError> {
    if !(self.interest & self.readiness).is_readable() {
      return Err(ConnError::Continue);
    }

    let mut count = 0usize;
    loop {
      let size = self.front_buf.available_space();
      if size == 0 {
        self.interest.remove(Ready::readable());
        break;
      }

      match self.sock.read(self.front_buf.space()) {
        Ok(0) => {
          break;
        },
        Err(e) => {
          match e.kind() {
            ErrorKind::WouldBlock => {
              self.readiness.remove(Ready::readable());
              break;
            },
            _ => {
              //log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error (kind: {:?}): {:?}", tok.0, code, e);
              self.interest  = Ready::empty();
              self.readiness = Ready::empty();
              return Err(ConnError::SocketError);
            }
          }
        },
        Ok(r) => {
          count += r;
          self.front_buf.fill(r);
          //debug!("UNIX CLIENT[{}] sent {} bytes: {:?}", tok.0, r, from_utf8(self.buf.data()));
        },
      };
    }

    Ok(count)
  }

  pub fn writable(&mut self) -> Result<usize,ConnError> {
    if !(self.interest & self.readiness).is_writable() {
      return Err(ConnError::Continue);
    }

    let mut count = 0usize;
    loop {
      let size = self.back_buf.available_data();
      if size == 0 {
        self.interest.remove(Ready::writable());
        break;
      }

      match self.sock.write(self.back_buf.data()) {
        Ok(0) => {
          break;
        },
        Ok(r) => {
          count += r;
          self.back_buf.consume(r);
        },
        Err(e) => {
          match e.kind() {
            ErrorKind::WouldBlock => {
              self.readiness.remove(Ready::writable());
              break;
            },
            e => {
              error!("channel write error: {:?}", e);
              self.interest  = Ready::empty();
              self.readiness = Ready::empty();
              return Err(ConnError::SocketError);
            }
          }
        }
      }
    }

    Ok(count)
  }

  pub fn read_message(&mut self) -> Option<Rx> {
    if self.blocking {
      self.read_message_blocking()
    } else {
      self.read_message_nonblocking()
    }
  }

  pub fn read_message_nonblocking(&mut self) -> Option<Rx> {
    if let Some(pos) = self.front_buf.data().iter().position(|&x| x == 0) {
      let mut res = None;

      if let Ok(s) = from_utf8(&self.front_buf.data()[..pos]) {
        match serde_json::from_str(s) {
          Ok(message) => res = Some(message),
          Err(e) => error!("could not parse message (error={:?}), ignoring:\n{}", e, s),
        }
      } else {
        error!("invalid utf-8 encoding in command message, ignoring");
      }

      self.front_buf.consume(pos+1);
      res
    } else {
      if self.front_buf.available_space() == 0 {
        if self.front_buf.capacity() == self.max_buffer_size {
          error!("command buffer full, cannot grow more, ignoring");
        } else {
          let new_size = min(self.front_buf.capacity()+5000, self.max_buffer_size);
          self.front_buf.grow(new_size);
        }
      }

      self.interest.insert(Ready::readable());
      None
    }
  }

  pub fn read_message_blocking(&mut self) -> Option<Rx> {
    loop {
      if let Some(pos) = self.front_buf.data().iter().position(|&x| x == 0) {
        let mut res = None;

        if let Ok(s) = from_utf8(&self.front_buf.data()[..pos]) {
          match serde_json::from_str(s) {
            Ok(message) => res = Some(message),
            Err(e) => error!("could not parse message (error={:?}), ignoring:\n{}", e, s),
          }
        } else {
          error!("invalid utf-8 encoding in command message, ignoring");
        }

        self.front_buf.consume(pos+1);
        return res;
      } else {
        if self.front_buf.available_space() == 0 {
          if self.front_buf.capacity() == self.max_buffer_size {
            error!("command buffer full, cannot grow more, ignoring");
            return None;
          } else {
            let new_size = min(self.front_buf.capacity()+5000, self.max_buffer_size);
            self.front_buf.grow(new_size);
          }
        }

        match self.sock.read(self.front_buf.space()) {
          Ok(0) => {
          },
          Err(_) => { return None; },
          Ok(r) => {
            self.front_buf.fill(r);
          },
        };
      }
    }
  }

  pub fn write_message(&mut self, message: &Tx) -> bool {
    if self.blocking {
      self.write_message_blocking(message)
    } else {
      self.write_message_nonblocking(message)
    }
  }

  pub fn write_message_nonblocking(&mut self, message: &Tx) -> bool {
    let message = &serde_json::to_string(message).map(|s| s.into_bytes()).unwrap_or(vec!());

    let msg_len = message.len() + 1;
    if msg_len > self.back_buf.available_space() {
      self.back_buf.shift();
    }

    if msg_len > self.back_buf.available_space() {
      if msg_len - self.back_buf.available_space() + self.back_buf.capacity() > self.max_buffer_size {
        error!("message is too large to write to back buffer. Consider increasing proxy channel buffer size, current value is {}", self.back_buf.capacity());
        return false;
      }

      let new_len = msg_len - self.back_buf.available_space() + self.back_buf.capacity();
      self.back_buf.grow( new_len );
    }

    self.back_buf.write(message);
    self.back_buf.write(&b"\0"[..]);
    self.interest.insert(Ready::writable());

    true
  }

  pub fn write_message_blocking(&mut self, message: &Tx) -> bool {
    let message = &serde_json::to_string(message).map(|s| s.into_bytes()).unwrap_or(vec!());

    let msg_len = message.len() + 1;
    if msg_len > self.back_buf.available_space() {
      self.back_buf.shift();
    }

    if msg_len > self.back_buf.available_space() {
      if msg_len - self.back_buf.available_space() + self.back_buf.capacity() > self.max_buffer_size {
        error!("message is too large to write to back buffer. Consider increasing proxy channel buffer size, current value is {}", self.back_buf.capacity());
        return false;
      }

      let new_len = msg_len - self.back_buf.available_space() + self.back_buf.capacity();
      self.back_buf.grow( new_len );
    }

    self.back_buf.write(message);
    self.back_buf.write(&b"\0"[..]);

    loop {
      let size = self.back_buf.available_data();
      if size == 0 {
        break;
      }

      match self.sock.write(self.back_buf.data()) {
        Ok(r) => {
          self.back_buf.consume(r);
        },
        Err(_) => {
          return true;
        }
      }
    }
    true
  }
}

impl<Tx: Debug+DeserializeOwned+Serialize, Rx: Debug+DeserializeOwned+Serialize> Channel<Tx,Rx> {
  pub fn generate(buffer_size: usize, max_buffer_size: usize) -> io::Result<(Channel<Tx,Rx>, Channel<Rx,Tx>)> {
    let     (command,proxy) = try!(UnixStream::pair());
    let     proxy_channel   = Channel::new(proxy, buffer_size, max_buffer_size);
    let mut command_channel = Channel::new(command, buffer_size, max_buffer_size);
    command_channel.set_nonblocking(false);
    Ok((command_channel, proxy_channel))
  }

  pub fn generate_nonblocking(buffer_size: usize, max_buffer_size: usize) -> io::Result<(Channel<Tx,Rx>, Channel<Rx,Tx>)> {
    let (command,proxy) = try!(UnixStream::pair());
    let proxy_channel   = Channel::new(proxy, buffer_size, max_buffer_size);
    let command_channel = Channel::new(command, buffer_size, max_buffer_size);
    Ok((command_channel, proxy_channel))
  }
}

impl<Tx: Debug+Serialize, Rx: Debug+DeserializeOwned> Iterator for Channel<Tx,Rx> {
  type Item = Rx;
  fn next(&mut self) -> Option<Self::Item> {
    self.read_message()
  }
}

impl<Tx,Rx> Evented for Channel<Tx,Rx> {
  fn register(&self,
              poll: &Poll,
              token: Token,
              interest: Ready,
              opts: PollOpt)
              -> io::Result<()> {
    self.sock.register(poll, token, interest, opts)
  }

  fn reregister(&self,
                poll: &Poll,
                token: Token,
                interest: Ready,
                opts: PollOpt)
                -> io::Result<()> {
    self.sock.reregister(poll, token, interest, opts)
  }

  fn deregister(&self, poll: &Poll) -> io::Result<()> {
    self.sock.deregister(poll)
  }
}
<|endoftext|>


<commit_before>//! Cost calculation logic

use bigint::{M256, U256, Gas, Address};

#[cfg(feature = "std")] use std::cmp::max;
#[cfg(not(feature = "std"))] use core::cmp::max;

use ::{Memory, Instruction, Patch};
use super::State;

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_JUMPDEST: usize = 1;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SCLEAR: usize = 15000;
const R_SUICIDE: usize = 24000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSIT: usize = 200;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_MEMORY: usize = 3;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;

fn sstore_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>) -> Gas {
    let index: U256 = machine.stack.peek(0).unwrap().into();
    let value = machine.stack.peek(1).unwrap();
    let address = machine.context.address;

    if value != M256::zero() && machine.account_state.storage_read(address, index).unwrap() == M256::zero() {
        G_SSET.into()
    } else {
        G_SRESET.into()
    }
}

fn call_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    Gas::from(P::gas_call()) + xfer_cost(machine, instruction) + new_cost(machine, instruction)
}

fn xfer_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    if instruction == &Instruction::CALL || instruction == &Instruction::CALLCODE {
        let val = machine.stack.peek(2).unwrap();
        if val != M256::zero() {
            G_CALLVALUE.into()
        } else {
            Gas::zero()
        }
    } else {
        Gas::zero()
    }
}

fn new_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    let address: Address = machine.stack.peek(1).unwrap().into();
    if (instruction == &Instruction::CALL || instruction == &Instruction::STATICCALL) && !machine.account_state.exists(address).unwrap() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    }
}

fn suicide_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>) -> Gas {
    let address: Address = machine.stack.peek(0).unwrap().into();
    Gas::from(P::gas_suicide()) + if !machine.account_state.exists(address).unwrap() {
        Gas::from(P::gas_suicide_new_account())
    } else {
        Gas::zero()
    }
}

fn memory_expand(current: Gas, from: Gas, len: Gas) -> Gas {
    if len == Gas::zero() {
        return current;
    }

    let rem = (from + len) % Gas::from(32u64);
    let new = if rem == Gas::zero() {
        (from + len) / Gas::from(32u64)
    } else {
        (from + len) / Gas::from(32u64) + Gas::from(1u64)
    };
    max(current, new)
}

/// Calculate code deposit cost for a ContractCreation transaction.
pub fn code_deposit_gas(len: usize) -> Gas {
    Gas::from(G_CODEDEPOSIT) * Gas::from(len)
}

/// Calculate the memory gas from the memory cost.
pub fn memory_gas(a: Gas) -> Gas {
    (Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)).into()
}

/// Calculate the memory cost. This is the same as the active memory
/// length in the Yellow Paper.
pub fn memory_cost<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    let ref stack = state.stack;

    let current = state.memory_cost;
    let next = match instruction {
        Instruction::SHA3 | Instruction::RETURN | Instruction::REVERT | Instruction::LOG(_) => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(1).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::CODECOPY | Instruction::CALLDATACOPY | Instruction::RETURNDATACOPY => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::EXTCODECOPY => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(3).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::MLOAD | Instruction::MSTORE => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(32u64))
        },
        Instruction::MSTORE8 => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(1u64))
        },
        Instruction::CREATE => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::CALL => {
            let in_from: U256 = stack.peek(3).unwrap().into();
            let in_len: U256 = stack.peek(4).unwrap().into();
            let out_from: U256 = stack.peek(5).unwrap().into();
            let out_len: U256 = stack.peek(6).unwrap().into();
            memory_expand(memory_expand(current, Gas::from(in_from), Gas::from(in_len)),
                          Gas::from(out_from), Gas::from(out_len))
        },
        _ => {
            current
        }
    };
    next
}

/// Calculate the gas cost.
pub fn gas_cost<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    match instruction {
        Instruction::CALL => call_cost::<M, P>(state, &Instruction::CALL),
        Instruction::CALLCODE => call_cost::<M, P>(state, &Instruction::CALLCODE),
        Instruction::DELEGATECALL => call_cost::<M, P>(state, &Instruction::DELEGATECALL),
        Instruction::STATICCALL => call_cost::<M, P>(state, &Instruction::STATICCALL),
        Instruction::SUICIDE => suicide_cost::<M, P>(state),
        Instruction::SSTORE => sstore_cost(state),

        Instruction::SHA3 => {
            let len = state.stack.peek(1).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::LOG(v) => {
            let len = state.stack.peek(1).unwrap();
            (Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)).into()
        },

        Instruction::EXTCODECOPY => {
            let len = state.stack.peek(3).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(P::gas_extcode()) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::CALLDATACOPY | Instruction::CODECOPY | Instruction::RETURNDATACOPY => {
            let len = state.stack.peek(2).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_VERYLOW) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::EXP => {
            if state.stack.peek(1).unwrap() == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + Gas::from(P::gas_expbyte()) * (Gas::from(1u64) + Gas::from(state.stack.peek(1).unwrap().log2floor()) / Gas::from(8u64))
            }
        }

        Instruction::CREATE => G_CREATE.into(),
        Instruction::JUMPDEST => G_JUMPDEST.into(),
        Instruction::SLOAD => P::gas_sload(),

        // W_zero
        Instruction::STOP | Instruction::RETURN | Instruction::REVERT
            => G_ZERO.into(),

        // W_base
        Instruction::ADDRESS | Instruction::ORIGIN | Instruction::CALLER |
        Instruction::CALLVALUE | Instruction::CALLDATASIZE | Instruction::RETURNDATASIZE |
        Instruction::CODESIZE | Instruction::GASPRICE | Instruction::COINBASE |
        Instruction::TIMESTAMP | Instruction::NUMBER | Instruction::DIFFICULTY |
        Instruction::GASLIMIT | Instruction::POP | Instruction::PC |
        Instruction::MSIZE | Instruction::GAS
            => G_BASE.into(),

        // W_verylow
        Instruction::ADD | Instruction::SUB | Instruction::NOT | Instruction::LT |
        Instruction::GT | Instruction::SLT | Instruction::SGT | Instruction::EQ |
        Instruction::ISZERO | Instruction::AND | Instruction::OR | Instruction::XOR |
        Instruction::BYTE | Instruction::CALLDATALOAD | Instruction::MLOAD |
        Instruction::MSTORE | Instruction::MSTORE8 | Instruction::PUSH(_) |
        Instruction::DUP(_) | Instruction::SWAP(_)
            => G_VERYLOW.into(),

        // W_low
        Instruction::MUL | Instruction::DIV | Instruction::SDIV | Instruction::MOD |
        Instruction::SMOD | Instruction::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Instruction::ADDMOD | Instruction::MULMOD | Instruction::JUMP
            => G_MID.into(),

        // W_high
        Instruction::JUMPI => G_HIGH.into(),

        // W_extcode
        Instruction::EXTCODESIZE => P::gas_extcode(),
        Instruction::BALANCE => P::gas_balance(),
        Instruction::BLOCKHASH => G_BLOCKHASH.into(),
    }
}

/// Raise gas stipend for CALL and CALLCODE instruction.
pub fn gas_stipend<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE => {
            let value = state.stack.peek(2).unwrap();

            if value != M256::zero() {
                G_CALLSTIPEND.into()
            } else {
                Gas::zero()
            }
        },
        _ => Gas::zero(),
    }
}

/// Calculate the refunded gas.
pub fn gas_refund<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    match instruction {
        Instruction::SSTORE => {
            let index: U256 = state.stack.peek(0).unwrap().into();
            let value = state.stack.peek(1).unwrap();
            let address = state.context.address;

            if value == M256::zero() && state.account_state.storage_read(address, index).unwrap() != M256::zero() {
                Gas::from(R_SCLEAR)
            } else {
                Gas::zero()
            }
        },
        Instruction::SUICIDE => {
            if state.removed.contains(&state.context.address) {
                Gas::zero()
            } else {
                Gas::from(R_SUICIDE)
            }
        },
        _ => Gas::zero()
    }
}
<commit_msg>add CALLCODE in CALL branch of gas calculation match statement<commit_after>//! Cost calculation logic

use bigint::{M256, U256, Gas, Address};

#[cfg(feature = "std")] use std::cmp::max;
#[cfg(not(feature = "std"))] use core::cmp::max;

use ::{Memory, Instruction, Patch};
use super::State;

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_JUMPDEST: usize = 1;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SCLEAR: usize = 15000;
const R_SUICIDE: usize = 24000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSIT: usize = 200;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_MEMORY: usize = 3;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;

fn sstore_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>) -> Gas {
    let index: U256 = machine.stack.peek(0).unwrap().into();
    let value = machine.stack.peek(1).unwrap();
    let address = machine.context.address;

    if value != M256::zero() && machine.account_state.storage_read(address, index).unwrap() == M256::zero() {
        G_SSET.into()
    } else {
        G_SRESET.into()
    }
}

fn call_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    Gas::from(P::gas_call()) + xfer_cost(machine, instruction) + new_cost(machine, instruction)
}

fn xfer_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    if instruction == &Instruction::CALL || instruction == &Instruction::CALLCODE {
        let val = machine.stack.peek(2).unwrap();
        if val != M256::zero() {
            G_CALLVALUE.into()
        } else {
            Gas::zero()
        }
    } else {
        Gas::zero()
    }
}

fn new_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    let address: Address = machine.stack.peek(1).unwrap().into();
    if (instruction == &Instruction::CALL || instruction == &Instruction::STATICCALL) && !machine.account_state.exists(address).unwrap() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    }
}

fn suicide_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>) -> Gas {
    let address: Address = machine.stack.peek(0).unwrap().into();
    Gas::from(P::gas_suicide()) + if !machine.account_state.exists(address).unwrap() {
        Gas::from(P::gas_suicide_new_account())
    } else {
        Gas::zero()
    }
}

fn memory_expand(current: Gas, from: Gas, len: Gas) -> Gas {
    if len == Gas::zero() {
        return current;
    }

    let rem = (from + len) % Gas::from(32u64);
    let new = if rem == Gas::zero() {
        (from + len) / Gas::from(32u64)
    } else {
        (from + len) / Gas::from(32u64) + Gas::from(1u64)
    };
    max(current, new)
}

/// Calculate code deposit cost for a ContractCreation transaction.
pub fn code_deposit_gas(len: usize) -> Gas {
    Gas::from(G_CODEDEPOSIT) * Gas::from(len)
}

/// Calculate the memory gas from the memory cost.
pub fn memory_gas(a: Gas) -> Gas {
    (Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)).into()
}

/// Calculate the memory cost. This is the same as the active memory
/// length in the Yellow Paper.
pub fn memory_cost<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    let ref stack = state.stack;

    let current = state.memory_cost;
    let next = match instruction {
        Instruction::SHA3 | Instruction::RETURN | Instruction::REVERT | Instruction::LOG(_) => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(1).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::CODECOPY | Instruction::CALLDATACOPY | Instruction::RETURNDATACOPY => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::EXTCODECOPY => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(3).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::MLOAD | Instruction::MSTORE => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(32u64))
        },
        Instruction::MSTORE8 => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(1u64))
        },
        Instruction::CREATE => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::CALL | Instruction::CALLCODE => {
            let in_from: U256 = stack.peek(3).unwrap().into();
            let in_len: U256 = stack.peek(4).unwrap().into();
            let out_from: U256 = stack.peek(5).unwrap().into();
            let out_len: U256 = stack.peek(6).unwrap().into();
            memory_expand(memory_expand(current, Gas::from(in_from), Gas::from(in_len)),
                          Gas::from(out_from), Gas::from(out_len))
        },
        _ => {
            current
        }
    };
    next
}

/// Calculate the gas cost.
pub fn gas_cost<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    match instruction {
        Instruction::CALL => call_cost::<M, P>(state, &Instruction::CALL),
        Instruction::CALLCODE => call_cost::<M, P>(state, &Instruction::CALLCODE),
        Instruction::DELEGATECALL => call_cost::<M, P>(state, &Instruction::DELEGATECALL),
        Instruction::STATICCALL => call_cost::<M, P>(state, &Instruction::STATICCALL),
        Instruction::SUICIDE => suicide_cost::<M, P>(state),
        Instruction::SSTORE => sstore_cost(state),

        Instruction::SHA3 => {
            let len = state.stack.peek(1).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::LOG(v) => {
            let len = state.stack.peek(1).unwrap();
            (Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)).into()
        },

        Instruction::EXTCODECOPY => {
            let len = state.stack.peek(3).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(P::gas_extcode()) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::CALLDATACOPY | Instruction::CODECOPY | Instruction::RETURNDATACOPY => {
            let len = state.stack.peek(2).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_VERYLOW) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::EXP => {
            if state.stack.peek(1).unwrap() == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + Gas::from(P::gas_expbyte()) * (Gas::from(1u64) + Gas::from(state.stack.peek(1).unwrap().log2floor()) / Gas::from(8u64))
            }
        }

        Instruction::CREATE => G_CREATE.into(),
        Instruction::JUMPDEST => G_JUMPDEST.into(),
        Instruction::SLOAD => P::gas_sload(),

        // W_zero
        Instruction::STOP | Instruction::RETURN | Instruction::REVERT
            => G_ZERO.into(),

        // W_base
        Instruction::ADDRESS | Instruction::ORIGIN | Instruction::CALLER |
        Instruction::CALLVALUE | Instruction::CALLDATASIZE | Instruction::RETURNDATASIZE |
        Instruction::CODESIZE | Instruction::GASPRICE | Instruction::COINBASE |
        Instruction::TIMESTAMP | Instruction::NUMBER | Instruction::DIFFICULTY |
        Instruction::GASLIMIT | Instruction::POP | Instruction::PC |
        Instruction::MSIZE | Instruction::GAS
            => G_BASE.into(),

        // W_verylow
        Instruction::ADD | Instruction::SUB | Instruction::NOT | Instruction::LT |
        Instruction::GT | Instruction::SLT | Instruction::SGT | Instruction::EQ |
        Instruction::ISZERO | Instruction::AND | Instruction::OR | Instruction::XOR |
        Instruction::BYTE | Instruction::CALLDATALOAD | Instruction::MLOAD |
        Instruction::MSTORE | Instruction::MSTORE8 | Instruction::PUSH(_) |
        Instruction::DUP(_) | Instruction::SWAP(_)
            => G_VERYLOW.into(),

        // W_low
        Instruction::MUL | Instruction::DIV | Instruction::SDIV | Instruction::MOD |
        Instruction::SMOD | Instruction::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Instruction::ADDMOD | Instruction::MULMOD | Instruction::JUMP
            => G_MID.into(),

        // W_high
        Instruction::JUMPI => G_HIGH.into(),

        // W_extcode
        Instruction::EXTCODESIZE => P::gas_extcode(),
        Instruction::BALANCE => P::gas_balance(),
        Instruction::BLOCKHASH => G_BLOCKHASH.into(),
    }
}

/// Raise gas stipend for CALL and CALLCODE instruction.
pub fn gas_stipend<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE => {
            let value = state.stack.peek(2).unwrap();

            if value != M256::zero() {
                G_CALLSTIPEND.into()
            } else {
                Gas::zero()
            }
        },
        _ => Gas::zero(),
    }
}

/// Calculate the refunded gas.
pub fn gas_refund<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    match instruction {
        Instruction::SSTORE => {
            let index: U256 = state.stack.peek(0).unwrap().into();
            let value = state.stack.peek(1).unwrap();
            let address = state.context.address;

            if value == M256::zero() && state.account_state.storage_read(address, index).unwrap() != M256::zero() {
                Gas::from(R_SCLEAR)
            } else {
                Gas::zero()
            }
        },
        Instruction::SUICIDE => {
            if state.removed.contains(&state.context.address) {
                Gas::zero()
            } else {
                Gas::from(R_SUICIDE)
            }
        },
        _ => Gas::zero()
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use core::*;

struct SymbolTable {
    pub table: HashMap<String, Option<Epiq>>,
}

pub struct Evaluator<'a> {
    ast :&'a RefCell<AbstractSyntaxTree>,
    symbol_table: SymbolTable,
}

impl<'a> Evaluator<'a> {
    pub fn new(ast :&'a RefCell<AbstractSyntaxTree>) -> Evaluator {
        Evaluator{ ast: ast, symbol_table: SymbolTable{ table: HashMap::new() } }
    }

    pub fn eval(&mut self) -> Option<&RefCell<AbstractSyntaxTree>> {
        let index;
        {
            let borrowed_ast = self.ast.borrow();
            index = borrowed_ast.entrypoint.unwrap();
        }
        let result = self.eval_internal(index);
        println!("max: {:?} index: {:?}", result, index);
        if result != index {
            // なんらかの変化があったので反映する必要がある
            // ここだと、entrypointを変更する
            let mut ast = self.ast.borrow_mut();
            (*ast).entrypoint = Some(result);
        }

        Some(self.ast)
    }

    fn eval_internal(&mut self, index: u32) -> u32 {
        let should_push = {
            let borrowed_ast = self.ast.borrow();
            let piq = borrowed_ast.get(index);

            match piq {
                &Epiq::Unit | &Epiq::Uit8(_) | &Epiq::Name(_) => false,
                &Epiq::Tpiq{ref o,p:_p,q:_q} => {
                    match o.as_ref() {
                        "#" => {
                            true
                        },
                        // block
                        r"\" => {
                            // TODO: 一つ目の環境の中身も、返す-1もひとまず無視する
                            // qのリストだけを逐次実行して、勝手に最後の値を返却するようにする
                            // ただ、そもそも、blockを評価しても実行されるわけではなく、
                            // 実行形式になるだけだ。
                            true
                        }
                        _ => false,
                    }
                },
            }
        };

        if should_push {
            // TODO: 実際のbindではなく、適当に固定値をbindしている
            let v = Epiq::Unit;

            // bind
            self.symbol_table.table.insert("abc".to_string(), Some(Epiq::Uit8(123)));

            // まずpushだけ
            self.ast.borrow_mut().push(v);
            self.ast.borrow().max_index.get()
        } else {
            index
        }
    }
}

#[test]
#[ignore]
fn test() {
    let ast = &RefCell::new(AbstractSyntaxTree::new());
    let mut evaluator = Evaluator::new(ast);
    evaluator.eval();
}

/*
fn beta_reduct(&mut self, entry: usize) {
    /*
    // 仮引数に実引数を入れる
    let mut a = vec![1, 3, 5];
    a.remove(1);
    a.insert(1, 2);
    println!("{:?}", a);

    // confirm that target is "application-piq"
    match self.vm.vctr.get(entry) {
        Some(&Epiq::Apiq { p: p1, q: q1 }) => {
            /* 引数をまず、lambdaの中に入れる */

            // ApiqのpはFpiqである必要がある(=ラムダ適用の左側はラムダ式でなければならない)
            match self.vm.vctr.get(p1) {
                Some(&Epiq::Fpiq { p: p2, q: q2 }) => {

                    // FpiqのpはPrmtである必要がある(=ラムダ式のは引数のシンボルが入る)
                    match self.vm.vctr.get(p2) {
                        Some(&Epiq::Prmt(_)) => {
                        },
                        Some(p3) => println!("not anonymous parameter {:?}", p3),
                        None => println!("{:?}", "index error"),
                    }
                },
                Some(p2) => println!("not function epiq {:?}", p2),
                None => println!("{:?}", "index error"),
            }

            println!("v.len(): {:?} entry: {:?}", self.vm.vctr.len(), entry);
        },
        Some(p1) => println!("not application epiq {:?}", p1),
        None => println!("{:?}", "index error"),
    }
    */

    let mut is_ok: (usize, usize) = (0, 0);

    match apiq_f((self, entry))
        // .and_then(aexp_e).and_then(pprn)
        .and_then(aexp_e).and_then(fpiq_p)
        // .and_then(aexp_e).and_then(pprn)
        .and_then(aexp_e) {
            Some(t) => {
                println!("{:?}", t.1);
                match apiq_q((self, entry)) {
                    Some(t2) => {
                        is_ok = (t.1, t2.1);
                    }
                    _ => {},
                }
            }
            None => {},
    }

    if is_ok != (0, 0) {
        self.vm.vctr.remove(is_ok.0);
        self.vm.vctr.insert(is_ok.0, Epiq::Prmt(is_ok.1));
    }
}
*/
<commit_msg>change eval logic a bit<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use core::*;

struct SymbolTable {
    pub table: HashMap<String, Option<Epiq>>,
}

pub struct Evaluator<'a> {
    ast :&'a RefCell<AbstractSyntaxTree>,
    symbol_table: SymbolTable,
}

impl<'a> Evaluator<'a> {
    pub fn new(ast :&'a RefCell<AbstractSyntaxTree>) -> Evaluator {
        Evaluator{ ast: ast, symbol_table: SymbolTable{ table: HashMap::new() } }
    }

    pub fn eval(&mut self) -> Option<&RefCell<AbstractSyntaxTree>> {
        let index;
        {
            let borrowed_ast = self.ast.borrow();
            index = borrowed_ast.entrypoint.unwrap();
        }
        let result = self.eval_internal(index);
        println!("max: {:?} index: {:?}", result, index);
        if result != index {
            // なんらかの変化があったので反映する必要がある
            // ここだと、entrypointを変更する
            let mut ast = self.ast.borrow_mut();
            (*ast).entrypoint = Some(result);
        }

        Some(self.ast)
    }

    fn eval_internal(&mut self, index: u32) -> u32 {
        if let Some(new_epiq) = {
            let borrowed_ast = self.ast.borrow();
            let piq = borrowed_ast.get(index);

            match piq {
                &Epiq::Unit | &Epiq::Uit8(_) | &Epiq::Name(_) => None,
                &Epiq::Tpiq{ref o,p:_p,q:_q} => {
                    match o.as_ref() {
                        "#" => {
                            // bind
                            // TODO: 実際のbindではなく、適当に固定値をbindしている
                            self.symbol_table.table.insert("abc".to_string(), Some(Epiq::Uit8(123)));

                            Some(Epiq::Unit)
                        },

                        // environment
                        "%" => {
                            Some(Tpiq)
                        },

                        // block
                        r"\" => {
                            // TODO: 一つ目の環境の中身も、返す-1もひとまず無視する
                            // qのリストだけを逐次実行して、勝手に最後の値を返却するようにする
                            // ただ、そもそも、blockを評価しても実行されるわけではなく、
                            // 実行形式になるだけだ。
                            None
                        }
                        _ => None,
                    }
                },
            }
        } {
            // まずpushだけ
            self.ast.borrow_mut().push(new_epiq);
            self.ast.borrow().max_index.get()
        } else {
            index
        }
    }
}

#[test]
#[ignore]
fn test() {
    let ast = &RefCell::new(AbstractSyntaxTree::new());
    let mut evaluator = Evaluator::new(ast);
    evaluator.eval();
}

/*
fn beta_reduct(&mut self, entry: usize) {
    /*
    // 仮引数に実引数を入れる
    let mut a = vec![1, 3, 5];
    a.remove(1);
    a.insert(1, 2);
    println!("{:?}", a);

    // confirm that target is "application-piq"
    match self.vm.vctr.get(entry) {
        Some(&Epiq::Apiq { p: p1, q: q1 }) => {
            /* 引数をまず、lambdaの中に入れる */

            // ApiqのpはFpiqである必要がある(=ラムダ適用の左側はラムダ式でなければならない)
            match self.vm.vctr.get(p1) {
                Some(&Epiq::Fpiq { p: p2, q: q2 }) => {

                    // FpiqのpはPrmtである必要がある(=ラムダ式のは引数のシンボルが入る)
                    match self.vm.vctr.get(p2) {
                        Some(&Epiq::Prmt(_)) => {
                        },
                        Some(p3) => println!("not anonymous parameter {:?}", p3),
                        None => println!("{:?}", "index error"),
                    }
                },
                Some(p2) => println!("not function epiq {:?}", p2),
                None => println!("{:?}", "index error"),
            }

            println!("v.len(): {:?} entry: {:?}", self.vm.vctr.len(), entry);
        },
        Some(p1) => println!("not application epiq {:?}", p1),
        None => println!("{:?}", "index error"),
    }
    */

    let mut is_ok: (usize, usize) = (0, 0);

    match apiq_f((self, entry))
        // .and_then(aexp_e).and_then(pprn)
        .and_then(aexp_e).and_then(fpiq_p)
        // .and_then(aexp_e).and_then(pprn)
        .and_then(aexp_e) {
            Some(t) => {
                println!("{:?}", t.1);
                match apiq_q((self, entry)) {
                    Some(t2) => {
                        is_ok = (t.1, t2.1);
                    }
                    _ => {},
                }
            }
            None => {},
    }

    if is_ok != (0, 0) {
        self.vm.vctr.remove(is_ok.0);
        self.vm.vctr.insert(is_ok.0, Epiq::Prmt(is_ok.1));
    }
}
*/
<|endoftext|>


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

/*!
Timer interface.

TimerConf is a MCU-specific struct.

Timers porvide a simple way to delay program executon for some time.
*/

#[cfg(mcu_lpc17xx)] pub use hal::lpc17xx::timer::TimerConf;
#[cfg(mcu_stm32f4)] pub use hal::stm32f4::timer::TimerConf;

#[path="../lib/wait_for.rs"] mod wait_for;

/// Timer implementation.
pub trait Timer {
  /// Implementation-specific method to wait a given number of microseconds.
  fn get_counter(&self) -> u32;

  #[inline(always)]
  /// Waits for specified number of microseconds.
  fn wait_us(&self, us: u32) {
    let start = self.get_counter();
    wait_for!((self.get_counter() - start) >= us);
  }

  #[inline(always)]
  /// Waits for specified number of milliseconds.
  fn wait_ms(&self, ms: u32) {
    self.wait_us(ms * 1000);
  }

  #[inline(always)]
  /// Waits for specified number of seconds.
  fn wait(&self, s: u32) {
    self.wait_us(s * 1000000);
  }
}
<commit_msg>Removed re-imports from hal timer<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
Timer interface.

TimerConf is a MCU-specific struct.

Timers porvide a simple way to delay program executon for some time.
*/

#[path="../lib/wait_for.rs"] mod wait_for;

/// Timer implementation.
pub trait Timer {
  /// Implementation-specific method to wait a given number of microseconds.
  fn get_counter(&self) -> u32;

  #[inline(always)]
  /// Waits for specified number of microseconds.
  fn wait_us(&self, us: u32) {
    let start = self.get_counter();
    wait_for!((self.get_counter() - start) >= us);
  }

  #[inline(always)]
  /// Waits for specified number of milliseconds.
  fn wait_ms(&self, ms: u32) {
    self.wait_us(ms * 1000);
  }

  #[inline(always)]
  /// Waits for specified number of seconds.
  fn wait(&self, s: u32) {
    self.wait_us(s * 1000000);
  }
}
<|endoftext|>


<commit_before>#[macro_escape]
macro_rules! wayland_protocol(
    ($name: expr, [$(($import: ident, $interface: ident)),*], [$(($prot_name:ident, $prot_import: ident, $prot_iface: ident)),*]) => {
        #[cfg(feature = "client")]
        pub use self::generated::client;

        #[cfg(feature = "server")]
        pub use self::generated::server;

        #[cfg(all(feature = "native_lib", any(feature = "client", feature = "server")))]
        pub use self::generated::c_interfaces;

        #[cfg(all(not(feature = "native_lib"), any(feature = "client", feature = "server")))]
        mod generated {
            #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
            #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
            #![allow(missing_docs)]

            #[cfg(feature = "client")]
            pub mod client {
                //! Client-side API of this protocol
                pub(crate) use wayland_client::{NewProxy, Proxy, ProxyMap};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{AnonymousObject, Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_client::protocol::{$($import),*};
                include!(concat!(env!("OUT_DIR"), "/", $name, "_rust_client_api.rs"));
            }

            #[cfg(feature = "server")]
            pub mod server {
                //! Server-side API of this protocol
                pub(crate) use wayland_server::{NewResource, Resource, ResourceMap};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{AnonymousObject, Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_server::protocol::{$($import),*};
                include!(concat!(env!("OUT_DIR"), "/", $name, "_rust_server_api.rs"));
            }
        }

        #[cfg(all(feature = "native_lib", any(feature = "client", feature = "server")))]
        mod generated {
            #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
            #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
            #![allow(missing_docs)]

            pub mod c_interfaces {
                //! C interfaces for this protocol

                // import client or server, both are the same anyway
                #[cfg(feature = "client")]
                pub use wayland_client::sys::protocol_interfaces::{$($interface),*};
                #[cfg(all(not(feature = "client"), feature = "server"))]
                pub use wayland_server::sys::protocol_interfaces::{$($interface),*};
                $(
                    pub(crate) use ::$prot_name::c_interfaces::$prot_iface;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_c_interfaces.rs"));
            }

            #[cfg(feature = "client")]
            pub mod client {
                //! Client-side API of this protocol
                pub(crate) use wayland_client::{NewProxy, Proxy, ProxyMap};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{AnonymousObject, Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_sys as sys;
                pub(crate) use wayland_client::protocol::{$($import),*};
                $(
                    pub(crate) use ::$prot_name::client::$prot_import;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_c_client_api.rs"));
            }

            #[cfg(feature = "server")]
            pub mod server {
                //! Server-side API of this protocol
                pub(crate) use wayland_server::{NewResource, Resource, ResourceMap};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{AnonymousObject, Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_sys as sys;
                pub(crate) use wayland_server::protocol::{$($import),*};
                $(
                    pub(crate) use ::$prot_name::server::$prot_import;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_c_server_api.rs"));
            }
        }
    }
);

#[cfg(feature = "unstable_protocols")]
#[macro_escape]
macro_rules! wayland_protocol_versioned(
    ($name: expr, [$($version: ident),*], $std_imports:tt, $prot_imports:tt) => {
        $(
            #[allow(missing_docs)]
            pub mod $version {
                wayland_protocol!(concat!($name, "-", stringify!($version)), $std_imports, $prot_imports);
            }
        )*
    }
);
<commit_msg>protocols: fix macro after rebase on d1466bf<commit_after>#[macro_escape]
macro_rules! wayland_protocol(
    ($name: expr, [$(($import: ident, $interface: ident)),*], [$(($prot_name:ident, $prot_import: ident, $prot_iface: ident)),*]) => {
        #[cfg(feature = "client")]
        pub use self::generated::client;

        #[cfg(feature = "server")]
        pub use self::generated::server;

        #[cfg(all(feature = "native_lib", any(feature = "client", feature = "server")))]
        pub use self::generated::c_interfaces;

        #[cfg(all(not(feature = "native_lib"), any(feature = "client", feature = "server")))]
        mod generated {
            #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
            #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
            #![allow(missing_docs)]

            #[cfg(feature = "client")]
            pub mod client {
                //! Client-side API of this protocol
                pub(crate) use wayland_client::{NewProxy, Proxy, ProxyMap};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{AnonymousObject, Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_client::protocol::{$($import),*};
                $(
                    pub(crate) use ::$prot_name::client::$prot_import;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_rust_client_api.rs"));
            }

            #[cfg(feature = "server")]
            pub mod server {
                //! Server-side API of this protocol
                pub(crate) use wayland_server::{NewResource, Resource, ResourceMap};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{AnonymousObject, Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_server::protocol::{$($import),*};
                $(
                    pub(crate) use ::$prot_name::server::$prot_import;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_rust_server_api.rs"));
            }
        }

        #[cfg(all(feature = "native_lib", any(feature = "client", feature = "server")))]
        mod generated {
            #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
            #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
            #![allow(missing_docs)]

            pub mod c_interfaces {
                //! C interfaces for this protocol

                // import client or server, both are the same anyway
                #[cfg(feature = "client")]
                pub use wayland_client::sys::protocol_interfaces::{$($interface),*};
                #[cfg(all(not(feature = "client"), feature = "server"))]
                pub use wayland_server::sys::protocol_interfaces::{$($interface),*};
                $(
                    pub(crate) use ::$prot_name::c_interfaces::$prot_iface;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_c_interfaces.rs"));
            }

            #[cfg(feature = "client")]
            pub mod client {
                //! Client-side API of this protocol
                pub(crate) use wayland_client::{NewProxy, Proxy, ProxyMap};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{AnonymousObject, Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_sys as sys;
                pub(crate) use wayland_client::protocol::{$($import),*};
                $(
                    pub(crate) use ::$prot_name::client::$prot_import;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_c_client_api.rs"));
            }

            #[cfg(feature = "server")]
            pub mod server {
                //! Server-side API of this protocol
                pub(crate) use wayland_server::{NewResource, Resource, ResourceMap};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{AnonymousObject, Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_sys as sys;
                pub(crate) use wayland_server::protocol::{$($import),*};
                $(
                    pub(crate) use ::$prot_name::server::$prot_import;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_c_server_api.rs"));
            }
        }
    }
);

#[cfg(feature = "unstable_protocols")]
#[macro_escape]
macro_rules! wayland_protocol_versioned(
    ($name: expr, [$($version: ident),*], $std_imports:tt, $prot_imports:tt) => {
        $(
            #[allow(missing_docs)]
            pub mod $version {
                wayland_protocol!(concat!($name, "-", stringify!($version)), $std_imports, $prot_imports);
            }
        )*
    }
);
<|endoftext|>


<commit_before>extern crate proc_macro;

use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::Comma;

#[proc_macro_derive(Asn1Read, attributes(explicit, implicit, default))]
pub fn derive_asn1_read(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    let name = input.ident;
    let (impl_lifetimes, ty_lifetimes, lifetime_name) = add_lifetime_if_none(input.generics);

    let expanded = match input.data {
        syn::Data::Struct(data) => {
            let read_block = generate_struct_read_block(&name, &data);
            quote::quote! {
                impl<#impl_lifetimes> asn1::SimpleAsn1Readable<#lifetime_name> for #name<#ty_lifetimes> {
                    const TAG: u8 = <asn1::Sequence as asn1::SimpleAsn1Readable>::TAG;
                    fn parse_data(data: &#lifetime_name [u8]) -> asn1::ParseResult<Self> {
                        asn1::parse(data, |p| #read_block)
                    }
                }
            }
        }
        syn::Data::Enum(data) => {
            let (read_block, can_parse_block) = generate_enum_read_block(&name, &data);
            quote::quote! {
                impl<#impl_lifetimes> asn1::Asn1Readable<#lifetime_name> for #name<#ty_lifetimes> {
                    fn parse(parser: &mut asn1::Parser<#lifetime_name>) -> asn1::ParseResult<Self> {
                        let tlv = parser.read_element::<asn1::Tlv>()?;
                        #read_block
                        Err(asn1::ParseError::new(asn1::ParseErrorKind::UnexpectedTag{actual: tlv.tag()}))
                    }

                    fn can_parse(tag: u8) -> bool {
                        #can_parse_block
                        false
                    }
                }
            }
        }
        _ => unimplemented!("Not supported for unions"),
    };

    proc_macro::TokenStream::from(expanded)
}

#[proc_macro_derive(Asn1Write, attributes(explicit, implicit, default))]
pub fn derive_asn1_write(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    let name = input.ident;
    let (impl_lifetimes, ty_lifetimes, lifetime_name) = add_lifetime_if_none(input.generics);

    let expanded = match input.data {
        syn::Data::Struct(data) => {
            let write_block = generate_struct_write_block(&data);
            quote::quote! {
                impl<#impl_lifetimes> asn1::SimpleAsn1Writable<#lifetime_name> for #name<#ty_lifetimes> {
                    const TAG: u8 = <asn1::SequenceWriter as asn1::SimpleAsn1Writable>::TAG;
                    fn write_data(&self, dest: &mut Vec<u8>) {
                        #write_block
                    }
                }
            }
        }
        syn::Data::Enum(data) => {
            let write_block = generate_enum_write_block(&name, &data);
            quote::quote! {
                impl<#impl_lifetimes> asn1::Asn1Writable<#lifetime_name> for #name<#ty_lifetimes> {
                    fn write(&self, w: &mut asn1::Writer) {
                        #write_block
                    }
                }
            }
        }
        _ => unimplemented!("Not supported for unions"),
    };

    proc_macro::TokenStream::from(expanded)
}

fn add_lifetime_if_none(
    mut generics: syn::Generics,
) -> (
    Punctuated<syn::Lifetime, Comma>,
    Punctuated<syn::Lifetime, Comma>,
    syn::Lifetime,
) {
    let mut impl_lifetimes = Punctuated::new();
    let mut ty_lifetimes = Punctuated::new();
    let mut lifetime = None;
    for param in &mut generics.params {
        if let syn::GenericParam::Lifetime(lifetime_def) = param {
            impl_lifetimes.push(lifetime_def.lifetime.clone());
            ty_lifetimes.push(lifetime_def.lifetime.clone());
            lifetime = Some(lifetime_def.lifetime.clone());
        }
    }

    let lifetime = lifetime.unwrap_or_else(|| {
        let lifetime = syn::Lifetime::new("'a", proc_macro2::Span::call_site());
        impl_lifetimes.push(lifetime.clone());
        lifetime
    });
    (impl_lifetimes, ty_lifetimes, lifetime)
}

enum OpType {
    Regular,
    Explicit(proc_macro2::Literal),
    Implicit(OpTypeArgs),
}

struct OpTypeArgs {
    value: proc_macro2::Literal,
    required: bool,
}

impl syn::parse::Parse for OpTypeArgs {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let value = input.parse::<proc_macro2::Literal>()?;
        let required = if input.lookahead1().peek(syn::Token![,]) {
            input.parse::<syn::Token![,]>()?;
            assert_eq!(input.parse::<syn::Ident>()?, "required");
            true
        } else {
            false
        };
        Ok(OpTypeArgs { value, required })
    }
}

fn extract_field_properties(attrs: &[syn::Attribute]) -> (OpType, Option<syn::Lit>) {
    let mut op_type = OpType::Regular;
    let mut default = None;
    for attr in attrs {
        if attr.path.is_ident("explicit") {
            if let OpType::Regular = op_type {
                op_type = OpType::Explicit(attr.parse_args::<proc_macro2::Literal>().unwrap());
            } else {
                panic!("Can't specify #[explicit] or #[implicit] more than once")
            }
        } else if attr.path.is_ident("implicit") {
            if let OpType::Regular = op_type {
                op_type = OpType::Implicit(attr.parse_args::<OpTypeArgs>().unwrap());
            } else {
                panic!("Can't specify #[explicit] or #[implicit] more than once")
            }
        } else if attr.path.is_ident("default") {
            if default.is_some() {
                panic!("Can't specify #[default] more than once");
            }
            default = Some(attr.parse_args::<syn::Lit>().unwrap());
        }
    }

    (op_type, default)
}

fn generate_read_element(
    struct_name: &syn::Ident,
    f: &syn::Field,
    f_name: &str,
) -> proc_macro2::TokenStream {
    let (read_type, default) = extract_field_properties(&f.attrs);

    let error_location = format!("{}::{}", struct_name, f_name);
    let add_error_location = quote::quote! {
        .map_err(|e| e.add_location(asn1::ParseLocation::Field(#error_location)))
    };
    let mut read_op = match read_type {
        OpType::Explicit(arg) => quote::quote! {
            p.read_optional_explicit_element(#arg)#add_error_location?
        },
        OpType::Implicit(arg) => {
            let value = arg.value;
            if arg.required {
                quote::quote! {
                    p.read_implicit_element(#value)#add_error_location?
                }
            } else {
                quote::quote! {
                    p.read_optional_implicit_element(#value)#add_error_location?
                }
            }
        }
        OpType::Regular => quote::quote! {
            p.read_element()#add_error_location?
        },
    };
    if let Some(default) = default {
        read_op = quote::quote! {{
            asn1::from_optional_default(#read_op, #default.into())#add_error_location?
        }};
    }
    read_op
}

fn generate_struct_read_block(
    struct_name: &syn::Ident,
    data: &syn::DataStruct,
) -> proc_macro2::TokenStream {
    match data.fields {
        syn::Fields::Named(ref fields) => {
            let recurse = fields.named.iter().map(|f| {
                let name = &f.ident;
                let read_op =
                    generate_read_element(struct_name, f, &format!("{}", name.as_ref().unwrap()));
                quote::quote_spanned! {f.span() =>
                    #name: #read_op,
                }
            });

            quote::quote! {
                Ok(Self {
                    #(#recurse)*
                })
            }
        }
        syn::Fields::Unnamed(ref fields) => {
            let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
                let read_op = generate_read_element(struct_name, f, &format!("{}", i));
                quote::quote_spanned! {f.span() =>
                    #read_op,
                }
            });

            quote::quote! {
                Ok(Self(
                    #(#recurse)*
                ))
            }
        }
        syn::Fields::Unit => {
            quote::quote! { Ok(Self) }
        }
    }
}

fn generate_enum_read_block(
    name: &syn::Ident,
    data: &syn::DataEnum,
) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
    let mut read_blocks = vec![];
    let mut can_parse_blocks = vec![];

    for variant in &data.variants {
        let field = match &variant.fields {
            syn::Fields::Unnamed(fields) => {
                assert_eq!(fields.unnamed.len(), 1);
                &fields.unnamed[0]
            }
            _ => panic!("enum elements must have a single field"),
        };
        let (op_type, default) = extract_field_properties(&variant.attrs);
        assert!(default.is_none());

        let ty = &field.ty;
        let ident = &variant.ident;

        let error_location = format!("{}::{}", name, ident);
        let add_error_location = quote::quote! {
            .map_err(|e| e.add_location(asn1::ParseLocation::Field(#error_location)))
        };
        match op_type {
            OpType::Regular => {
                read_blocks.push(quote::quote! {
                    if <#ty>::can_parse(tlv.tag()) {
                        return Ok(#name::#ident(tlv.parse()#add_error_location?));
                    }
                });
                can_parse_blocks.push(quote::quote! {
                    if <#ty>::can_parse(tag) {
                        return true;
                    }
                });
            }
            OpType::Explicit(tag) => {
                read_blocks.push(quote::quote! {
                    if tlv.tag() == asn1::explicit_tag(#tag) {
                        return Ok(#name::#ident(asn1::parse(
                            tlv.full_data(),
                            |p| Ok(p.read_optional_explicit_element(#tag)#add_error_location?.unwrap()))?
                        ))
                    }
                });
                can_parse_blocks.push(quote::quote! {
                    if tag == asn1::explicit_tag(#tag) {
                        return true;
                    }
                });
            }
            OpType::Implicit(arg) => {
                let tag = arg.value;
                read_blocks.push(quote::quote! {
                    if tlv.tag() == asn1::implicit_tag(#tag, <#ty as asn1::SimpleAsn1Readable>::TAG) {
                        return Ok(#name::#ident(asn1::parse(
                            tlv.full_data(),
                            |p| Ok(p.read_optional_implicit_element(#tag)#add_error_location?.unwrap()))?
                        ))
                    }
                });
                can_parse_blocks.push(quote::quote! {
                    if tag == asn1::implicit_tag(#tag, <#ty as asn1::SimpleAsn1Readable>::TAG) {
                        return true;
                    }
                });
            }
        };
    }

    let read_block = quote::quote! {
        #(#read_blocks)*
    };
    let can_parse_block = quote::quote! {
        #(#can_parse_blocks)*
    };
    (read_block, can_parse_block)
}

fn generate_write_element(
    f: &syn::Field,
    mut field_read: proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
    let (write_type, default) = extract_field_properties(&f.attrs);

    if let Some(default) = default {
        field_read = quote::quote! {&{
            asn1::to_optional_default(#field_read, &(#default).into())
        }}
    }

    match write_type {
        OpType::Explicit(arg) => quote::quote_spanned! {f.span() =>
            w.write_optional_explicit_element(#field_read, #arg);
        },
        OpType::Implicit(arg) => {
            let value = arg.value;
            if arg.required {
                quote::quote_spanned! {f.span() =>
                    w.write_implicit_element(#field_read, #value);
                }
            } else {
                quote::quote_spanned! {f.span() =>
                    w.write_optional_implicit_element(#field_read, #value);
                }
            }
        }
        OpType::Regular => quote::quote! {
            w.write_element(#field_read);
        },
    }
}

fn generate_struct_write_block(data: &syn::DataStruct) -> proc_macro2::TokenStream {
    match data.fields {
        syn::Fields::Named(ref fields) => {
            let recurse = fields.named.iter().map(|f| {
                let name = &f.ident;
                generate_write_element(f, quote::quote! { &self.#name })
            });

            quote::quote! {
                let mut w = asn1::Writer::new(dest);
                #(#recurse)*
            }
        }
        syn::Fields::Unnamed(ref fields) => {
            let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
                let index = syn::Index::from(i);
                generate_write_element(f, quote::quote! { &self.#index })
            });

            quote::quote! {
                let mut w = asn1::Writer::new(dest);
                #(#recurse)*
            }
        }
        syn::Fields::Unit => {
            quote::quote! {}
        }
    }
}

fn generate_enum_write_block(name: &syn::Ident, data: &syn::DataEnum) -> proc_macro2::TokenStream {
    let write_arms = data.variants.iter().map(|v| {
        match &v.fields {
            syn::Fields::Unnamed(fields) => {
                assert_eq!(fields.unnamed.len(), 1);
            }
            _ => panic!("enum elements must have a single field"),
        };
        let (op_type, default) = extract_field_properties(&v.attrs);
        assert!(default.is_none());
        let ident = &v.ident;

        match op_type {
            OpType::Regular => {
                quote::quote! {
                    #name::#ident(value) => w.write_element(value),
                }
            }
            OpType::Explicit(tag) => {
                quote::quote! {
                    #name::#ident(value) => w.write_optional_explicit_element(&Some(value), #tag),
                }
            }
            OpType::Implicit(arg) => {
                let tag = arg.value;
                quote::quote! {
                    #name::#ident(value) => w.write_optional_implicit_element(&Some(value), #tag),
                }
            }
        }
    });
    quote::quote! {
        match self {
            #(#write_arms)*
        }
    }
}
<commit_msg>Adhere to clippy's demands (#205)<commit_after>extern crate proc_macro;

use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::Comma;

#[proc_macro_derive(Asn1Read, attributes(explicit, implicit, default))]
pub fn derive_asn1_read(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    let name = input.ident;
    let (impl_lifetimes, ty_lifetimes, lifetime_name) = add_lifetime_if_none(input.generics);

    let expanded = match input.data {
        syn::Data::Struct(data) => {
            let read_block = generate_struct_read_block(&name, &data);
            quote::quote! {
                impl<#impl_lifetimes> asn1::SimpleAsn1Readable<#lifetime_name> for #name<#ty_lifetimes> {
                    const TAG: u8 = <asn1::Sequence as asn1::SimpleAsn1Readable>::TAG;
                    fn parse_data(data: &#lifetime_name [u8]) -> asn1::ParseResult<Self> {
                        asn1::parse(data, |p| #read_block)
                    }
                }
            }
        }
        syn::Data::Enum(data) => {
            let (read_block, can_parse_block) = generate_enum_read_block(&name, &data);
            quote::quote! {
                impl<#impl_lifetimes> asn1::Asn1Readable<#lifetime_name> for #name<#ty_lifetimes> {
                    fn parse(parser: &mut asn1::Parser<#lifetime_name>) -> asn1::ParseResult<Self> {
                        let tlv = parser.read_element::<asn1::Tlv>()?;
                        #read_block
                        Err(asn1::ParseError::new(asn1::ParseErrorKind::UnexpectedTag{actual: tlv.tag()}))
                    }

                    fn can_parse(tag: u8) -> bool {
                        #can_parse_block
                        false
                    }
                }
            }
        }
        _ => unimplemented!("Not supported for unions"),
    };

    proc_macro::TokenStream::from(expanded)
}

#[proc_macro_derive(Asn1Write, attributes(explicit, implicit, default))]
pub fn derive_asn1_write(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    let name = input.ident;
    let (impl_lifetimes, ty_lifetimes, lifetime_name) = add_lifetime_if_none(input.generics);

    let expanded = match input.data {
        syn::Data::Struct(data) => {
            let write_block = generate_struct_write_block(&data);
            quote::quote! {
                impl<#impl_lifetimes> asn1::SimpleAsn1Writable<#lifetime_name> for #name<#ty_lifetimes> {
                    const TAG: u8 = <asn1::SequenceWriter as asn1::SimpleAsn1Writable>::TAG;
                    fn write_data(&self, dest: &mut Vec<u8>) {
                        #write_block
                    }
                }
            }
        }
        syn::Data::Enum(data) => {
            let write_block = generate_enum_write_block(&name, &data);
            quote::quote! {
                impl<#impl_lifetimes> asn1::Asn1Writable<#lifetime_name> for #name<#ty_lifetimes> {
                    fn write(&self, w: &mut asn1::Writer) {
                        #write_block
                    }
                }
            }
        }
        _ => unimplemented!("Not supported for unions"),
    };

    proc_macro::TokenStream::from(expanded)
}

fn add_lifetime_if_none(
    mut generics: syn::Generics,
) -> (
    Punctuated<syn::Lifetime, Comma>,
    Punctuated<syn::Lifetime, Comma>,
    syn::Lifetime,
) {
    let mut impl_lifetimes = Punctuated::new();
    let mut ty_lifetimes = Punctuated::new();
    let mut lifetime = None;
    for param in &mut generics.params {
        if let syn::GenericParam::Lifetime(lifetime_def) = param {
            impl_lifetimes.push(lifetime_def.lifetime.clone());
            ty_lifetimes.push(lifetime_def.lifetime.clone());
            lifetime = Some(lifetime_def.lifetime.clone());
        }
    }

    let lifetime = lifetime.unwrap_or_else(|| {
        let lifetime = syn::Lifetime::new("'a", proc_macro2::Span::call_site());
        impl_lifetimes.push(lifetime.clone());
        lifetime
    });
    (impl_lifetimes, ty_lifetimes, lifetime)
}

enum OpType {
    Regular,
    Explicit(proc_macro2::Literal),
    Implicit(OpTypeArgs),
}

struct OpTypeArgs {
    value: proc_macro2::Literal,
    required: bool,
}

impl syn::parse::Parse for OpTypeArgs {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let value = input.parse::<proc_macro2::Literal>()?;
        let required = if input.lookahead1().peek(syn::Token![,]) {
            input.parse::<syn::Token![,]>()?;
            assert_eq!(input.parse::<syn::Ident>()?, "required");
            true
        } else {
            false
        };
        Ok(OpTypeArgs { value, required })
    }
}

fn extract_field_properties(attrs: &[syn::Attribute]) -> (OpType, Option<syn::Lit>) {
    let mut op_type = OpType::Regular;
    let mut default = None;
    for attr in attrs {
        if attr.path.is_ident("explicit") {
            if let OpType::Regular = op_type {
                op_type = OpType::Explicit(attr.parse_args::<proc_macro2::Literal>().unwrap());
            } else {
                panic!("Can't specify #[explicit] or #[implicit] more than once")
            }
        } else if attr.path.is_ident("implicit") {
            if let OpType::Regular = op_type {
                op_type = OpType::Implicit(attr.parse_args::<OpTypeArgs>().unwrap());
            } else {
                panic!("Can't specify #[explicit] or #[implicit] more than once")
            }
        } else if attr.path.is_ident("default") {
            assert!(default.is_none(), "Can't specify #[default] more than once");
            default = Some(attr.parse_args::<syn::Lit>().unwrap());
        }
    }

    (op_type, default)
}

fn generate_read_element(
    struct_name: &syn::Ident,
    f: &syn::Field,
    f_name: &str,
) -> proc_macro2::TokenStream {
    let (read_type, default) = extract_field_properties(&f.attrs);

    let error_location = format!("{}::{}", struct_name, f_name);
    let add_error_location = quote::quote! {
        .map_err(|e| e.add_location(asn1::ParseLocation::Field(#error_location)))
    };
    let mut read_op = match read_type {
        OpType::Explicit(arg) => quote::quote! {
            p.read_optional_explicit_element(#arg)#add_error_location?
        },
        OpType::Implicit(arg) => {
            let value = arg.value;
            if arg.required {
                quote::quote! {
                    p.read_implicit_element(#value)#add_error_location?
                }
            } else {
                quote::quote! {
                    p.read_optional_implicit_element(#value)#add_error_location?
                }
            }
        }
        OpType::Regular => quote::quote! {
            p.read_element()#add_error_location?
        },
    };
    if let Some(default) = default {
        read_op = quote::quote! {{
            asn1::from_optional_default(#read_op, #default.into())#add_error_location?
        }};
    }
    read_op
}

fn generate_struct_read_block(
    struct_name: &syn::Ident,
    data: &syn::DataStruct,
) -> proc_macro2::TokenStream {
    match data.fields {
        syn::Fields::Named(ref fields) => {
            let recurse = fields.named.iter().map(|f| {
                let name = &f.ident;
                let read_op =
                    generate_read_element(struct_name, f, &format!("{}", name.as_ref().unwrap()));
                quote::quote_spanned! {f.span() =>
                    #name: #read_op,
                }
            });

            quote::quote! {
                Ok(Self {
                    #(#recurse)*
                })
            }
        }
        syn::Fields::Unnamed(ref fields) => {
            let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
                let read_op = generate_read_element(struct_name, f, &format!("{}", i));
                quote::quote_spanned! {f.span() =>
                    #read_op,
                }
            });

            quote::quote! {
                Ok(Self(
                    #(#recurse)*
                ))
            }
        }
        syn::Fields::Unit => {
            quote::quote! { Ok(Self) }
        }
    }
}

fn generate_enum_read_block(
    name: &syn::Ident,
    data: &syn::DataEnum,
) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
    let mut read_blocks = vec![];
    let mut can_parse_blocks = vec![];

    for variant in &data.variants {
        let field = match &variant.fields {
            syn::Fields::Unnamed(fields) => {
                assert_eq!(fields.unnamed.len(), 1);
                &fields.unnamed[0]
            }
            _ => panic!("enum elements must have a single field"),
        };
        let (op_type, default) = extract_field_properties(&variant.attrs);
        assert!(default.is_none());

        let ty = &field.ty;
        let ident = &variant.ident;

        let error_location = format!("{}::{}", name, ident);
        let add_error_location = quote::quote! {
            .map_err(|e| e.add_location(asn1::ParseLocation::Field(#error_location)))
        };
        match op_type {
            OpType::Regular => {
                read_blocks.push(quote::quote! {
                    if <#ty>::can_parse(tlv.tag()) {
                        return Ok(#name::#ident(tlv.parse()#add_error_location?));
                    }
                });
                can_parse_blocks.push(quote::quote! {
                    if <#ty>::can_parse(tag) {
                        return true;
                    }
                });
            }
            OpType::Explicit(tag) => {
                read_blocks.push(quote::quote! {
                    if tlv.tag() == asn1::explicit_tag(#tag) {
                        return Ok(#name::#ident(asn1::parse(
                            tlv.full_data(),
                            |p| Ok(p.read_optional_explicit_element(#tag)#add_error_location?.unwrap()))?
                        ))
                    }
                });
                can_parse_blocks.push(quote::quote! {
                    if tag == asn1::explicit_tag(#tag) {
                        return true;
                    }
                });
            }
            OpType::Implicit(arg) => {
                let tag = arg.value;
                read_blocks.push(quote::quote! {
                    if tlv.tag() == asn1::implicit_tag(#tag, <#ty as asn1::SimpleAsn1Readable>::TAG) {
                        return Ok(#name::#ident(asn1::parse(
                            tlv.full_data(),
                            |p| Ok(p.read_optional_implicit_element(#tag)#add_error_location?.unwrap()))?
                        ))
                    }
                });
                can_parse_blocks.push(quote::quote! {
                    if tag == asn1::implicit_tag(#tag, <#ty as asn1::SimpleAsn1Readable>::TAG) {
                        return true;
                    }
                });
            }
        };
    }

    let read_block = quote::quote! {
        #(#read_blocks)*
    };
    let can_parse_block = quote::quote! {
        #(#can_parse_blocks)*
    };
    (read_block, can_parse_block)
}

fn generate_write_element(
    f: &syn::Field,
    mut field_read: proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
    let (write_type, default) = extract_field_properties(&f.attrs);

    if let Some(default) = default {
        field_read = quote::quote! {&{
            asn1::to_optional_default(#field_read, &(#default).into())
        }}
    }

    match write_type {
        OpType::Explicit(arg) => quote::quote_spanned! {f.span() =>
            w.write_optional_explicit_element(#field_read, #arg);
        },
        OpType::Implicit(arg) => {
            let value = arg.value;
            if arg.required {
                quote::quote_spanned! {f.span() =>
                    w.write_implicit_element(#field_read, #value);
                }
            } else {
                quote::quote_spanned! {f.span() =>
                    w.write_optional_implicit_element(#field_read, #value);
                }
            }
        }
        OpType::Regular => quote::quote! {
            w.write_element(#field_read);
        },
    }
}

fn generate_struct_write_block(data: &syn::DataStruct) -> proc_macro2::TokenStream {
    match data.fields {
        syn::Fields::Named(ref fields) => {
            let recurse = fields.named.iter().map(|f| {
                let name = &f.ident;
                generate_write_element(f, quote::quote! { &self.#name })
            });

            quote::quote! {
                let mut w = asn1::Writer::new(dest);
                #(#recurse)*
            }
        }
        syn::Fields::Unnamed(ref fields) => {
            let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
                let index = syn::Index::from(i);
                generate_write_element(f, quote::quote! { &self.#index })
            });

            quote::quote! {
                let mut w = asn1::Writer::new(dest);
                #(#recurse)*
            }
        }
        syn::Fields::Unit => {
            quote::quote! {}
        }
    }
}

fn generate_enum_write_block(name: &syn::Ident, data: &syn::DataEnum) -> proc_macro2::TokenStream {
    let write_arms = data.variants.iter().map(|v| {
        match &v.fields {
            syn::Fields::Unnamed(fields) => {
                assert_eq!(fields.unnamed.len(), 1);
            }
            _ => panic!("enum elements must have a single field"),
        };
        let (op_type, default) = extract_field_properties(&v.attrs);
        assert!(default.is_none());
        let ident = &v.ident;

        match op_type {
            OpType::Regular => {
                quote::quote! {
                    #name::#ident(value) => w.write_element(value),
                }
            }
            OpType::Explicit(tag) => {
                quote::quote! {
                    #name::#ident(value) => w.write_optional_explicit_element(&Some(value), #tag),
                }
            }
            OpType::Implicit(arg) => {
                let tag = arg.value;
                quote::quote! {
                    #name::#ident(value) => w.write_optional_implicit_element(&Some(value), #tag),
                }
            }
        }
    });
    quote::quote! {
        match self {
            #(#write_arms)*
        }
    }
}
<|endoftext|>