<commit_before>use rustc_errors::struct_span_err;
use rustc_middle::mir;

use super::FunctionCx;
use super::LocalRef;
use super::OperandValue;
use crate::traits::BuilderMethods;
use crate::traits::*;

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
    pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>) -> Bx {
        debug!("codegen_statement(statement={:?})", statement);

        self.set_debug_loc(&mut bx, statement.source_info);
        match statement.kind {
            mir::StatementKind::Assign(box (ref place, ref rvalue)) => {
                if let Some(index) = place.as_local() {
                    match self.locals[index] {
                        LocalRef::Place(cg_dest) => self.codegen_rvalue(bx, cg_dest, rvalue),
                        LocalRef::UnsizedPlace(cg_indirect_dest) => {
                            self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue)
                        }
                        LocalRef::Operand(None) => {
                            let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
                            self.locals[index] = LocalRef::Operand(Some(operand));
                            self.debug_introduce_local(&mut bx, index);
                            bx
                        }
                        LocalRef::Operand(Some(op)) => {
                            if !op.layout.is_zst() {
                                span_bug!(
                                    statement.source_info.span,
                                    "operand {:?} already assigned",
                                    rvalue
                                );
                            }

                            // If the type is zero-sized, it's already been set here,
                            // but we still need to make sure we codegen the operand
                            self.codegen_rvalue_operand(bx, rvalue).0
                        }
                    }
                } else {
                    let cg_dest = self.codegen_place(&mut bx, place.as_ref());
                    self.codegen_rvalue(bx, cg_dest, rvalue)
                }
            }
            mir::StatementKind::SetDiscriminant { box ref place, variant_index } => {
                self.codegen_place(&mut bx, place.as_ref())
                    .codegen_set_discr(&mut bx, variant_index);
                bx
            }
            mir::StatementKind::StorageLive(local) => {
                if let LocalRef::Place(cg_place) = self.locals[local] {
                    cg_place.storage_live(&mut bx);
                } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] {
                    cg_indirect_place.storage_live(&mut bx);
                }
                bx
            }
            mir::StatementKind::StorageDead(local) => {
                if let LocalRef::Place(cg_place) = self.locals[local] {
                    cg_place.storage_dead(&mut bx);
                } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] {
                    cg_indirect_place.storage_dead(&mut bx);
                }
                bx
            }
            mir::StatementKind::LlvmInlineAsm(ref asm) => {
                let outputs = asm
                    .outputs
                    .iter()
                    .map(|output| self.codegen_place(&mut bx, output.as_ref()))
                    .collect();

                let input_vals = asm.inputs.iter().fold(
                    Vec::with_capacity(asm.inputs.len()),
                    |mut acc, (span, input)| {
                        let op = self.codegen_operand(&mut bx, input);
                        if let OperandValue::Immediate(_) = op.val {
                            acc.push(op.immediate());
                        } else {
                            struct_span_err!(
                                bx.sess(),
                                span.to_owned(),
                                E0669,
                                "invalid value for constraint in inline assembly"
                            )
                            .emit();
                        }
                        acc
                    },
                );

                if input_vals.len() == asm.inputs.len() {
                    let res = bx.codegen_llvm_inline_asm(
                        &asm.asm,
                        outputs,
                        input_vals,
                        statement.source_info.span,
                    );
                    if !res {
                        struct_span_err!(
                            bx.sess(),
                            statement.source_info.span,
                            E0668,
                            "malformed inline assembly"
                        )
                        .emit();
                    }
                }
                bx
            }
            mir::StatementKind::Coverage(box ref coverage) => {
                self.codegen_coverage(&mut bx, coverage.clone());
                bx
            }
            mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {
                ref src,
                ref dst,
                ref count,
            }) => {
                let dst_val = self.codegen_operand(&mut bx, dst);
                let src_val = self.codegen_operand(&mut bx, src);
                let count_val = self.codegen_operand(&mut bx, count);
                let count = count_val.immediate_or_packed_pair(&mut bx);
                let dst = dst_val.immediate_or_packed_pair(&mut bx);
                let src = src_val.immediate_or_packed_pair(&mut bx);
                let flags = crate::MemFlags::empty();
                bx.memcpy(
                    dst,
                    dst_val.layout.layout.align.pref,
                    src,
                    src_val.layout.layout.align.pref,
                    count,
                    flags,
                );
                bx
            }
            mir::StatementKind::FakeRead(..)
            | mir::StatementKind::Retag { .. }
            | mir::StatementKind::AscribeUserType(..)
            | mir::StatementKind::Nop => bx,
        }
    }
}
<commit_msg>Change CopyNonOverlapping::codegen_ssa<commit_after>use rustc_errors::struct_span_err;
use rustc_middle::mir;

use super::FunctionCx;
use super::LocalRef;
use super::OperandValue;
use crate::traits::BuilderMethods;
use crate::traits::*;

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
    pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>) -> Bx {
        debug!("codegen_statement(statement={:?})", statement);

        self.set_debug_loc(&mut bx, statement.source_info);
        match statement.kind {
            mir::StatementKind::Assign(box (ref place, ref rvalue)) => {
                if let Some(index) = place.as_local() {
                    match self.locals[index] {
                        LocalRef::Place(cg_dest) => self.codegen_rvalue(bx, cg_dest, rvalue),
                        LocalRef::UnsizedPlace(cg_indirect_dest) => {
                            self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue)
                        }
                        LocalRef::Operand(None) => {
                            let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
                            self.locals[index] = LocalRef::Operand(Some(operand));
                            self.debug_introduce_local(&mut bx, index);
                            bx
                        }
                        LocalRef::Operand(Some(op)) => {
                            if !op.layout.is_zst() {
                                span_bug!(
                                    statement.source_info.span,
                                    "operand {:?} already assigned",
                                    rvalue
                                );
                            }

                            // If the type is zero-sized, it's already been set here,
                            // but we still need to make sure we codegen the operand
                            self.codegen_rvalue_operand(bx, rvalue).0
                        }
                    }
                } else {
                    let cg_dest = self.codegen_place(&mut bx, place.as_ref());
                    self.codegen_rvalue(bx, cg_dest, rvalue)
                }
            }
            mir::StatementKind::SetDiscriminant { box ref place, variant_index } => {
                self.codegen_place(&mut bx, place.as_ref())
                    .codegen_set_discr(&mut bx, variant_index);
                bx
            }
            mir::StatementKind::StorageLive(local) => {
                if let LocalRef::Place(cg_place) = self.locals[local] {
                    cg_place.storage_live(&mut bx);
                } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] {
                    cg_indirect_place.storage_live(&mut bx);
                }
                bx
            }
            mir::StatementKind::StorageDead(local) => {
                if let LocalRef::Place(cg_place) = self.locals[local] {
                    cg_place.storage_dead(&mut bx);
                } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] {
                    cg_indirect_place.storage_dead(&mut bx);
                }
                bx
            }
            mir::StatementKind::LlvmInlineAsm(ref asm) => {
                let outputs = asm
                    .outputs
                    .iter()
                    .map(|output| self.codegen_place(&mut bx, output.as_ref()))
                    .collect();

                let input_vals = asm.inputs.iter().fold(
                    Vec::with_capacity(asm.inputs.len()),
                    |mut acc, (span, input)| {
                        let op = self.codegen_operand(&mut bx, input);
                        if let OperandValue::Immediate(_) = op.val {
                            acc.push(op.immediate());
                        } else {
                            struct_span_err!(
                                bx.sess(),
                                span.to_owned(),
                                E0669,
                                "invalid value for constraint in inline assembly"
                            )
                            .emit();
                        }
                        acc
                    },
                );

                if input_vals.len() == asm.inputs.len() {
                    let res = bx.codegen_llvm_inline_asm(
                        &asm.asm,
                        outputs,
                        input_vals,
                        statement.source_info.span,
                    );
                    if !res {
                        struct_span_err!(
                            bx.sess(),
                            statement.source_info.span,
                            E0668,
                            "malformed inline assembly"
                        )
                        .emit();
                    }
                }
                bx
            }
            mir::StatementKind::Coverage(box ref coverage) => {
                self.codegen_coverage(&mut bx, coverage.clone());
                bx
            }
            mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {
                ref src,
                ref dst,
                ref count,
            }) => {
                let dst_val = self.codegen_operand(&mut bx, dst);
                let src_val = self.codegen_operand(&mut bx, src);
                let count = self.codegen_operand(&mut bx, count).immediate();
                let get_val_align = |oper_ref: crate::mir::OperandRef<'_, _>| match oper_ref.val {
                    OperandValue::Ref(val, _, align) => (val, align),
                    _ => unreachable!(),
                };
                let pointee_layout = dst_val
                    .layout
                    .pointee_info_at(&mut bx, rustc_target::abi::Size::ZERO)
                    .expect("Expected pointer");
                let elem_size = bx.const_u64(pointee_layout.size.bytes());
                let byte_count = bx.mul(count, elem_size);

                let (dst, dst_align) = get_val_align(dst_val);
                let (src, src_align) = get_val_align(src_val);
                bx.memcpy(dst, dst_align, src, src_align, byte_count, crate::MemFlags::empty());
                bx
            }
            mir::StatementKind::FakeRead(..)
            | mir::StatementKind::Retag { .. }
            | mir::StatementKind::AscribeUserType(..)
            | mir::StatementKind::Nop => bx,
        }
    }
}
<|endoftext|>


<commit_before>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::str;
use std::io::{Read, Write, ErrorKind};
use std::result::Result;
use std::net::TcpStream;
use std::time::Duration;
use rand::{thread_rng, Rng};

use super::command::ControlCommandResponse;
use super::command::ControlCommand;
use super::command::COMMAND_SIZE;
use APP_CONF;
use LINE_FEED;
use cache::route::CacheRoute;
use cache::route::ROUTE_HASH_SIZE;

pub struct ControlHandle;

enum ControlHandleError {
    Closed,
    IncompatibleHasher,
    NotRecognized,
    TimedOut,
    ConnectionAborted,
    Interrupted,
    Unknown,
}

#[derive(PartialEq)]
enum ControlHandleMessageResult {
    Continue,
    Close,
}

const MAX_LINE_SIZE: usize = COMMAND_SIZE + ROUTE_HASH_SIZE + 1;
const HASH_VALUE_SIZE: usize = 10;
const HASH_RESULT_SIZE: usize = 7 + ROUTE_HASH_SIZE + 1;
const SHARD_DEFAULT: ControlShard = 0;
const TCP_TIMEOUT_NON_ESTABLISHED: u64 = 20;

pub type ControlShard = u8;

lazy_static! {
    static ref CONNECTED_BANNER: String = format!("CONNECTED <{} v{}>",
        env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
}

impl ControlHandleError {
    pub fn to_str(&self) -> &'static str {
        match *self {
            ControlHandleError::Closed => "closed",
            ControlHandleError::IncompatibleHasher => "incompatible_hasher",
            ControlHandleError::NotRecognized => "not_recognized",
            ControlHandleError::TimedOut => "timed_out",
            ControlHandleError::ConnectionAborted => "connection_aborted",
            ControlHandleError::Interrupted => "interrupted",
            ControlHandleError::Unknown => "unknown",
        }
    }
}

impl ControlHandle {
    pub fn client(mut stream: TcpStream) {
        // Configure stream (non-established)
        ControlHandle::configure_stream(&stream, false);

        // Send connected banner
        write!(stream, "{}{}", *CONNECTED_BANNER, LINE_FEED).expect("write failed");

        // Ensure client hasher is compatible
        match Self::ensure_hasher(&stream) {
            Ok(_) => {
                // Configure stream (established)
                ControlHandle::configure_stream(&stream, true);

                // Send started acknowledgement
                write!(stream, "STARTED{}", LINE_FEED).expect("write failed");

                // Select default shard
                let mut shard = SHARD_DEFAULT;

                // Wait for incoming messages
                loop {
                    let mut read = [0; MAX_LINE_SIZE];

                    match stream.read(&mut read) {
                        Ok(n) => {
                            if n == 0 ||
                                Self::on_message(&mut shard, &stream, &read[0..n]) ==
                                    ControlHandleMessageResult::Close
                            {
                                // Should close?
                                break;
                            }
                        }
                        Err(_) => panic!("stream down"),
                    }
                }
            }
            Err(err) => {
                write!(stream, "ENDED {}{}", err.to_str(), LINE_FEED).expect("write failed");
            }
        }
    }

    fn configure_stream(stream: &TcpStream, is_established: bool) {
        let tcp_timeout = if is_established == true {
            APP_CONF.control.tcp_timeout
        } else {
            TCP_TIMEOUT_NON_ESTABLISHED
        };

        assert!(stream.set_nodelay(true).is_ok());

        assert!(
            stream
                .set_read_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
        assert!(
            stream
                .set_write_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
    }

    fn ensure_hasher(mut stream: &TcpStream) -> Result<Option<()>, ControlHandleError> {
        let test_value: String = thread_rng()
            .gen_ascii_chars()
            .take(HASH_VALUE_SIZE)
            .collect();
        let test_hash = CacheRoute::hash(test_value.as_str());

        write!(stream, "HASHREQ {}{}", test_value, LINE_FEED).expect("write failed");

        debug!(
            "sent hasher request: {} and expecting hash: {}",
            test_value,
            test_hash
        );

        loop {
            let mut read = [0; HASH_RESULT_SIZE];

            match stream.read(&mut read) {
                Ok(n) => {
                    if n == 0 {
                        return Err(ControlHandleError::Closed);
                    }

                    let mut parts = str::from_utf8(&read[0..n]).unwrap_or("").split_whitespace();

                    if parts.next().unwrap_or("") == "HASHRES" {
                        let res_hash = parts.next().unwrap_or("");

                        debug!(
                            "got hasher response: {} and expecting: {}",
                            res_hash,
                            test_hash
                        );

                        // Validate hash
                        if res_hash.is_empty() == false && res_hash == test_hash {
                            return Ok(None);
                        }

                        return Err(ControlHandleError::IncompatibleHasher);
                    }

                    return Err(ControlHandleError::NotRecognized);
                }
                Err(err) => {
                    let err_reason = match err.kind() {
                        ErrorKind::TimedOut => ControlHandleError::TimedOut,
                        ErrorKind::ConnectionAborted => ControlHandleError::ConnectionAborted,
                        ErrorKind::Interrupted => ControlHandleError::Interrupted,
                        _ => ControlHandleError::Unknown,
                    };

                    return Err(err_reason);
                }
            }
        }
    }

    fn on_message(
        shard: &mut ControlShard,
        mut stream: &TcpStream,
        message_slice: &[u8],
    ) -> ControlHandleMessageResult {
        let message = str::from_utf8(message_slice).unwrap_or("");

        debug!("got control message on shard {}: {}", shard, message);

        let mut result = ControlHandleMessageResult::Continue;

        let response = match Self::handle_message(shard, &message) {
            Ok(resp) => {
                match resp {
                    ControlCommandResponse::Ok |
                    ControlCommandResponse::Pong |
                    ControlCommandResponse::Ended |
                    ControlCommandResponse::Nil |
                    ControlCommandResponse::Void => {
                        if resp == ControlCommandResponse::Ended {
                            result = ControlHandleMessageResult::Close;
                        }
                        resp.to_str()
                    }
                    _ => ControlCommandResponse::Err.to_str(),
                }
            }
            _ => ControlCommandResponse::Err.to_str(),
        };

        if response.is_empty() == false {
            write!(stream, "{}{}", response, LINE_FEED).expect("write failed");
        }

        return result;
    }

    fn handle_message(
        shard: &mut ControlShard,
        message: &str,
    ) -> Result<ControlCommandResponse, Option<()>> {
        let mut parts = message.split_whitespace();
        let command = parts.next().unwrap_or("");

        debug!("will dispatch command: {}", command);

        match command {
            "" => Ok(ControlCommandResponse::Void),
            "FLUSHB" => ControlCommand::dispatch_flush_bucket(shard, parts),
            "FLUSHA" => ControlCommand::dispatch_flush_auth(shard, parts),
            "PING" => ControlCommand::dispatch_ping(),
            "SHARD" => ControlCommand::dispatch_shard(shard, parts),
            "QUIT" => ControlCommand::dispatch_quit(),
            _ => Ok(ControlCommandResponse::Nil),
        }
    }
}
<commit_msg>Explicit Bloom Control close message<commit_after>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::str;
use std::io::{Read, Write, ErrorKind};
use std::result::Result;
use std::net::TcpStream;
use std::time::Duration;
use rand::{thread_rng, Rng};

use super::command::ControlCommandResponse;
use super::command::ControlCommand;
use super::command::COMMAND_SIZE;
use APP_CONF;
use LINE_FEED;
use cache::route::CacheRoute;
use cache::route::ROUTE_HASH_SIZE;

pub struct ControlHandle;

enum ControlHandleError {
    Closed,
    IncompatibleHasher,
    NotRecognized,
    TimedOut,
    ConnectionAborted,
    Interrupted,
    Unknown,
}

#[derive(PartialEq)]
enum ControlHandleMessageResult {
    Continue,
    Close,
}

const MAX_LINE_SIZE: usize = COMMAND_SIZE + ROUTE_HASH_SIZE + 1;
const HASH_VALUE_SIZE: usize = 10;
const HASH_RESULT_SIZE: usize = 7 + ROUTE_HASH_SIZE + 1;
const SHARD_DEFAULT: ControlShard = 0;
const TCP_TIMEOUT_NON_ESTABLISHED: u64 = 20;

pub type ControlShard = u8;

lazy_static! {
    static ref CONNECTED_BANNER: String = format!("CONNECTED <{} v{}>",
        env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
}

impl ControlHandleError {
    pub fn to_str(&self) -> &'static str {
        match *self {
            ControlHandleError::Closed => "closed",
            ControlHandleError::IncompatibleHasher => "incompatible_hasher",
            ControlHandleError::NotRecognized => "not_recognized",
            ControlHandleError::TimedOut => "timed_out",
            ControlHandleError::ConnectionAborted => "connection_aborted",
            ControlHandleError::Interrupted => "interrupted",
            ControlHandleError::Unknown => "unknown",
        }
    }
}

impl ControlHandle {
    pub fn client(mut stream: TcpStream) {
        // Configure stream (non-established)
        ControlHandle::configure_stream(&stream, false);

        // Send connected banner
        write!(stream, "{}{}", *CONNECTED_BANNER, LINE_FEED).expect("write failed");

        // Ensure client hasher is compatible
        match Self::ensure_hasher(&stream) {
            Ok(_) => {
                // Configure stream (established)
                ControlHandle::configure_stream(&stream, true);

                // Send started acknowledgement
                write!(stream, "STARTED{}", LINE_FEED).expect("write failed");

                // Select default shard
                let mut shard = SHARD_DEFAULT;

                // Wait for incoming messages
                loop {
                    let mut read = [0; MAX_LINE_SIZE];

                    match stream.read(&mut read) {
                        Ok(n) => {
                            if n == 0 ||
                                Self::on_message(&mut shard, &stream, &read[0..n]) ==
                                    ControlHandleMessageResult::Close
                            {
                                // Should close?
                                break;
                            }
                        },
                        Err(err) => {
                            info!("closing control thread with traceback: {}", err);

                            panic!("closing control channel");
                        },
                    }
                }
            }
            Err(err) => {
                write!(stream, "ENDED {}{}", err.to_str(), LINE_FEED).expect("write failed");
            }
        }
    }

    fn configure_stream(stream: &TcpStream, is_established: bool) {
        let tcp_timeout = if is_established == true {
            APP_CONF.control.tcp_timeout
        } else {
            TCP_TIMEOUT_NON_ESTABLISHED
        };

        assert!(stream.set_nodelay(true).is_ok());

        assert!(
            stream
                .set_read_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
        assert!(
            stream
                .set_write_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
    }

    fn ensure_hasher(mut stream: &TcpStream) -> Result<Option<()>, ControlHandleError> {
        let test_value: String = thread_rng()
            .gen_ascii_chars()
            .take(HASH_VALUE_SIZE)
            .collect();
        let test_hash = CacheRoute::hash(test_value.as_str());

        write!(stream, "HASHREQ {}{}", test_value, LINE_FEED).expect("write failed");

        debug!(
            "sent hasher request: {} and expecting hash: {}",
            test_value,
            test_hash
        );

        loop {
            let mut read = [0; HASH_RESULT_SIZE];

            match stream.read(&mut read) {
                Ok(n) => {
                    if n == 0 {
                        return Err(ControlHandleError::Closed);
                    }

                    let mut parts = str::from_utf8(&read[0..n]).unwrap_or("").split_whitespace();

                    if parts.next().unwrap_or("") == "HASHRES" {
                        let res_hash = parts.next().unwrap_or("");

                        debug!(
                            "got hasher response: {} and expecting: {}",
                            res_hash,
                            test_hash
                        );

                        // Validate hash
                        if res_hash.is_empty() == false && res_hash == test_hash {
                            return Ok(None);
                        }

                        return Err(ControlHandleError::IncompatibleHasher);
                    }

                    return Err(ControlHandleError::NotRecognized);
                }
                Err(err) => {
                    let err_reason = match err.kind() {
                        ErrorKind::TimedOut => ControlHandleError::TimedOut,
                        ErrorKind::ConnectionAborted => ControlHandleError::ConnectionAborted,
                        ErrorKind::Interrupted => ControlHandleError::Interrupted,
                        _ => ControlHandleError::Unknown,
                    };

                    return Err(err_reason);
                }
            }
        }
    }

    fn on_message(
        shard: &mut ControlShard,
        mut stream: &TcpStream,
        message_slice: &[u8],
    ) -> ControlHandleMessageResult {
        let message = str::from_utf8(message_slice).unwrap_or("");

        debug!("got control message on shard {}: {}", shard, message);

        let mut result = ControlHandleMessageResult::Continue;

        let response = match Self::handle_message(shard, &message) {
            Ok(resp) => {
                match resp {
                    ControlCommandResponse::Ok |
                    ControlCommandResponse::Pong |
                    ControlCommandResponse::Ended |
                    ControlCommandResponse::Nil |
                    ControlCommandResponse::Void => {
                        if resp == ControlCommandResponse::Ended {
                            result = ControlHandleMessageResult::Close;
                        }
                        resp.to_str()
                    }
                    _ => ControlCommandResponse::Err.to_str(),
                }
            }
            _ => ControlCommandResponse::Err.to_str(),
        };

        if response.is_empty() == false {
            write!(stream, "{}{}", response, LINE_FEED).expect("write failed");
        }

        return result;
    }

    fn handle_message(
        shard: &mut ControlShard,
        message: &str,
    ) -> Result<ControlCommandResponse, Option<()>> {
        let mut parts = message.split_whitespace();
        let command = parts.next().unwrap_or("");

        debug!("will dispatch command: {}", command);

        match command {
            "" => Ok(ControlCommandResponse::Void),
            "FLUSHB" => ControlCommand::dispatch_flush_bucket(shard, parts),
            "FLUSHA" => ControlCommand::dispatch_flush_auth(shard, parts),
            "PING" => ControlCommand::dispatch_ping(),
            "SHARD" => ControlCommand::dispatch_shard(shard, parts),
            "QUIT" => ControlCommand::dispatch_quit(),
            _ => Ok(ControlCommandResponse::Nil),
        }
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;
use std::string::String;
use std::collections::HashMap;

struct Compiler {
    pub lines: Vec<String>,
    pub instructions: Vec<String>,
    pub labels: HashMap<String, u32>,
    pub bytecodes: Vec<u32>,
}

impl Compiler {
    pub fn new() -> Self {
        Compiler {
            lines: Vec::new(),
            instructions: Vec::new(),
            labels: HashMap::new(),
            bytecodes: Vec::new(),
        }
    }

    pub fn parse(&mut self, assembly: &str) {
        self.split_lines(assembly);
        self.strip_comments();
        self.compile_labels();
        self.compile_bytecodes();
    }

    fn compile_bytecodes(&mut self) {
        let mut instructions = self.instructions.iter();

        while let Some(instruction) = instructions.next() {
            match instruction.find(':') {
                Some(_) => {
                    // Ignore labels
                }
                None => {
                    let mut bytecodes = instruction.split_whitespace();
                    match bytecodes.next() {
                        Some("brk") => {
                            self.bytecodes.push(0);
                        }
                        Some(opcode) => {
                            match u32::from_str_radix(opcode, 16) {
                                Ok(bytecode) => {
                                    self.bytecodes.push(bytecode);
                                }
                                _ => {}
                            }
                        }
                        None => {}
                    }
                }
            }
        }
    }

    fn compile_labels(&mut self) {
        let mut instructions = self.instructions.iter();
        let mut address = 0;

        while let Some(instruction) = instructions.next() {
            match instruction.find(':') {
                Some(index) => {
                    self.labels.insert(instruction.split_at(index).0.to_string(), address);
                }
                None => {
                    address += 4;
                }
            }
        }
    }

    fn strip_comments(&mut self) {
        let mut lines = self.lines.iter();
        while let Some(line) = lines.next() {
            let trimmed_line = line.trim();
            if !trimmed_line.is_empty() && !trimmed_line.starts_with(";") {
                let instruction = match trimmed_line.find(';') {
                    Some(index) => trimmed_line.split_at(index).0,
                    None => trimmed_line,
                };
                self.instructions.push(instruction.trim().to_string());
            }
        }
    }

    fn split_lines(&mut self, assembly: &str) {
        let mut line = String::new();
        let mut chars = assembly.chars();

        while let Some(c) = chars.next() {
            match c {
                // Line Feed | Vertical Tab | Form Feed | Next Line | Line/Paragraph Separator
                '\u{000A}' | '\u{000B}' | '\u{000C}' | '\u{0085}' | '\u{2028}' | '\u{2029}' => {
                    self.lines.push(line);
                    line = String::new();
                }

                // Carriage Return
                '\u{000D}' => {
                    self.lines.push(line);
                    line = String::new();

                    // Carriage Return + Line Feed
                    match chars.next() {
                        Some(n) => {
                            if n != '\u{000A}' {
                                line.push(n);
                            }
                        }
                        None => {}
                    }
                }

                _ => {
                    line.push(c);
                }
            }
        }

        if !line.is_empty() {
            self.lines.push(line);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Compiler;
    use std::collections::HashMap;

    #[test]
    fn it_splits_lines_by_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_vertical_tab() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0B0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_form_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0C0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_next_line() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{0085}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_line_separator() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{2028}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_paragraph_separator() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{2029}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_ignors_trailing_separators() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0\r\n");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_strips_single_line_comments() {
        let mut compiler = Compiler::new();
        compiler.parse("; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_single_line_comments_starting_with_spaces() {
        let mut compiler = Compiler::new();
        compiler.parse(" ; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_single_line_comments_starting_with_tabs() {
        let mut compiler = Compiler::new();
        compiler.parse("\t; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_inline_comments() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_strips_inline_comments_starting_with_spaces() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0 ; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_strips_inline_comments_starting_with_tabs() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\t; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_trims_spaces_from_instructions() {
        let mut compiler = Compiler::new();
        compiler.parse(" 0 0 0 0 ");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_trims_tabs_from_instructions() {
        let mut compiler = Compiler::new();
        compiler.parse("\t0 0 0 0\t");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_compiles_addresses_for_labels() {
        let mut compiler = Compiler::new();
        compiler.parse("first:\nsecond:\n0 0 0 0\nthird:");

        let mut labels = HashMap::new();
        labels.insert("first".to_string(), 0);
        labels.insert("second".to_string(), 0);
        labels.insert("third".to_string(), 4);

        assert_eq!(compiler.labels, labels);
    }

    #[test]
    fn it_lets_the_last_label_win() {
        let mut compiler = Compiler::new();
        compiler.parse("label:\n0 0 0 0\nlabel:");

        let mut labels = HashMap::new();
        labels.insert("label".to_string(), 4);

        assert_eq!(compiler.labels, labels);
    }

    #[test]
    fn it_ignores_trailing_label_characters() {
        let mut compiler = Compiler::new();
        compiler.parse("label:with bits\n0 0 0 0\nlabel:with bytes");

        let mut labels = HashMap::new();
        labels.insert("label".to_string(), 4);

        assert_eq!(compiler.labels, labels);
    }

    #[test]
    fn it_parses_hex_for_opcode_0() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0");

        assert_eq!(compiler.bytecodes, vec![0]);
    }

    #[test]
    fn it_parses_brk_as_opcode_0() {
        let mut compiler = Compiler::new();
        compiler.parse("brk 0 0 0");

        assert_eq!(compiler.bytecodes, vec![0]);
    }
}
<commit_msg>Compile operand A.<commit_after>use std::vec::Vec;
use std::string::String;
use std::collections::HashMap;

struct Compiler {
    pub lines: Vec<String>,
    pub instructions: Vec<String>,
    pub labels: HashMap<String, u32>,
    pub bytecodes: Vec<u32>,
}

impl Compiler {
    pub fn new() -> Self {
        Compiler {
            lines: Vec::new(),
            instructions: Vec::new(),
            labels: HashMap::new(),
            bytecodes: Vec::new(),
        }
    }

    pub fn parse(&mut self, assembly: &str) {
        self.split_lines(assembly);
        self.strip_comments();
        self.compile_labels();
        self.compile_bytecodes();
    }

    fn compile_bytecodes(&mut self) {
        let mut instructions = self.instructions.iter();

        while let Some(instruction) = instructions.next() {
            match instruction.find(':') {
                Some(_) => {
                    // Ignore labels
                }
                None => {
                    let mut bytecodes = instruction.split_whitespace();

                    // Opcode
                    match bytecodes.next() {
                        Some("brk") => {
                            self.bytecodes.push(0);
                        }
                        Some(opcode) => {
                            match u32::from_str_radix(opcode, 16) {
                                Ok(bytecode) => {
                                    self.bytecodes.push(bytecode);
                                }
                                _ => {}
                            }
                        }
                        None => {}
                    }

                    // Operand A
                    match bytecodes.next() {
                        Some(operand) => {
                            match self.labels.get(operand) {
                                None => {
                                    match u32::from_str_radix(operand, 16) {
                                        Ok(bytecode) => {
                                            self.bytecodes.push(bytecode);
                                        }
                                        _ => {}
                                    }
                                }
                                Some(address) => {
                                    self.bytecodes.push(*address);
                                }
                            }
                        }
                        None => {}
                    }
                }
            }
        }
    }

    fn compile_labels(&mut self) {
        let mut instructions = self.instructions.iter();
        let mut address = 0;

        while let Some(instruction) = instructions.next() {
            match instruction.find(':') {
                Some(index) => {
                    self.labels.insert(instruction.split_at(index).0.to_string(), address);
                }
                None => {
                    address += 4;
                }
            }
        }
    }

    fn strip_comments(&mut self) {
        let mut lines = self.lines.iter();
        while let Some(line) = lines.next() {
            let trimmed_line = line.trim();
            if !trimmed_line.is_empty() && !trimmed_line.starts_with(";") {
                let instruction = match trimmed_line.find(';') {
                    Some(index) => trimmed_line.split_at(index).0,
                    None => trimmed_line,
                };
                self.instructions.push(instruction.trim().to_string());
            }
        }
    }

    fn split_lines(&mut self, assembly: &str) {
        let mut line = String::new();
        let mut chars = assembly.chars();

        while let Some(c) = chars.next() {
            match c {
                // Line Feed | Vertical Tab | Form Feed | Next Line | Line/Paragraph Separator
                '\u{000A}' | '\u{000B}' | '\u{000C}' | '\u{0085}' | '\u{2028}' | '\u{2029}' => {
                    self.lines.push(line);
                    line = String::new();
                }

                // Carriage Return
                '\u{000D}' => {
                    self.lines.push(line);
                    line = String::new();

                    // Carriage Return + Line Feed
                    match chars.next() {
                        Some(n) => {
                            if n != '\u{000A}' {
                                line.push(n);
                            }
                        }
                        None => {}
                    }
                }

                _ => {
                    line.push(c);
                }
            }
        }

        if !line.is_empty() {
            self.lines.push(line);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Compiler;
    use std::collections::HashMap;

    #[test]
    fn it_splits_lines_by_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_vertical_tab() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0B0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_form_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\x0C0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_carriage_return_line_feed() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_next_line() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{0085}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_line_separator() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{2028}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_splits_lines_by_paragraph_separator() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\u{2029}0 0 0 0");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_ignors_trailing_separators() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\r\n0 0 0 0\r\n");

        assert_eq!(compiler.lines.len(), 2);
    }

    #[test]
    fn it_strips_single_line_comments() {
        let mut compiler = Compiler::new();
        compiler.parse("; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_single_line_comments_starting_with_spaces() {
        let mut compiler = Compiler::new();
        compiler.parse(" ; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_single_line_comments_starting_with_tabs() {
        let mut compiler = Compiler::new();
        compiler.parse("\t; single line comment\n0 0 0 0\n");

        assert_eq!(compiler.lines.len(), 2);
        assert_eq!(compiler.instructions.len(), 1);
    }

    #[test]
    fn it_strips_inline_comments() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_strips_inline_comments_starting_with_spaces() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0 ; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_strips_inline_comments_starting_with_tabs() {
        let mut compiler = Compiler::new();
        compiler.parse("0 0 0 0\t; inline comment\n");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_trims_spaces_from_instructions() {
        let mut compiler = Compiler::new();
        compiler.parse(" 0 0 0 0 ");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_trims_tabs_from_instructions() {
        let mut compiler = Compiler::new();
        compiler.parse("\t0 0 0 0\t");

        assert_eq!(compiler.lines.len(), 1);
        assert_eq!(compiler.instructions, vec!["0 0 0 0"]);
    }

    #[test]
    fn it_compiles_addresses_for_labels() {
        let mut compiler = Compiler::new();
        compiler.parse("first:\nsecond:\n0 0 0 0\nthird:");

        let mut labels = HashMap::new();
        labels.insert("first".to_string(), 0);
        labels.insert("second".to_string(), 0);
        labels.insert("third".to_string(), 4);

        assert_eq!(compiler.labels, labels);
    }

    #[test]
    fn it_lets_the_last_label_win() {
        let mut compiler = Compiler::new();
        compiler.parse("label:\n0 0 0 0\nlabel:");

        let mut labels = HashMap::new();
        labels.insert("label".to_string(), 4);

        assert_eq!(compiler.labels, labels);
    }

    #[test]
    fn it_ignores_trailing_label_characters() {
        let mut compiler = Compiler::new();
        compiler.parse("label:with bits\n0 0 0 0\nlabel:with bytes");

        let mut labels = HashMap::new();
        labels.insert("label".to_string(), 4);

        assert_eq!(compiler.labels, labels);
    }

    #[test]
    fn it_parses_hex_for_opcode_0() {
        let mut compiler = Compiler::new();
        compiler.parse("0");

        assert_eq!(compiler.bytecodes, vec![0x0]);
    }

    #[test]
    fn it_parses_brk_as_opcode_0() {
        let mut compiler = Compiler::new();
        compiler.parse("brk");

        assert_eq!(compiler.bytecodes, vec![0x0]);
    }

    #[test]
    fn it_parses_operand_A_as_hex() {
        let mut compiler = Compiler::new();
        compiler.parse("brk f");

        assert_eq!(compiler.bytecodes, vec![0x0, 0xf]);
    }

    #[test]
    fn it_parses_operand_A_as_a_label() {
        let mut compiler = Compiler::new();
        compiler.parse("brk end\nend:");

        assert_eq!(compiler.bytecodes, vec![0x0, 0x4]);
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate x11;

use x11::xlib;

use std::rc::{ Rc, Weak };
use std::cell::RefCell;
use std::boxed::Box;
use std::ptr;
use super::layout;
use super::super::libx;

pub const TITLE_HEIGHT: libc::c_int = 20;

pub enum Mode {
    Normal,
    Fullscreen,
}

pub struct Container {
    pub id: Option<xlib::Window>,
    pub visible: bool,
    pub titlebar_height: usize,
    parent: *mut Container,
    pub clients: Vec<Container>,
    pub mode: Mode,
    pub titlebar: Option<layout::Rectangle>,
    pub context: libx::Context,

    pub layout: layout::Type,
    pub direction: layout::Direction,
}

impl PartialEq for Container {
    fn eq(&self, other: &Self) -> bool {
        self.raw_id() == other.raw_id()
    }
}

impl Container {
    pub fn new(context: libx::Context) -> Container{
        let pid = context.root;
        let attrs = libx::get_window_attributes(context, pid);

        let id = libx::create_window(context, pid,
                                     attrs.x, attrs.y,
                                     attrs.width as libc::c_uint,
                                     attrs.height as libc::c_uint);
        libx::select_input(context, id, xlib::SubstructureNotifyMask | xlib::SubstructureRedirectMask | xlib::ButtonPressMask);
        Container {
            context: context,
            clients: Vec::new(),
            visible: false,
            id: Some(id),
            mode: Mode::Normal,
            category: Type::Container,
            parent: ptr::null_mut(),
            titlebar: None,
            titlebar_height: 0,

            layout: layout::Type::Tiling,
            direction: layout::Direction::Horizontal,
        }
    }

    pub fn from_id(context: libx::Context, id: xlib::Window) -> Container {
        Container {
            context: context,
            clients: Vec::new(),
            visible: false,
            id: Some(id),
            mode: Mode::Normal,
            parent: ptr::null_mut(),
            titlebar: None,
            titlebar_height: 0,

            layout: layout::Type::Tiling,
            direction: layout::Direction::Horizontal,
        }
    }

    pub fn print_tree(&self, indent: i32) {
        for i in 0..indent {
            print!(" ");
        }
        let attrs = libx::get_window_attributes(self.context, self.raw_id());
        let pid = match self.get_parent() {
            Some(p) => { p.raw_id() }
            None => { 0}
        };
        println!("C {} pid:{} x:{} y:{} w:{} h:{}", self.raw_id(), pid, attrs.x, attrs.y, attrs.width, attrs.height);
        for client in self.clients.iter() {
            client.print_tree(indent+4);
        }
    }

    pub fn raw_id(&self) -> xlib::Window {
        // let mut id: xlib::Window = 0;
        // if self.id.is_some() {
        //     id = self.id.unwrap();
        // }
        // if self.display.is_some() {
        //     id = unsafe {
        //         self.display.as_ref().unwrap().get_window().unwrap().platform_window() as xlib::Window
        //     };
        // };
        // id
        self.id.unwrap()
    }

    // pub fn is_top(&self) -> bool {
    //     let top = self.get_top();
    //     match top {
    //         Some(w) => {
    //             w.id == self.id
    //         }
    //         Noen => false
    //     }
    // }

    pub fn is_empty(&self) -> bool{
        self.clients.is_empty()
    }

    pub fn size(&self) -> usize {
        self.clients.len()
    }

    pub fn be_parent(&mut self, client: &mut Container) {
        let need_reprent = match client.get_parent() {
            Some(p) => {
                if p.raw_id() == self.raw_id() { false } else { true }
            }
            None => {
                true
            }
        };
        if need_reprent {
            libx::reparent(self.context, client.raw_id(), self.raw_id(), 0, 0);
            client.parent = self;
        }
    }

    pub fn add(&mut self, mut client: Container) {
        self.be_parent(&mut client);
        self.clients.push(client);
    }

    pub fn insert(&mut self, index: usize,  mut client: Container) {
        self.be_parent(&mut client);
        self.clients.insert(index, client);
    }

    pub fn remove(&mut self, id: xlib::Window) -> Option<Container>{
        let res = self.contain(id);
        match res {
            Some(index) => {
                let r = self.clients.remove(index);
                Some(r)
            }
            None => {
                // for c in self.clients.iter_mut() {
                //     let r = c.remove(id);
                //     if r.is_some(){
                //         return r;
                //     }
                // }
                None
            }
        }
    }

    /// remove App container and destroy all its parent containers that are empty
    pub fn tree_remove(&mut self, id: xlib::Window) -> Option<Container> {
        println!("try remove {} from {}", id, self.raw_id());
        let res = self.contain(id);
        match res {
            Some(i) => {
                let r = self.clients.remove(i);
                Some(r)
            }
            None => {
                let mut r: Option<Container> = None;
                let mut index: i32 = -1;
                for (i, c) in self.clients.iter_mut().enumerate() {
                    r = c.tree_remove(id);
                    if r.is_some(){
                        index = i as i32;
                        break
                    }
                }
                if index >= 0 {
                    let i = index as usize;
                    let size = self.get_child(i).unwrap().size();
                    if size == 0 {
                        let container = self.clients.remove(i);
                        container.destroy();
                    }
                }
                r
            }
        }
    }
    pub fn get_child(&mut self, index: usize) -> Option<&mut Container> {
        self.clients.get_mut(index)
    }

    pub fn get_parent(&self) -> Option<&mut Container> {
        if self.parent == ptr::null_mut() {
            None
        }
        else{
            Some(unsafe{ &mut *self.parent })
        }
    }

    pub fn tree_search(&mut self, id: xlib::Window) -> Option<&mut Container>{
        if self.raw_id() == id {
            return Some(self);
        }

        for client in self.clients.iter_mut() {
            let r = client.tree_search(id);
            if r.is_some(){
                return r
            }
        }
        None
    }

    pub fn contain(&self, id: xlib::Window) -> Option<usize>{
        self.clients.iter().position(|x| (*x).raw_id() == id)
    }

    pub fn configure(&mut self, x: i32, y: i32, width: usize, height: usize) {
        libx::resize_window(self.context, self.raw_id(), x, y, width, height);
        // layout for children clients
        self.update_layout();
    }

    pub fn update_layout(&mut self) {
        layout::update_layout(self);
    }

    pub fn map(&self) {
        // self.visible = true;
        libx::map_window(self.context, self.raw_id());
        for client in self.clients.iter() {
            client.map();
        }
    }

    pub fn unmap(&self) {
        // self.visible = false;
        for client in self.clients.iter() {
            client.unmap();
        }
        libx::unmap_window(self.context, self.raw_id());
    }

    pub fn destroy(&self) -> bool {
        // can distroy only if it has no clients
        if self.clients.is_empty() {
            unsafe{
                xlib::XDestroyWindow(self.context.display, self.raw_id());
                true
            }
        }
        else {
            false
        }
    }

    pub fn next_client(&mut self, id: xlib::Window) -> Option<&mut Container>{
        match self.contain(id) {
            Some(i) => {
                let mut next = i+1;
                if next == self.size() {
                    next = 0;
                }
                self.get_child(next)
            }
            None => {
                None
            }
        }
    }

    pub fn last_client(&mut self, id: xlib::Window) -> Option<&mut Container>{
        match self.contain(id) {
            Some(i) => {
                let mut last = i-1;
                if last < 0 {
                    last = self.size() - 1
                }
                self.get_child(last)
            }
            None => {
                None
            }
        }
    }

    pub fn change_layout(&mut self, layout_type: layout::Type) {
        if self.layout == layout_type {
            match self.direction {
                layout::Direction::Horizontal => {
                    self.direction = layout::Direction::Vertical;
                }
                layout::Direction::Vertical => {
                    self.direction = layout::Direction::Horizontal;
                }
                _ => {}
            }
        }
        else{
            self.layout = layout_type;
            self.direction = layout::Direction::Horizontal;
        }
    }

    pub fn split(&mut self) -> bool {
        if !self.is_empty() {
            return false;
        }

        let mut container = Container::new(self.context);
        // add to parent
        match self.get_parent() {
            Some(p) => {
                let attrs = libx::get_window_attributes(self.context, self.raw_id());

                libx::reparent(self.context, container.raw_id(), p.raw_id(),
                               0, 0);
                // configure to the same size and position like old one
                container.configure(attrs.x, attrs.y,
                                    attrs.width as usize,
                                    attrs.height as usize);
            }
            None => {}
        }

        // swap the property
        let id = self.id;
        self.id = container.id;
        container.id = id;
        container.titlebar_height = self.titlebar_height;
        self.add(container);
        self.map();
        true
    }

    pub fn focus(&self) {
        let id = self.raw_id();
        libx::set_input_focus(self.context, id);
        libx::raise_window(self.context, id);
        self.decorate(true);
    }

    pub fn unfocus(&self) {
        // libx::lower_window(self.context, self.id);
        self.decorate(false);
    }

    pub fn switch_client(&self) {
        let (x, _) = libx::get_input_focus(self.context);

    }

    pub fn decorate(&self, focused: bool) {
        match self.get_parent() {
            Some(p) => {
                layout::decorate(self, focused);
            }
            None => {}
        }

    }

    // fullscreen & normal toggle
    pub fn mode_toggle(&mut self) {
        let context = self.context;
        let id = self.raw_id();
        match self.mode {
            Mode::Normal => {
                self.mode = Mode::Fullscreen;
                println!("fullscreen {} {}", id, context.root);
                libx::reparent(context, id, context.root, 0, 0);

                let width = libx::display_width(context, context.screen_num);
                let height = libx::display_height(context, context.screen_num);
                libx::resize_window(context, id, 0, 0,
                                    width as usize,
                                    height as usize);
            }
            Mode::Fullscreen => {
                self.mode = Mode::Normal;

                match self.get_parent() {
                    Some(p) => {
                        let pid = p.raw_id();
                        libx::reparent(context, id, pid, 0, 0);
                        p.update_layout();
                    }
                    None => {
                        let pid =  context.root;
                        libx::reparent(context, id, pid, 0, 0);
                    }
                };
            }
        }
    }

    // decide which client when click on titlebar
    pub fn query_point(&self, x: i32, y: i32) -> Option<&Container>{
        for client in self.clients.iter() {
            match client.titlebar {
                Some(rec) => {
                    if rec.contain(x, y) {
                        return Some(client);
                    }
                }
                None => {}
            }
        }
        None
    }
}

// #[test]
// fn window_eq() {
//     use std::ptr;
//     let c1 = libx::Context {
//         display: ptr::null_mut()
//     };
//     let w1 = Window::new(c1, 1);
//     let c2 = libx::Context {
//         display: ptr::null_mut()
//     };
//     let w2 = Window::new(c2, 1);
//     assert_eq!(w1, w2);
// }
<commit_msg>remove useless use<commit_after>extern crate libc;
extern crate x11;

use x11::xlib;
use std::ptr;
use super::layout;
use super::super::libx;

pub const TITLE_HEIGHT: libc::c_int = 20;

pub enum Mode {
    Normal,
    Fullscreen,
}

pub struct Container {
    pub id: Option<xlib::Window>,
    pub visible: bool,
    pub titlebar_height: usize,
    parent: *mut Container,
    pub clients: Vec<Container>,
    pub mode: Mode,
    pub titlebar: Option<layout::Rectangle>,
    pub context: libx::Context,

    pub layout: layout::Type,
    pub direction: layout::Direction,
}

impl PartialEq for Container {
    fn eq(&self, other: &Self) -> bool {
        self.raw_id() == other.raw_id()
    }
}

impl Container {
    pub fn new(context: libx::Context) -> Container{
        let pid = context.root;
        let attrs = libx::get_window_attributes(context, pid);

        let id = libx::create_window(context, pid,
                                     attrs.x, attrs.y,
                                     attrs.width as libc::c_uint,
                                     attrs.height as libc::c_uint);
        libx::select_input(context, id, xlib::SubstructureNotifyMask | xlib::SubstructureRedirectMask | xlib::ButtonPressMask);
        Container {
            context: context,
            clients: Vec::new(),
            visible: false,
            id: Some(id),
            mode: Mode::Normal,
            category: Type::Container,
            parent: ptr::null_mut(),
            titlebar: None,
            titlebar_height: 0,

            layout: layout::Type::Tiling,
            direction: layout::Direction::Horizontal,
        }
    }

    pub fn from_id(context: libx::Context, id: xlib::Window) -> Container {
        Container {
            context: context,
            clients: Vec::new(),
            visible: false,
            id: Some(id),
            mode: Mode::Normal,
            parent: ptr::null_mut(),
            titlebar: None,
            titlebar_height: 0,

            layout: layout::Type::Tiling,
            direction: layout::Direction::Horizontal,
        }
    }

    pub fn print_tree(&self, indent: i32) {
        for i in 0..indent {
            print!(" ");
        }
        let attrs = libx::get_window_attributes(self.context, self.raw_id());
        let pid = match self.get_parent() {
            Some(p) => { p.raw_id() }
            None => { 0}
        };
        println!("C {} pid:{} x:{} y:{} w:{} h:{}", self.raw_id(), pid, attrs.x, attrs.y, attrs.width, attrs.height);
        for client in self.clients.iter() {
            client.print_tree(indent+4);
        }
    }

    pub fn raw_id(&self) -> xlib::Window {
        // let mut id: xlib::Window = 0;
        // if self.id.is_some() {
        //     id = self.id.unwrap();
        // }
        // if self.display.is_some() {
        //     id = unsafe {
        //         self.display.as_ref().unwrap().get_window().unwrap().platform_window() as xlib::Window
        //     };
        // };
        // id
        self.id.unwrap()
    }

    // pub fn is_top(&self) -> bool {
    //     let top = self.get_top();
    //     match top {
    //         Some(w) => {
    //             w.id == self.id
    //         }
    //         Noen => false
    //     }
    // }

    pub fn is_empty(&self) -> bool{
        self.clients.is_empty()
    }

    pub fn size(&self) -> usize {
        self.clients.len()
    }

    pub fn be_parent(&mut self, client: &mut Container) {
        let need_reprent = match client.get_parent() {
            Some(p) => {
                if p.raw_id() == self.raw_id() { false } else { true }
            }
            None => {
                true
            }
        };
        if need_reprent {
            libx::reparent(self.context, client.raw_id(), self.raw_id(), 0, 0);
            client.parent = self;
        }
    }

    pub fn add(&mut self, mut client: Container) {
        self.be_parent(&mut client);
        self.clients.push(client);
    }

    pub fn insert(&mut self, index: usize,  mut client: Container) {
        self.be_parent(&mut client);
        self.clients.insert(index, client);
    }

    pub fn remove(&mut self, id: xlib::Window) -> Option<Container>{
        let res = self.contain(id);
        match res {
            Some(index) => {
                let r = self.clients.remove(index);
                Some(r)
            }
            None => {
                // for c in self.clients.iter_mut() {
                //     let r = c.remove(id);
                //     if r.is_some(){
                //         return r;
                //     }
                // }
                None
            }
        }
    }

    /// remove App container and destroy all its parent containers that are empty
    pub fn tree_remove(&mut self, id: xlib::Window) -> Option<Container> {
        println!("try remove {} from {}", id, self.raw_id());
        let res = self.contain(id);
        match res {
            Some(i) => {
                let r = self.clients.remove(i);
                Some(r)
            }
            None => {
                let mut r: Option<Container> = None;
                let mut index: i32 = -1;
                for (i, c) in self.clients.iter_mut().enumerate() {
                    r = c.tree_remove(id);
                    if r.is_some(){
                        index = i as i32;
                        break
                    }
                }
                if index >= 0 {
                    let i = index as usize;
                    let size = self.get_child(i).unwrap().size();
                    if size == 0 {
                        let container = self.clients.remove(i);
                        container.destroy();
                    }
                }
                r
            }
        }
    }
    pub fn get_child(&mut self, index: usize) -> Option<&mut Container> {
        self.clients.get_mut(index)
    }

    pub fn get_parent(&self) -> Option<&mut Container> {
        if self.parent == ptr::null_mut() {
            None
        }
        else{
            Some(unsafe{ &mut *self.parent })
        }
    }

    pub fn tree_search(&mut self, id: xlib::Window) -> Option<&mut Container>{
        if self.raw_id() == id {
            return Some(self);
        }

        for client in self.clients.iter_mut() {
            let r = client.tree_search(id);
            if r.is_some(){
                return r
            }
        }
        None
    }

    pub fn contain(&self, id: xlib::Window) -> Option<usize>{
        self.clients.iter().position(|x| (*x).raw_id() == id)
    }

    pub fn configure(&mut self, x: i32, y: i32, width: usize, height: usize) {
        libx::resize_window(self.context, self.raw_id(), x, y, width, height);
        // layout for children clients
        self.update_layout();
    }

    pub fn update_layout(&mut self) {
        layout::update_layout(self);
    }

    pub fn map(&self) {
        // self.visible = true;
        libx::map_window(self.context, self.raw_id());
        for client in self.clients.iter() {
            client.map();
        }
    }

    pub fn unmap(&self) {
        // self.visible = false;
        for client in self.clients.iter() {
            client.unmap();
        }
        libx::unmap_window(self.context, self.raw_id());
    }

    pub fn destroy(&self) -> bool {
        // can distroy only if it has no clients
        if self.clients.is_empty() {
            unsafe{
                xlib::XDestroyWindow(self.context.display, self.raw_id());
                true
            }
        }
        else {
            false
        }
    }

    pub fn next_client(&mut self, id: xlib::Window) -> Option<&mut Container>{
        match self.contain(id) {
            Some(i) => {
                let mut next = i+1;
                if next == self.size() {
                    next = 0;
                }
                self.get_child(next)
            }
            None => {
                None
            }
        }
    }

    pub fn last_client(&mut self, id: xlib::Window) -> Option<&mut Container>{
        match self.contain(id) {
            Some(i) => {
                let mut last = i-1;
                if last < 0 {
                    last = self.size() - 1
                }
                self.get_child(last)
            }
            None => {
                None
            }
        }
    }

    pub fn change_layout(&mut self, layout_type: layout::Type) {
        if self.layout == layout_type {
            match self.direction {
                layout::Direction::Horizontal => {
                    self.direction = layout::Direction::Vertical;
                }
                layout::Direction::Vertical => {
                    self.direction = layout::Direction::Horizontal;
                }
                _ => {}
            }
        }
        else{
            self.layout = layout_type;
            self.direction = layout::Direction::Horizontal;
        }
    }

    pub fn split(&mut self) -> bool {
        if !self.is_empty() {
            return false;
        }

        let mut container = Container::new(self.context);
        // add to parent
        match self.get_parent() {
            Some(p) => {
                let attrs = libx::get_window_attributes(self.context, self.raw_id());

                libx::reparent(self.context, container.raw_id(), p.raw_id(),
                               0, 0);
                // configure to the same size and position like old one
                container.configure(attrs.x, attrs.y,
                                    attrs.width as usize,
                                    attrs.height as usize);
            }
            None => {}
        }

        // swap the property
        let id = self.id;
        self.id = container.id;
        container.id = id;
        container.titlebar_height = self.titlebar_height;
        self.add(container);
        self.map();
        true
    }

    pub fn focus(&self) {
        let id = self.raw_id();
        libx::set_input_focus(self.context, id);
        libx::raise_window(self.context, id);
        self.decorate(true);
    }

    pub fn unfocus(&self) {
        // libx::lower_window(self.context, self.id);
        self.decorate(false);
    }

    pub fn switch_client(&self) {
        let (x, _) = libx::get_input_focus(self.context);

    }

    pub fn decorate(&self, focused: bool) {
        match self.get_parent() {
            Some(p) => {
                layout::decorate(self, focused);
            }
            None => {}
        }

    }

    // fullscreen & normal toggle
    pub fn mode_toggle(&mut self) {
        let context = self.context;
        let id = self.raw_id();
        match self.mode {
            Mode::Normal => {
                self.mode = Mode::Fullscreen;
                println!("fullscreen {} {}", id, context.root);
                libx::reparent(context, id, context.root, 0, 0);

                let width = libx::display_width(context, context.screen_num);
                let height = libx::display_height(context, context.screen_num);
                libx::resize_window(context, id, 0, 0,
                                    width as usize,
                                    height as usize);
            }
            Mode::Fullscreen => {
                self.mode = Mode::Normal;

                match self.get_parent() {
                    Some(p) => {
                        let pid = p.raw_id();
                        libx::reparent(context, id, pid, 0, 0);
                        p.update_layout();
                    }
                    None => {
                        let pid =  context.root;
                        libx::reparent(context, id, pid, 0, 0);
                    }
                };
            }
        }
    }

    // decide which client when click on titlebar
    pub fn query_point(&self, x: i32, y: i32) -> Option<&Container>{
        for client in self.clients.iter() {
            match client.titlebar {
                Some(rec) => {
                    if rec.contain(x, y) {
                        return Some(client);
                    }
                }
                None => {}
            }
        }
        None
    }
}

// #[test]
// fn window_eq() {
//     use std::ptr;
//     let c1 = libx::Context {
//         display: ptr::null_mut()
//     };
//     let w1 = Window::new(c1, 1);
//     let c2 = libx::Context {
//         display: ptr::null_mut()
//     };
//     let w2 = Window::new(c2, 1);
//     assert_eq!(w1, w2);
// }
<|endoftext|>


<commit_before>use std::io::BufReader;
use self::Token::{
	TokPassageName, TokTagStart, TokTagEnd, TokTag,
	TokEmpty, TokMakroStart, TokMakroEnd, TokVariable,
	TokSet, TokAssign, TokInt, TokFloat, TokNumOp, TokCompOp,
	TokLogOp, TokText, TokFormatBold, TokFormatItalic,
	TokFormatUnder,	TokFormatStrike, TokFormatSub, TokFormatSup,
	TokFormatMonoStart,	TokFormatMonoEnd, TokString, TokBracketOpen,
	TokBracketClose, TokIf, TokElse, TokEndIf
};

pub fn lex(input :String) -> Vec<Token> {
   	let inp = BufReader::new(input.as_bytes());
	let lexer = TweeLexer::new(inp);
	lexer.collect()
}

#[derive(PartialEq,Debug)]
pub enum Token {
	TokPassageName (String),
	TokTagStart,
	TokTagEnd,
	TokTag (String),
	TokText (String),
	TokFormatBold,
	TokFormatItalic,
	TokFormatUnder,
	TokFormatStrike,
	TokFormatSub,
	TokFormatSup,
	TokFormatMonoStart,
	TokFormatMonoEnd,
	TokMakroStart,
	TokMakroEnd,
	TokBracketOpen,
	TokBracketClose,
	TokVariable (String),
	TokInt (i32),
	TokFloat (f32),
	TokString (String),
	TokSet,
	TokAssign,
	TokNumOp (String),
	TokCompOp (String),
	TokLogOp (String),
	TokIf,
	TokElse,
	TokEndIf,
	TokEmpty
}

rustlex! TweeLexer {
	let DIGIT = ['0'-'9'];
	let LETTER_S = ['a'-'z'];
	let LETTER_L = ['A'-'Z'];
	let LETTER = (LETTER_S|LETTER_L);
	let SPECIAL = ["'._$"];
	let SPACE = ' ';
	let UNDERSCORE = '_';
	let NEWLINE = '\n';

	let CHAR = LETTER_S | LETTER_L | DIGIT | SPECIAL;
	let WORD = CHAR CHAR*;

	let PASSAGE_CHAR = SPACE | LETTER_S | LETTER_L | DIGIT | SPECIAL;
	let PASSAGE_START = "::";
	let PASSAGE_NAME = PASSAGE_CHAR PASSAGE_CHAR*;
	let TAG_START = '[';
	let TAG_END = ']';

	// TODO what is allowed?
	let TEXT = (LETTER | DIGIT | SPACE | NEWLINE)+;

	let FORMAT_ITALIC = "//";
	let FORMAT_BOLD = '"';
	let FORMAT_UNDER = "__";
	let FORMAT_STRIKE = "==";
	let FORMAT_SUB = "~~";
	let FORMAT_SUP = "^^";
	let FORMAT_MONO_START = "{{{";
	let FORMAT_MONO_END = "}}}";

	let MAKRO_START = "<<";
	let MAKRO_END = ">>";

	let BR_OPEN = '(';
	let BR_CLOSE = ')';

	let VAR_CHAR = LETTER | DIGIT | UNDERSCORE;
	let VAR_NAME = '$' (LETTER | UNDERSCORE) VAR_CHAR*;

	let NUMBER = DIGIT DIGIT*;
	let INT = '-'? NUMBER;
	// TODO exact definition of float in twee
	let FLOAT = (INT "." NUMBER?) | ("." NUMBER);

	let STRING = ('"' [^'"']* '"') | ("'" [^"'"]* "'");

	let SET = "set";
	let ASSIGN = "=" | "to";
	let IF = "if";
	let ELSE = "else";
	let END_IF = "endif";

	let NUM_OP = ["+-*/%"];
	let COMP_OP = "is" | "==" | "eq" | "neq" | ">" | "gt" | ">=" | "gte" | "<" | "lt" | "<=" | "lte";
	let LOG_OP = "and" | "or" | "not";

	INITIAL {
		PASSAGE_START => |lexer:&mut TweeLexer<R>| {
			lexer.PASSAGE();
			Some(TokEmpty)
		}

		MAKRO_START => |lexer:&mut TweeLexer<R>| {
			lexer.MAKRO();
			Some(TokMakroStart)
		}

		FORMAT_ITALIC => |_:&mut TweeLexer<R>| Some(TokFormatItalic)
		FORMAT_BOLD => |_:&mut TweeLexer<R>| Some(TokFormatBold)
		FORMAT_UNDER => |_:&mut TweeLexer<R>| Some(TokFormatUnder)
		FORMAT_STRIKE => |_:&mut TweeLexer<R>| Some(TokFormatStrike)
		FORMAT_SUB => |_:&mut TweeLexer<R>| Some(TokFormatSub)
		FORMAT_SUP => |_:&mut TweeLexer<R>| Some(TokFormatSup)
		FORMAT_MONO_START => |_:&mut TweeLexer<R>| Some(TokFormatMonoStart)
		FORMAT_MONO_END => |_:&mut TweeLexer<R>| Some(TokFormatMonoEnd)

		TEXT => |lexer:&mut TweeLexer<R>| Some(TokText(lexer.yystr()))
	}

	PASSAGE {
		// TODO trim()
		PASSAGE_NAME => |lexer:&mut TweeLexer<R>| Some(TokPassageName(lexer.yystr()))
		TAG_START => |lexer:&mut TweeLexer<R>| {
			lexer.TAGS();
			Some(TokTagStart)
		}
		NEWLINE => |lexer:&mut TweeLexer<R>| {
			lexer.INITIAL();
			Some(TokEmpty)
		}
	}

	TAGS {
		WORD => |lexer:&mut TweeLexer<R>| Some(TokTag(lexer.yystr()))
		TAG_END => |lexer:&mut TweeLexer<R>| {
			lexer.PASSAGE();
			Some(TokTagEnd)
		}
	}

	MAKRO {
		MAKRO_END => |lexer:&mut TweeLexer<R>| {
			lexer.INITIAL();
			Some(TokMakroEnd)
		}
		VAR_NAME =>  |lexer:&mut TweeLexer<R>| Some(TokVariable(lexer.yystr()))
		FLOAT =>  |lexer:&mut TweeLexer<R>| Some(TokFloat(lexer.yystr()[..].parse().unwrap()))
		INT =>  |lexer:&mut TweeLexer<R>| Some(TokInt(lexer.yystr()[..].parse().unwrap()))
		STRING =>  |lexer:&mut TweeLexer<R>| Some(TokString(lexer.yystr()))
		SET =>  |_:&mut TweeLexer<R>| Some(TokSet)
		ASSIGN =>  |_:&mut TweeLexer<R>| Some(TokAssign)
		IF =>  |_:&mut TweeLexer<R>| Some(TokIf)
		ELSE =>  |_:&mut TweeLexer<R>| Some(TokElse)
		END_IF =>  |_:&mut TweeLexer<R>| Some(TokEndIf)
		NUM_OP =>  |lexer:&mut TweeLexer<R>| Some(TokNumOp(lexer.yystr()))
		COMP_OP =>  |lexer:&mut TweeLexer<R>| Some(TokCompOp(lexer.yystr()))
		LOG_OP =>  |lexer:&mut TweeLexer<R>| Some(TokLogOp(lexer.yystr()))
		BR_OPEN =>  |_:&mut TweeLexer<R>| Some(TokBracketOpen)
		BR_CLOSE =>  |_:&mut TweeLexer<R>| Some(TokBracketClose)
	}

}

#[test]
fn it_works() {

}
<commit_msg>Add recognition of passage links & usage of "None"<commit_after>use std::io::BufReader;
use self::Token::{
	TokPassageName, TokTagStart, TokTagEnd, TokTag,
	TokMakroStart, TokMakroEnd, TokVariable,
	TokSet, TokAssign, TokInt, TokFloat, TokNumOp, TokCompOp,
	TokLogOp, TokText, TokFormatBold, TokFormatItalic,
	TokFormatUnder,	TokFormatStrike, TokFormatSub, TokFormatSup,
	TokFormatMonoStart,	TokFormatMonoEnd, TokString, TokBracketOpen,
	TokBracketClose, TokIf, TokElse, TokEndIf, TokPassageLink
};

pub fn lex(input :String) -> Vec<Token> {
   	let inp = BufReader::new(input.as_bytes());
	let lexer = TweeLexer::new(inp);
	lexer.collect()
}

#[derive(PartialEq,Debug)]
pub enum Token {
	TokPassageName (String),
	TokTagStart,
	TokTagEnd,
	TokPassageLink (String, String),
	TokTag (String),
	TokText (String),
	TokFormatBold,
	TokFormatItalic,
	TokFormatUnder,
	TokFormatStrike,
	TokFormatSub,
	TokFormatSup,
	TokFormatMonoStart,
	TokFormatMonoEnd,
	TokMakroStart,
	TokMakroEnd,
	TokBracketOpen,
	TokBracketClose,
	TokVariable (String),
	TokInt (i32),
	TokFloat (f32),
	TokString (String),
	TokSet,
	TokAssign,
	TokNumOp (String),
	TokCompOp (String),
	TokLogOp (String),
	TokIf,
	TokElse,
	TokEndIf
}

rustlex! TweeLexer {
	let DIGIT = ['0'-'9'];
	let LETTER_S = ['a'-'z'];
	let LETTER_L = ['A'-'Z'];
	let LETTER = (LETTER_S|LETTER_L);
	let SPECIAL = ["'._$"];
	let SPACE = ' ';
	let UNDERSCORE = '_';
	let NEWLINE = '\n';

	let CHAR = LETTER_S | LETTER_L | DIGIT | SPECIAL;
	let WORD = CHAR CHAR*;

	// TODO what is allowed?
	let TEXT = (LETTER | DIGIT | SPACE | NEWLINE)+;
	let TEXTLINES = (LETTER | DIGIT | SPACE | NEWLINE)+;

	let PASSAGE_CHAR = SPACE | LETTER_S | LETTER_L | DIGIT | SPECIAL;
	let PASSAGE_START = "::";
	let PASSAGE_NAME = PASSAGE_CHAR PASSAGE_CHAR*;
	let TAG_START = '[';
	let TAG_END = ']';

	let LINK_SIMPLE = "[[" PASSAGE_NAME "]]";
	let LINK_LABELED = "[[" TEXT "|" PASSAGE_NAME "]]";

	let FORMAT_ITALIC = "//";
	let FORMAT_BOLD = '"';
	let FORMAT_UNDER = "__";
	let FORMAT_STRIKE = "==";
	let FORMAT_SUB = "~~";
	let FORMAT_SUP = "^^";
	let FORMAT_MONO_START = "{{{";
	let FORMAT_MONO_END = "}}}";

	let MAKRO_START = "<<";
	let MAKRO_END = ">>";

	let BR_OPEN = '(';
	let BR_CLOSE = ')';

	let VAR_CHAR = LETTER | DIGIT | UNDERSCORE;
	let VAR_NAME = '$' (LETTER | UNDERSCORE) VAR_CHAR*;

	let NUMBER = DIGIT DIGIT*;
	let INT = '-'? NUMBER;
	// TODO exact definition of float in twee
	let FLOAT = (INT "." NUMBER?) | ("." NUMBER);

	let STRING = ('"' [^'"']* '"') | ("'" [^"'"]* "'");

	let SET = "set";
	let ASSIGN = "=" | "to";
	let IF = "if";
	let ELSE = "else";
	let END_IF = "endif";

	let NUM_OP = ["+-*/%"];
	let COMP_OP = "is" | "==" | "eq" | "neq" | ">" | "gt" | ">=" | "gte" | "<" | "lt" | "<=" | "lte";
	let LOG_OP = "and" | "or" | "not";

	INITIAL {
		PASSAGE_START => |lexer:&mut TweeLexer<R>| -> Option<Token>{
			lexer.PASSAGE();
			None
		}

		MAKRO_START => |lexer:&mut TweeLexer<R>| {
			lexer.MAKRO();
			Some(TokMakroStart)
		}

		LINK_SIMPLE =>  |lexer:&mut TweeLexer<R>| {
			let s =  lexer.yystr();
			let trimmed = &s[2 .. s.len()-2];
			let name = &trimmed.to_string();
			Some(TokPassageLink(name.clone(), name.clone()))
		}

		LINK_LABELED =>  |lexer:&mut TweeLexer<R>| {
			let s =  lexer.yystr();
			let trimmed = &s[2 .. s.len()-2];
			let matches = &trimmed.split("|").collect::<Vec<&str>>();
			assert_eq!(matches.len(), 2);
			let text = matches[0].to_string();
			let name = matches[1].to_string();
			Some(TokPassageLink(text, name))
		}

		FORMAT_ITALIC => |_:&mut TweeLexer<R>| Some(TokFormatItalic)
		FORMAT_BOLD => |_:&mut TweeLexer<R>| Some(TokFormatBold)
		FORMAT_UNDER => |_:&mut TweeLexer<R>| Some(TokFormatUnder)
		FORMAT_STRIKE => |_:&mut TweeLexer<R>| Some(TokFormatStrike)
		FORMAT_SUB => |_:&mut TweeLexer<R>| Some(TokFormatSub)
		FORMAT_SUP => |_:&mut TweeLexer<R>| Some(TokFormatSup)
		FORMAT_MONO_START => |_:&mut TweeLexer<R>| Some(TokFormatMonoStart)
		FORMAT_MONO_END => |_:&mut TweeLexer<R>| Some(TokFormatMonoEnd)

		TEXTLINES => |lexer:&mut TweeLexer<R>| Some(TokText(lexer.yystr()))
	}

	PASSAGE {
		// TODO trim()
		PASSAGE_NAME => |lexer:&mut TweeLexer<R>| Some(TokPassageName(lexer.yystr()))
		TAG_START => |lexer:&mut TweeLexer<R>| {
			lexer.TAGS();
			Some(TokTagStart)
		}
		NEWLINE => |lexer:&mut TweeLexer<R>| -> Option<Token>{
			lexer.INITIAL();
			None
		}
	}

	TAGS {
		WORD => |lexer:&mut TweeLexer<R>| Some(TokTag(lexer.yystr()))
		TAG_END => |lexer:&mut TweeLexer<R>| {
			lexer.PASSAGE();
			Some(TokTagEnd)
		}
	}

	MAKRO {
		MAKRO_END => |lexer:&mut TweeLexer<R>| {
			lexer.INITIAL();
			Some(TokMakroEnd)
		}
		VAR_NAME =>  |lexer:&mut TweeLexer<R>| Some(TokVariable(lexer.yystr()))
		FLOAT =>  |lexer:&mut TweeLexer<R>| Some(TokFloat(lexer.yystr()[..].parse().unwrap()))
		INT =>  |lexer:&mut TweeLexer<R>| Some(TokInt(lexer.yystr()[..].parse().unwrap()))
		STRING =>  |lexer:&mut TweeLexer<R>| Some(TokString(lexer.yystr()))
		SET =>  |_:&mut TweeLexer<R>| Some(TokSet)
		ASSIGN =>  |_:&mut TweeLexer<R>| Some(TokAssign)
		IF =>  |_:&mut TweeLexer<R>| Some(TokIf)
		ELSE =>  |_:&mut TweeLexer<R>| Some(TokElse)
		END_IF =>  |_:&mut TweeLexer<R>| Some(TokEndIf)
		NUM_OP =>  |lexer:&mut TweeLexer<R>| Some(TokNumOp(lexer.yystr()))
		COMP_OP =>  |lexer:&mut TweeLexer<R>| Some(TokCompOp(lexer.yystr()))
		LOG_OP =>  |lexer:&mut TweeLexer<R>| Some(TokLogOp(lexer.yystr()))
		BR_OPEN =>  |_:&mut TweeLexer<R>| Some(TokBracketOpen)
		BR_CLOSE =>  |_:&mut TweeLexer<R>| Some(TokBracketClose)
	}

}

#[test]
fn it_works() {

}
<|endoftext|>