<commit_before>use alloc::arc::Arc;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::ops::DerefMut;
use core::{mem, ptr};

use common::elf::Elf;
use common::memory;

use scheduler::context::{CONTEXT_STACK_SIZE, CONTEXT_STACK_ADDR, context_switch,
context_userspace, Context, ContextMemory};

use schemes::Url;

use sync::Intex;

/// Execute an executable
pub fn execute(url: Url, mut args: Vec<String>) {
    let context_ptr: *mut Context = {
        let mut contexts = ::env().contexts.lock();
        if let Some(mut current) = contexts.current_mut() {
            current.deref_mut()
        } else {
            return
        }
    };

    Context::spawn("kexec ".to_string() + &url.string, box move || {
        if let Ok(mut resource) = url.open() {
            let mut vec: Vec<u8> = Vec::new();
            resource.read_to_end(&mut vec);

            let executable = Elf::from_data(vec.as_ptr() as usize);
            let entry = unsafe { executable.entry() };
            let mut memory = Vec::new();
            unsafe {
                for segment in executable.load_segment().iter() {
                    let virtual_address = segment.vaddr as usize;
                    let virtual_size = segment.mem_len as usize;
                    let physical_address = memory::alloc(virtual_size);

                    if physical_address > 0 {
                        // Copy progbits
                        ::memcpy(physical_address as *mut u8,
                                 (executable.data + segment.off as usize) as *const u8,
                                 segment.file_len as usize);
                        // Zero bss
                        ::memset((physical_address + segment.file_len as usize) as *mut u8,
                        0,
                        segment.mem_len as usize - segment.file_len as usize);

                        memory.push(ContextMemory {
                            physical_address: physical_address,
                            virtual_address: virtual_address,
                            virtual_size: virtual_size,
                            writeable: segment.flags & 2 == 2
                        });
                    }
                }
            }

            if entry > 0 && ! memory.is_empty() {
                args.insert(0, url.to_string());

                let mut context_args: Vec<usize> = Vec::new();
                context_args.push(0); // ENVP
                context_args.push(0); // ARGV NULL
                let mut argc = 0;
                for i in 0..args.len() {
                    let reverse_i = args.len() - i - 1;
                    if let Some(ref mut arg) = args.get_mut(reverse_i) {
                        if ! arg.ends_with('\0') {
                            arg.push('\0');
                        }
                        context_args.push(arg.as_ptr() as usize);
                        argc += 1;
                    }
                }
                context_args.push(argc);

                unsafe {
                    let _intex = Intex::static_lock();

                    let context = &mut *context_ptr;

                    context.name = url.string;

                    context.sp = context.kernel_stack + CONTEXT_STACK_SIZE - 128;

                    context.stack = Some(ContextMemory {
                        physical_address: memory::alloc(CONTEXT_STACK_SIZE),
                        virtual_address: CONTEXT_STACK_ADDR,
                        virtual_size: CONTEXT_STACK_SIZE,
                        writeable: true
                    });

                    context.args = Arc::new(UnsafeCell::new(args));
                    context.cwd = Arc::new(UnsafeCell::new((*context.cwd.get()).clone()));
                    context.memory = Arc::new(UnsafeCell::new(memory));

                    let user_sp = if let Some(ref stack) = context.stack {
                        let mut sp = stack.physical_address + stack.virtual_size - 128;
                        for arg in context_args.iter() {
                            sp -= mem::size_of::<usize>();
                            ptr::write(sp as *mut usize, *arg);
                        }
                        sp - stack.physical_address + stack.virtual_address
                    } else {
                        0
                    };

                    context.push(0x20 | 3);
                    context.push(user_sp);
                    context.push(/*1 << 9*/ 0);
                    context.push(0x18 | 3);
                    context.push(entry);
                    context.push(context_userspace as usize);
                }
            } else {
                debug!("{}: Invalid memory or entry\n", url.string);
            }
        } else {
            debug!("{}: Failed to open\n", url.string);
        }
    });

    loop {
        unsafe { context_switch(false) };
    }
}
<commit_msg>Cleanup in executor<commit_after>use alloc::arc::Arc;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::ops::DerefMut;
use core::{mem, ptr};

use common::elf::Elf;
use common::memory;

use scheduler::context::{CONTEXT_STACK_SIZE, CONTEXT_STACK_ADDR, context_switch,
context_userspace, Context, ContextMemory};

use schemes::Url;

use sync::Intex;

/// Execute an executable
pub fn execute(url: Url, mut args: Vec<String>) {
    let mut context_ptr: *mut Context = 0 as *mut Context;
    let mut entry: usize = 0;

    if let Ok(mut resource) = url.open() {
        let mut vec: Vec<u8> = Vec::new();
        resource.read_to_end(&mut vec);

        let executable = Elf::from_data(vec.as_ptr() as usize);
        entry = unsafe { executable.entry() };
        let mut memory = Vec::new();
        unsafe {
            for segment in executable.load_segment().iter() {
                let virtual_address = segment.vaddr as usize;
                let virtual_size = segment.mem_len as usize;
                let physical_address = memory::alloc(virtual_size);

                if physical_address > 0 {
                    // Copy progbits
                    ::memcpy(physical_address as *mut u8,
                             (executable.data + segment.off as usize) as *const u8,
                             segment.file_len as usize);
                    // Zero bss
                    ::memset((physical_address + segment.file_len as usize) as *mut u8,
                    0,
                    segment.mem_len as usize - segment.file_len as usize);

                    memory.push(ContextMemory {
                        physical_address: physical_address,
                        virtual_address: virtual_address,
                        virtual_size: virtual_size,
                        writeable: segment.flags & 2 == 2
                    });
                }
            }
        }

        if entry > 0 && ! memory.is_empty() {
            args.insert(0, url.to_string());

            let mut contexts = ::env().contexts.lock();
            if let Some(mut context) = contexts.current_mut() {
                unsafe { context.unmap() };

                context.name = url.string;
                context.args = Arc::new(UnsafeCell::new(args));
                context.cwd = Arc::new(UnsafeCell::new(unsafe { (*context.cwd.get()).clone() }));
                context.memory = Arc::new(UnsafeCell::new(memory));

                unsafe { context.map() };

                context_ptr = context.deref_mut();
            }
        } else {
            debug!("{}: Invalid memory or entry\n", url.string);
        }
    } else {
        debug!("{}: Failed to open\n", url.string);
    }

    if context_ptr as usize > 0 {
        Context::spawn("kexec".to_string(), box move || {
            unsafe {
                let _intex = Intex::static_lock();

                let context = &mut *context_ptr;

                let mut context_args: Vec<usize> = Vec::new();
                context_args.push(0); // ENVP
                context_args.push(0); // ARGV NULL
                let mut argc = 0;
                for i in 0..(*context.args.get()).len() {
                    let reverse_i = (*context.args.get()).len() - i - 1;
                    if let Some(ref mut arg) = (*context.args.get()).get_mut(reverse_i) {
                        if ! arg.ends_with('\0') {
                            arg.push('\0');
                        }
                        context_args.push(arg.as_ptr() as usize);
                        argc += 1;
                    }
                }
                context_args.push(argc);

                context.sp = context.kernel_stack + CONTEXT_STACK_SIZE - 128;

                context.stack = Some(ContextMemory {
                    physical_address: memory::alloc(CONTEXT_STACK_SIZE),
                    virtual_address: CONTEXT_STACK_ADDR,
                    virtual_size: CONTEXT_STACK_SIZE,
                    writeable: true
                });

                let user_sp = if let Some(ref stack) = context.stack {
                    let mut sp = stack.physical_address + stack.virtual_size - 128;
                    for arg in context_args.iter() {
                        sp -= mem::size_of::<usize>();
                        ptr::write(sp as *mut usize, *arg);
                    }
                    sp - stack.physical_address + stack.virtual_address
                } else {
                    0
                };

                context.push(0x20 | 3);
                context.push(user_sp);
                context.push(/*1 << 9*/ 0);
                context.push(0x18 | 3);
                context.push(entry);
                context.push(context_userspace as usize);
            }
        });

        loop {
            unsafe { context_switch(false) };
        }
    }
}
<|endoftext|>


<commit_before>//! Code for generating action code.
//!
//! From the outside, action fns have one of two forms. If they take
//! symbols as input, e.g. from a production like `X = Y Z => ...`
//! (which takes Y and Z as input), they have this form:
//!
//! ```
//! fn __action17<
//!     'input,                       // user-declared type parameters (*)
//! >(
//!     input: &'input str,           // user-declared parameters
//!     __0: (usize, usize, usize),   // symbols being reduced, if any
//!     ...
//!     __N: (usize, Foo, usize),     // each has a type (L, T, L)
//! ) -> Box<Expr<'input>>
//! ```
//!
//! Otherwise, they have this form:
//!
//! ```
//! fn __action17<
//!     'input,                       // user-declared type parameters (*)
//! >(
//!     input: &'input str,           // user-declared parameters
//!    __lookbehind: &usize,          // value for @R -- "end of previous token"
//!    __lookahead: &usize,           // value for @L -- "start of next token"
//! ) -> Box<Expr<'input>>
//! ```
//!
//! * -- in this case, those "user-declared" parameters are inserted by
//! the "internal tokenizer".

use grammar::repr as r;
use rust::RustWrite;
use std::io::{self, Write};

pub fn emit_action_code<W: Write>(grammar: &r::Grammar, rust: &mut RustWrite<W>) -> io::Result<()> {
    for (i, defn) in grammar.action_fn_defns.iter().enumerate() {
        rust!(rust, "");

        // we always thread the parameters through to the action code,
        // even if they are not used, and hence we need to disable the
        // unused variables lint, which otherwise gets very excited.
        if !grammar.parameters.is_empty() {
            rust!(rust, "#[allow(unused_variables)]");
        }

        match defn.kind {
            r::ActionFnDefnKind::User(ref data) => {
                try!(emit_user_action_code(grammar, rust, i, defn, data))
            }
            r::ActionFnDefnKind::Lookaround(ref variant) => {
                try!(emit_lookaround_action_code(grammar, rust, i, defn, variant))
            }
            r::ActionFnDefnKind::Inline(ref data) => {
                try!(emit_inline_action_code(grammar, rust, i, defn, data))
            }
        }
    }

    Ok(())
}

fn ret_type_string(grammar: &r::Grammar, defn: &r::ActionFnDefn) -> String {
    if defn.fallible {
        format!(
            "Result<{},{}lalrpop_util::ParseError<{},{},{}>>",
            defn.ret_type,
            grammar.prefix,
            grammar.types.terminal_loc_type(),
            grammar.types.terminal_token_type(),
            grammar.types.error_type()
        )
    } else {
        format!("{}", defn.ret_type)
    }
}

fn emit_user_action_code<W: Write>(
    grammar: &r::Grammar,
    rust: &mut RustWrite<W>,
    index: usize,
    defn: &r::ActionFnDefn,
    data: &r::UserActionFnDefn,
) -> io::Result<()> {
    let ret_type = ret_type_string(grammar, defn);

    // For each symbol to be reduced, we will receive
    // a (L, T, L) triple where the Ls are locations and
    // the T is the data. Ignore the locations and bind
    // the data to the name the user gave.
    let mut arguments: Vec<String> = data
        .arg_patterns
        .iter()
        .zip(
            data.arg_types
                .iter()
                .cloned()
                .map(|t| grammar.types.spanned_type(t)),
        )
        .map(|(p, t)| format!("(_, {}, _): {}", p, t))
        .collect();

    // If this is a reduce of an empty production, we will
    // automatically add position information in the form of
    // lookbehind/lookahead values. Otherwise, those values would be
    // determined from the arguments themselves.
    if data.arg_patterns.is_empty() {
        arguments.extend(vec![
            format!(
                "{}lookbehind: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
            format!(
                "{}lookahead: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
        ]);
    }

    try!(rust.write_fn_header(
        grammar,
        &r::Visibility::Priv,
        format!("{}action{}", grammar.prefix, index),
        vec![],
        None,
        arguments,
        ret_type,
        vec![]
    ));
    rust!(rust, "{{");
    rust!(rust, "{}", data.code);
    rust!(rust, "}}");
    Ok(())
}

fn emit_lookaround_action_code<W: Write>(
    grammar: &r::Grammar,
    rust: &mut RustWrite<W>,
    index: usize,
    _defn: &r::ActionFnDefn,
    data: &r::LookaroundActionFnDefn,
) -> io::Result<()> {
    try!(rust.write_fn_header(
        grammar,
        &r::Visibility::Priv,
        format!("{}action{}", grammar.prefix, index),
        vec![],
        None,
        vec![
            format!(
                "{}lookbehind: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
            format!(
                "{}lookahead: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
        ],
        format!("{}", grammar.types.terminal_loc_type()),
        vec![]
    ));

    rust!(rust, "{{");
    match *data {
        r::LookaroundActionFnDefn::Lookahead => {
            // take the lookahead, if any; otherwise, we are
            // at EOF, so taker the lookbehind (end of last
            // pushed token); if that is missing too, then
            // supply default.
            rust!(rust, "{}lookahead.clone()", grammar.prefix);
        }
        r::LookaroundActionFnDefn::Lookbehind => {
            // take lookbehind or supply default
            rust!(rust, "{}lookbehind.clone()", grammar.prefix);
        }
    }
    rust!(rust, "}}");
    Ok(())
}

fn emit_inline_action_code<W: Write>(
    grammar: &r::Grammar,
    rust: &mut RustWrite<W>,
    index: usize,
    defn: &r::ActionFnDefn,
    data: &r::InlineActionFnDefn,
) -> io::Result<()> {
    let ret_type = ret_type_string(grammar, defn);

    let arg_types: Vec<_> = data
        .symbols
        .iter()
        .flat_map(|sym| match *sym {
            r::InlinedSymbol::Original(ref s) => vec![s.clone()],
            r::InlinedSymbol::Inlined(_, ref syms) => syms.clone(),
        })
        .map(|s| s.ty(&grammar.types))
        .collect();

    // this is the number of symbols we expect to be passed in; it is
    // distinct from data.symbols.len(), because sometimes we have
    // inlined actions with no input symbols
    let num_flat_args = arg_types.len();

    let mut arguments: Vec<_> = arg_types
        .iter()
        .map(|&t| grammar.types.spanned_type(t.clone()))
        .enumerate()
        .map(|(i, t)| format!("{}{}: {}", grammar.prefix, i, t))
        .collect();

    // If no symbols are being reduced, add in the
    // lookbehind/lookahead.
    if arguments.len() == 0 {
        arguments.extend(vec![
            format!(
                "{}lookbehind: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
            format!(
                "{}lookahead: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
        ]);
    }

    try!(rust.write_fn_header(
        grammar,
        &r::Visibility::Priv,
        format!("{}action{}", grammar.prefix, index),
        vec![],
        None,
        arguments,
        ret_type,
        vec![]
    ));
    rust!(rust, "{{");

    // For each inlined thing, compute the start/end locations.
    // Do this first so that none of the arguments have been moved
    // yet and we can easily access their locations.
    let mut arg_counter = 0;
    let mut temp_counter = 0;
    for symbol in &data.symbols {
        match *symbol {
            r::InlinedSymbol::Original(_) => {
                arg_counter += 1;
            }
            r::InlinedSymbol::Inlined(_, ref syms) => {
                if syms.len() > 0 {
                    // If we are reducing symbols, then start and end
                    // can be the start/end location of the first/last
                    // symbol respectively. Easy peezy.

                    rust!(
                        rust,
                        "let {}start{} = {}{}.0.clone();",
                        grammar.prefix,
                        temp_counter,
                        grammar.prefix,
                        arg_counter
                    );

                    let last_arg_index = arg_counter + syms.len() - 1;
                    rust!(
                        rust,
                        "let {}end{} = {}{}.2.clone();",
                        grammar.prefix,
                        temp_counter,
                        grammar.prefix,
                        last_arg_index
                    );
                } else {
                    // If we have no symbols, then `arg_counter`
                    // represents index of the first symbol after this
                    // inlined item (if any), and `arg_counter-1`
                    // represents index of the symbol before this
                    // item.

                    if arg_counter > 0 {
                        rust!(
                            rust,
                            "let {}start{} = {}{}.2.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix,
                            arg_counter - 1
                        );
                    } else if num_flat_args > 0 {
                        rust!(
                            rust,
                            "let {}start{} = {}{}.0.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix,
                            arg_counter
                        );
                    } else {
                        rust!(
                            rust,
                            "let {}start{} = {}lookbehind.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix
                        );
                    }

                    if arg_counter < num_flat_args {
                        rust!(
                            rust,
                            "let {}end{} = {}{}.0.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix,
                            arg_counter
                        );
                    } else if num_flat_args > 0 {
                        rust!(
                            rust,
                            "let {}end{} = {}{}.2.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix,
                            num_flat_args - 1
                        );
                    } else {
                        rust!(
                            rust,
                            "let {}end{} = {}lookahead.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix
                        );
                    }
                }

                temp_counter += 1;
                arg_counter += syms.len();
            }
        }
    }

    // Now create temporaries for the inlined things
    let mut arg_counter = 0;
    let mut temp_counter = 0;

    // if there are type parameters then type annotation is required
    let annotate = !grammar.non_lifetime_type_parameters().is_empty();

    for symbol in &data.symbols {
        match *symbol {
            r::InlinedSymbol::Original(_) => {
                arg_counter += 1;
            }
            r::InlinedSymbol::Inlined(inlined_action, ref syms) => {
                // execute the inlined reduce action
                rust!(
                    rust,
                    "let {}temp{} = {}action{}",
                    grammar.prefix,
                    temp_counter,
                    grammar.prefix,
                    inlined_action.index(),
                );
                if annotate {
                    rust!(rust, "::<");
                    for t in grammar.non_lifetime_type_parameters() {
                        rust!(rust, "{},", t);
                    }
                    rust!(rust, ">");
                }
                rust!(rust, "(");
                for parameter in &grammar.parameters {
                    rust!(rust, "{},", parameter.name);
                }
                for i in 0..syms.len() {
                    rust!(rust, "{}{},", grammar.prefix, arg_counter + i);
                }
                if syms.len() == 0 {
                    rust!(rust, "&{}start{},", grammar.prefix, temp_counter);
                    rust!(rust, "&{}end{},", grammar.prefix, temp_counter);
                }
                rust!(rust, ");");

                // wrap up the inlined value along with its span
                rust!(
                    rust,
                    "let {}temp{} = ({}start{}, {}temp{}, {}end{});",
                    grammar.prefix,
                    temp_counter,
                    grammar.prefix,
                    temp_counter,
                    grammar.prefix,
                    temp_counter,
                    grammar.prefix,
                    temp_counter
                );

                temp_counter += 1;
                arg_counter += syms.len();
            }
        }
    }
    rust!(rust, "{}action{}", grammar.prefix, data.action.index());
    if annotate {
        rust!(rust, "::<");
        for t in grammar.non_lifetime_type_parameters() {
            rust!(rust, "{},", t);
        }
        rust!(rust, ">");
    }
    rust!(rust, "(");
    for parameter in &grammar.parameters {
        rust!(rust, "{},", parameter.name);
    }
    let mut arg_counter = 0;
    let mut temp_counter = 0;
    for symbol in &data.symbols {
        match *symbol {
            r::InlinedSymbol::Original(_) => {
                rust!(rust, "{}{},", grammar.prefix, arg_counter);
                arg_counter += 1;
            }
            r::InlinedSymbol::Inlined(_, ref syms) => {
                rust!(rust, "{}temp{},", grammar.prefix, temp_counter);
                temp_counter += 1;
                arg_counter += syms.len();
            }
        }
    }
    assert!(data.symbols.len() > 0);
    rust!(rust, ")");

    rust!(rust, "}}");
    Ok(())
}
<commit_msg>Reset action code to previous commit<commit_after>//! Code for generating action code.
//!
//! From the outside, action fns have one of two forms. If they take
//! symbols as input, e.g. from a production like `X = Y Z => ...`
//! (which takes Y and Z as input), they have this form:
//!
//! ```
//! fn __action17<
//!     'input,                       // user-declared type parameters (*)
//! >(
//!     input: &'input str,           // user-declared parameters
//!     __0: (usize, usize, usize),   // symbols being reduced, if any
//!     ...
//!     __N: (usize, Foo, usize),     // each has a type (L, T, L)
//! ) -> Box<Expr<'input>>
//! ```
//!
//! Otherwise, they have this form:
//!
//! ```
//! fn __action17<
//!     'input,                       // user-declared type parameters (*)
//! >(
//!     input: &'input str,           // user-declared parameters
//!    __lookbehind: &usize,          // value for @R -- "end of previous token"
//!    __lookahead: &usize,           // value for @L -- "start of next token"
//! ) -> Box<Expr<'input>>
//! ```
//!
//! * -- in this case, those "user-declared" parameters are inserted by
//! the "internal tokenizer".

use grammar::repr as r;
use rust::RustWrite;
use std::io::{self, Write};

pub fn emit_action_code<W: Write>(grammar: &r::Grammar, rust: &mut RustWrite<W>) -> io::Result<()> {
    for (i, defn) in grammar.action_fn_defns.iter().enumerate() {
        rust!(rust, "");

        // we always thread the parameters through to the action code,
        // even if they are not used, and hence we need to disable the
        // unused variables lint, which otherwise gets very excited.
        if !grammar.parameters.is_empty() {
            rust!(rust, "#[allow(unused_variables)]");
        }

        match defn.kind {
            r::ActionFnDefnKind::User(ref data) => {
                try!(emit_user_action_code(grammar, rust, i, defn, data))
            }
            r::ActionFnDefnKind::Lookaround(ref variant) => {
                try!(emit_lookaround_action_code(grammar, rust, i, defn, variant))
            }
            r::ActionFnDefnKind::Inline(ref data) => {
                try!(emit_inline_action_code(grammar, rust, i, defn, data))
            }
        }
    }

    Ok(())
}

fn ret_type_string(grammar: &r::Grammar, defn: &r::ActionFnDefn) -> String {
    if defn.fallible {
        format!(
            "Result<{},{}lalrpop_util::ParseError<{},{},{}>>",
            defn.ret_type,
            grammar.prefix,
            grammar.types.terminal_loc_type(),
            grammar.types.terminal_token_type(),
            grammar.types.error_type()
        )
    } else {
        format!("{}", defn.ret_type)
    }
}

fn emit_user_action_code<W: Write>(
    grammar: &r::Grammar,
    rust: &mut RustWrite<W>,
    index: usize,
    defn: &r::ActionFnDefn,
    data: &r::UserActionFnDefn,
) -> io::Result<()> {
    let ret_type = ret_type_string(grammar, defn);

    // For each symbol to be reduced, we will receive
    // a (L, T, L) triple where the Ls are locations and
    // the T is the data. Ignore the locations and bind
    // the data to the name the user gave.
    let mut arguments: Vec<String> = data
        .arg_patterns
        .iter()
        .zip(
            data.arg_types
                .iter()
                .cloned()
                .map(|t| grammar.types.spanned_type(t)),
        )
        .map(|(p, t)| format!("(_, {}, _): {}", p, t))
        .collect();

    // If this is a reduce of an empty production, we will
    // automatically add position information in the form of
    // lookbehind/lookahead values. Otherwise, those values would be
    // determined from the arguments themselves.
    if data.arg_patterns.is_empty() {
        arguments.extend(vec![
            format!(
                "{}lookbehind: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
            format!(
                "{}lookahead: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
        ]);
    }

    try!(rust.write_fn_header(
        grammar,
        &r::Visibility::Priv,
        format!("{}action{}", grammar.prefix, index),
        vec![],
        None,
        arguments,
        ret_type,
        vec![]
    ));
    rust!(rust, "{{");
    rust!(rust, "{}", data.code);
    rust!(rust, "}}");
    Ok(())
}

fn emit_lookaround_action_code<W: Write>(
    grammar: &r::Grammar,
    rust: &mut RustWrite<W>,
    index: usize,
    _defn: &r::ActionFnDefn,
    data: &r::LookaroundActionFnDefn,
) -> io::Result<()> {
    try!(rust.write_fn_header(
        grammar,
        &r::Visibility::Priv,
        format!("{}action{}", grammar.prefix, index),
        vec![],
        None,
        vec![
            format!(
                "{}lookbehind: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
            format!(
                "{}lookahead: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
        ],
        format!("{}", grammar.types.terminal_loc_type()),
        vec![]
    ));

    rust!(rust, "{{");
    match *data {
        r::LookaroundActionFnDefn::Lookahead => {
            // take the lookahead, if any; otherwise, we are
            // at EOF, so taker the lookbehind (end of last
            // pushed token); if that is missing too, then
            // supply default.
            rust!(rust, "{}lookahead.clone()", grammar.prefix);
        }
        r::LookaroundActionFnDefn::Lookbehind => {
            // take lookbehind or supply default
            rust!(rust, "{}lookbehind.clone()", grammar.prefix);
        }
    }
    rust!(rust, "}}");
    Ok(())
}

fn emit_inline_action_code<W: Write>(
    grammar: &r::Grammar,
    rust: &mut RustWrite<W>,
    index: usize,
    defn: &r::ActionFnDefn,
    data: &r::InlineActionFnDefn,
) -> io::Result<()> {
    let ret_type = ret_type_string(grammar, defn);

    let arg_types: Vec<_> = data
        .symbols
        .iter()
        .flat_map(|sym| match *sym {
            r::InlinedSymbol::Original(ref s) => vec![s.clone()],
            r::InlinedSymbol::Inlined(_, ref syms) => syms.clone(),
        })
        .map(|s| s.ty(&grammar.types))
        .collect();

    // this is the number of symbols we expect to be passed in; it is
    // distinct from data.symbols.len(), because sometimes we have
    // inlined actions with no input symbols
    let num_flat_args = arg_types.len();

    let mut arguments: Vec<_> = arg_types
        .iter()
        .map(|&t| grammar.types.spanned_type(t.clone()))
        .enumerate()
        .map(|(i, t)| format!("{}{}: {}", grammar.prefix, i, t))
        .collect();

    // If no symbols are being reduced, add in the
    // lookbehind/lookahead.
    if arguments.len() == 0 {
        arguments.extend(vec![
            format!(
                "{}lookbehind: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
            format!(
                "{}lookahead: &{}",
                grammar.prefix,
                grammar.types.terminal_loc_type()
            ),
        ]);
    }

    try!(rust.write_fn_header(
        grammar,
        &r::Visibility::Priv,
        format!("{}action{}", grammar.prefix, index),
        vec![],
        None,
        arguments,
        ret_type,
        vec![]
    ));
    rust!(rust, "{{");

    // For each inlined thing, compute the start/end locations.
    // Do this first so that none of the arguments have been moved
    // yet and we can easily access their locations.
    let mut arg_counter = 0;
    let mut temp_counter = 0;
    for symbol in &data.symbols {
        match *symbol {
            r::InlinedSymbol::Original(_) => {
                arg_counter += 1;
            }
            r::InlinedSymbol::Inlined(_, ref syms) => {
                if syms.len() > 0 {
                    // If we are reducing symbols, then start and end
                    // can be the start/end location of the first/last
                    // symbol respectively. Easy peezy.

                    rust!(
                        rust,
                        "let {}start{} = {}{}.0.clone();",
                        grammar.prefix,
                        temp_counter,
                        grammar.prefix,
                        arg_counter
                    );

                    let last_arg_index = arg_counter + syms.len() - 1;
                    rust!(
                        rust,
                        "let {}end{} = {}{}.2.clone();",
                        grammar.prefix,
                        temp_counter,
                        grammar.prefix,
                        last_arg_index
                    );
                } else {
                    // If we have no symbols, then `arg_counter`
                    // represents index of the first symbol after this
                    // inlined item (if any), and `arg_counter-1`
                    // represents index of the symbol before this
                    // item.

                    if arg_counter > 0 {
                        rust!(
                            rust,
                            "let {}start{} = {}{}.2.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix,
                            arg_counter - 1
                        );
                    } else if num_flat_args > 0 {
                        rust!(
                            rust,
                            "let {}start{} = {}{}.0.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix,
                            arg_counter
                        );
                    } else {
                        rust!(
                            rust,
                            "let {}start{} = {}lookbehind.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix
                        );
                    }

                    if arg_counter < num_flat_args {
                        rust!(
                            rust,
                            "let {}end{} = {}{}.0.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix,
                            arg_counter
                        );
                    } else if num_flat_args > 0 {
                        rust!(
                            rust,
                            "let {}end{} = {}{}.2.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix,
                            num_flat_args - 1
                        );
                    } else {
                        rust!(
                            rust,
                            "let {}end{} = {}lookahead.clone();",
                            grammar.prefix,
                            temp_counter,
                            grammar.prefix
                        );
                    }
                }

                temp_counter += 1;
                arg_counter += syms.len();
            }
        }
    }

    // Now create temporaries for the inlined things
    let mut arg_counter = 0;
    let mut temp_counter = 0;

    // if there are type parameters then type annotation is required
    let annotate = !grammar.non_lifetime_type_parameters().is_empty();
    let lparen = if annotate {"::<"} else {"("};

    for symbol in &data.symbols {
        match *symbol {
            r::InlinedSymbol::Original(_) => {
                arg_counter += 1;
            }
            r::InlinedSymbol::Inlined(inlined_action, ref syms) => {
                // execute the inlined reduce action
                rust!(
                    rust,
                    "let {}temp{} = {}action{}{}",
                    grammar.prefix,
                    temp_counter,
                    grammar.prefix,
                    inlined_action.index(),
                    lparen
                );
                for t in grammar.non_lifetime_type_parameters() {
                    rust!(rust, "{},", t);
                }
                if annotate {rust!(rust, ">(")};
                for parameter in &grammar.parameters {
                    rust!(rust, "{},", parameter.name);
                }
                for i in 0..syms.len() {
                    rust!(rust, "{}{},", grammar.prefix, arg_counter + i);
                }
                if syms.len() == 0 {
                    rust!(rust, "&{}start{},", grammar.prefix, temp_counter);
                    rust!(rust, "&{}end{},", grammar.prefix, temp_counter);
                }
                rust!(rust, ");");

                // wrap up the inlined value along with its span
                rust!(
                    rust,
                    "let {}temp{} = ({}start{}, {}temp{}, {}end{});",
                    grammar.prefix,
                    temp_counter,
                    grammar.prefix,
                    temp_counter,
                    grammar.prefix,
                    temp_counter,
                    grammar.prefix,
                    temp_counter
                );

                temp_counter += 1;
                arg_counter += syms.len();
            }
        }
    }
    rust!(rust, "{}action{}{}", grammar.prefix, data.action.index(), lparen);
    for t in grammar.non_lifetime_type_parameters() {
        rust!(rust, "{},", t);
    }
    if annotate {rust!(rust, ">(")};
    for parameter in &grammar.parameters {
        rust!(rust, "{},", parameter.name);
    }
    let mut arg_counter = 0;
    let mut temp_counter = 0;
    for symbol in &data.symbols {
        match *symbol {
            r::InlinedSymbol::Original(_) => {
                rust!(rust, "{}{},", grammar.prefix, arg_counter);
                arg_counter += 1;
            }
            r::InlinedSymbol::Inlined(_, ref syms) => {
                rust!(rust, "{}temp{},", grammar.prefix, temp_counter);
                temp_counter += 1;
                arg_counter += syms.len();
            }
        }
    }
    assert!(data.symbols.len() > 0);
    rust!(rust, ")");

    rust!(rust, "}}");
    Ok(())
}
<|endoftext|>


<commit_before>//! Code for generating action code.

use grammar::repr as r;
use rust::RustWrite;
use std::io::{self, Write};

pub fn emit_action_code<W:Write>(grammar: &r::Grammar,
                                 rust: &mut RustWrite<W>)
                                 -> io::Result<()>
{
    for (i, defn) in grammar.action_fn_defns.iter().enumerate() {
        rust!(rust, "");

        match defn.kind {
            r::ActionFnDefnKind::User(ref data) =>
                try!(emit_user_action_code(grammar, rust, i, defn, data)),
            r::ActionFnDefnKind::Lookaround(ref variant) =>
                try!(emit_lookaround_action_code(grammar, rust, i, defn, variant)),
            r::ActionFnDefnKind::Inline(ref data) =>
                try!(emit_inline_action_code(grammar, rust, i, defn, data)),
        }
    }

    Ok(())
}

fn ret_type_string(grammar: &r::Grammar,
                   defn: &r::ActionFnDefn)
                   -> String
{
    if defn.fallible {
        format!("Result<{},{}ParseError<{},{},{}>>",
                defn.ret_type,
                grammar.prefix,
                grammar.types.terminal_loc_type(),
                grammar.types.terminal_token_type(),
                grammar.types.error_type())
    } else {
        format!("{}", defn.ret_type)
    }
}

fn emit_user_action_code<W:Write>(grammar: &r::Grammar,
                                  rust: &mut RustWrite<W>,
                                  index: usize,
                                  defn: &r::ActionFnDefn,
                                  data: &r::UserActionFnDefn)
                                  -> io::Result<()>
{
    let ret_type = ret_type_string(grammar, defn);

    let lookarounds = vec![
        format!("{}lookbehind: &Option<{}>", grammar.prefix, grammar.types.terminal_loc_type()),
        format!("{}lookahead: &Option<{}>", grammar.prefix, grammar.types.triple_type())];

    try!(rust.write_pub_fn_header(
        grammar,
        format!("{}action{}", grammar.prefix, index),
        vec![],
        data.arg_patterns.iter()
                         .zip(data.arg_types.iter())
                         .map(|(p, t)| format!("{}: {}", p, t))
                         .chain(lookarounds)
                         .collect(),
        ret_type,
        vec![]));
    rust!(rust, "{{");
    rust!(rust, "{}", data.code);
    rust!(rust, "}}");
    Ok(())
}

fn emit_lookaround_action_code<W:Write>(grammar: &r::Grammar,
                                        rust: &mut RustWrite<W>,
                                        index: usize,
                                        _defn: &r::ActionFnDefn,
                                        data: &r::LookaroundActionFnDefn)
                                        -> io::Result<()>
{
    try!(rust.write_pub_fn_header(
        grammar,
        format!("{}action{}", grammar.prefix, index),
        vec![],
        vec![format!("{}lookbehind: &Option<{}>", grammar.prefix, grammar.types.terminal_loc_type()),
             format!("{}lookahead: &Option<{}>", grammar.prefix, grammar.types.triple_type())],
        format!("{}", grammar.types.terminal_loc_type()),
        vec![]));

    rust!(rust, "{{");
    match *data {
        r::LookaroundActionFnDefn::Lookahead => {
            // take the lookahead, if any; otherwise, we are
            // at EOF, so taker the lookbehind (end of last
            // pushed token); if that is missing too, then
            // supply default.
            rust!(rust, "{}lookahead.as_ref()\
                         .map(|o| ::std::clone::Clone::clone(&o.0))\
                         .or_else(|| ::std::clone::Clone::clone(&{}lookbehind))\
                         .unwrap_or_default()",
                  grammar.prefix, grammar.prefix);
        }
        r::LookaroundActionFnDefn::Lookbehind => {
            // take lookbehind or supply default
            rust!(rust, "::std::clone::Clone::clone(&{}lookbehind).unwrap_or_default()",
                  grammar.prefix);
        }
    }
    rust!(rust, "}}");
    Ok(())
}

fn emit_inline_action_code<W:Write>(grammar: &r::Grammar,
                                    rust: &mut RustWrite<W>,
                                    index: usize,
                                    defn: &r::ActionFnDefn,
                                    data: &r::InlineActionFnDefn)
                                    -> io::Result<()>
{
    let ret_type = ret_type_string(grammar, defn);

    let arg_types: Vec<_> =
        data.symbols.iter()
                    .flat_map(|sym| match *sym {
                        r::InlinedSymbol::Original(s) => vec![s],
                        r::InlinedSymbol::Inlined(_, ref syms) => syms.clone(),
                    })
                    .map(|s| s.ty(&grammar.types))
                    .collect();

    let arguments: Vec<_> =
        arg_types.iter()
                 .enumerate()
                 .map(|(i, t)| format!("{}{}: {}", grammar.prefix, i, t))
                 .chain(vec![
                     format!("{}lookbehind: &Option<{}>",
                             grammar.prefix,
                             grammar.types.terminal_loc_type()),
                     format!("{}lookahead: &Option<{}>",
                             grammar.prefix,
                             grammar.types.triple_type())])
                 .collect();

    try!(rust.write_pub_fn_header(
        grammar,
        format!("{}action{}", grammar.prefix, index),
        vec![],
        arguments,
        ret_type,
        vec![]));
    rust!(rust, "{{");

    // create temporaries for the inlined things
    let mut arg_counter = 0;
    let mut temp_counter = 0;
    for symbol in &data.symbols {
        match *symbol {
            r::InlinedSymbol::Original(_) => {
                arg_counter += 1;
            }
            r::InlinedSymbol::Inlined(inlined_action, ref syms) => {
                rust!(rust, "let {}temp{} = {}action{}(",
                      grammar.prefix, temp_counter,
                      grammar.prefix, inlined_action.index());
                for parameter in &grammar.parameters {
                    rust!(rust, "{},", parameter.name);
                }
                for _ in syms {
                    rust!(rust, "{}{},", grammar.prefix, arg_counter);
                    arg_counter += 1;
                }
                rust!(rust, "{}lookbehind,", grammar.prefix);
                rust!(rust, "{}lookahead,", grammar.prefix);
                rust!(rust, ");");
                temp_counter += 1;
            }
        }
    }

    rust!(rust, "{}action{}(", grammar.prefix, data.action.index());
    for parameter in &grammar.parameters {
        rust!(rust, "{},", parameter.name);
    }
    let mut arg_counter = 0;
    let mut temp_counter = 0;
    for symbol in &data.symbols {
        match *symbol {
            r::InlinedSymbol::Original(_) => {
                rust!(rust, "{}{},", grammar.prefix, arg_counter);
                arg_counter += 1;
            }
            r::InlinedSymbol::Inlined(_, ref syms) => {
                rust!(rust, "{}temp{},", grammar.prefix, temp_counter);
                temp_counter += 1;
                arg_counter += syms.len();
            }
        }
    }
    rust!(rust, "{}lookbehind,", grammar.prefix);
    rust!(rust, "{}lookahead,", grammar.prefix);
    rust!(rust, ")");

    rust!(rust, "}}");
    Ok(())
}

<commit_msg>apply rustfmt to action.rs<commit_after>//! Code for generating action code.

use grammar::repr as r;
use rust::RustWrite;
use std::io::{self, Write};

pub fn emit_action_code<W: Write>(grammar: &r::Grammar, rust: &mut RustWrite<W>) -> io::Result<()> {
    for (i, defn) in grammar.action_fn_defns.iter().enumerate() {
        rust!(rust, "");

        match defn.kind {
            r::ActionFnDefnKind::User(ref data) => {
                try!(emit_user_action_code(grammar, rust, i, defn, data))
            }
            r::ActionFnDefnKind::Lookaround(ref variant) => {
                try!(emit_lookaround_action_code(grammar, rust, i, defn, variant))
            }
            r::ActionFnDefnKind::Inline(ref data) => {
                try!(emit_inline_action_code(grammar, rust, i, defn, data))
            }
        }
    }

    Ok(())
}

fn ret_type_string(grammar: &r::Grammar, defn: &r::ActionFnDefn) -> String {
    if defn.fallible {
        format!("Result<{},{}ParseError<{},{},{}>>",
                defn.ret_type,
                grammar.prefix,
                grammar.types.terminal_loc_type(),
                grammar.types.terminal_token_type(),
                grammar.types.error_type())
    } else {
        format!("{}", defn.ret_type)
    }
}

fn emit_user_action_code<W: Write>(grammar: &r::Grammar,
                                   rust: &mut RustWrite<W>,
                                   index: usize,
                                   defn: &r::ActionFnDefn,
                                   data: &r::UserActionFnDefn)
                                   -> io::Result<()> {
    let ret_type = ret_type_string(grammar, defn);

    let lookarounds = vec![format!("{}lookbehind: &Option<{}>",
                                   grammar.prefix,
                                   grammar.types.terminal_loc_type()),
                           format!("{}lookahead: &Option<{}>",
                                   grammar.prefix,
                                   grammar.types.triple_type())];

    try!(rust.write_pub_fn_header(grammar,
                                  format!("{}action{}", grammar.prefix, index),
                                  vec![],
                                  data.arg_patterns
                                      .iter()
                                      .zip(data.arg_types.iter())
                                      .map(|(p, t)| format!("{}: {}", p, t))
                                      .chain(lookarounds)
                                      .collect(),
                                  ret_type,
                                  vec![]));
    rust!(rust, "{{");
    rust!(rust, "{}", data.code);
    rust!(rust, "}}");
    Ok(())
}

fn emit_lookaround_action_code<W: Write>(grammar: &r::Grammar,
                                         rust: &mut RustWrite<W>,
                                         index: usize,
                                         _defn: &r::ActionFnDefn,
                                         data: &r::LookaroundActionFnDefn)
                                         -> io::Result<()> {
    try!(rust.write_pub_fn_header(grammar,
                                  format!("{}action{}", grammar.prefix, index),
                                  vec![],
                                  vec![format!("{}lookbehind: &Option<{}>",
                                               grammar.prefix,
                                               grammar.types.terminal_loc_type()),
                                       format!("{}lookahead: &Option<{}>",
                                               grammar.prefix,
                                               grammar.types.triple_type())],
                                  format!("{}", grammar.types.terminal_loc_type()),
                                  vec![]));

    rust!(rust, "{{");
    match *data {
        r::LookaroundActionFnDefn::Lookahead => {
            // take the lookahead, if any; otherwise, we are
            // at EOF, so taker the lookbehind (end of last
            // pushed token); if that is missing too, then
            // supply default.
            rust!(rust,
                  "{}lookahead.as_ref().map(|o| ::std::clone::Clone::clone(&o.0)).or_else(|| \
                   ::std::clone::Clone::clone(&{}lookbehind)).unwrap_or_default()",
                  grammar.prefix,
                  grammar.prefix);
        }
        r::LookaroundActionFnDefn::Lookbehind => {
            // take lookbehind or supply default
            rust!(rust,
                  "::std::clone::Clone::clone(&{}lookbehind).unwrap_or_default()",
                  grammar.prefix);
        }
    }
    rust!(rust, "}}");
    Ok(())
}

fn emit_inline_action_code<W: Write>(grammar: &r::Grammar,
                                     rust: &mut RustWrite<W>,
                                     index: usize,
                                     defn: &r::ActionFnDefn,
                                     data: &r::InlineActionFnDefn)
                                     -> io::Result<()> {
    let ret_type = ret_type_string(grammar, defn);

    let arg_types: Vec<_> = data.symbols
                                .iter()
                                .flat_map(|sym| {
                                    match *sym {
                                        r::InlinedSymbol::Original(s) => vec![s],
                                        r::InlinedSymbol::Inlined(_, ref syms) => syms.clone(),
                                    }
                                })
                                .map(|s| s.ty(&grammar.types))
                                .collect();

    let arguments: Vec<_> = arg_types.iter()
                                     .enumerate()
                                     .map(|(i, t)| format!("{}{}: {}", grammar.prefix, i, t))
                                     .chain(vec![format!("{}lookbehind: &Option<{}>",
                                                         grammar.prefix,
                                                         grammar.types.terminal_loc_type()),
                                                 format!("{}lookahead: &Option<{}>",
                                                         grammar.prefix,
                                                         grammar.types.triple_type())])
                                     .collect();

    try!(rust.write_pub_fn_header(grammar,
                                  format!("{}action{}", grammar.prefix, index),
                                  vec![],
                                  arguments,
                                  ret_type,
                                  vec![]));
    rust!(rust, "{{");

    // create temporaries for the inlined things
    let mut arg_counter = 0;
    let mut temp_counter = 0;
    for symbol in &data.symbols {
        match *symbol {
            r::InlinedSymbol::Original(_) => {
                arg_counter += 1;
            }
            r::InlinedSymbol::Inlined(inlined_action, ref syms) => {
                rust!(rust,
                      "let {}temp{} = {}action{}(",
                      grammar.prefix,
                      temp_counter,
                      grammar.prefix,
                      inlined_action.index());
                for parameter in &grammar.parameters {
                    rust!(rust, "{},", parameter.name);
                }
                for _ in syms {
                    rust!(rust, "{}{},", grammar.prefix, arg_counter);
                    arg_counter += 1;
                }
                rust!(rust, "{}lookbehind,", grammar.prefix);
                rust!(rust, "{}lookahead,", grammar.prefix);
                rust!(rust, ");");
                temp_counter += 1;
            }
        }
    }

    rust!(rust, "{}action{}(", grammar.prefix, data.action.index());
    for parameter in &grammar.parameters {
        rust!(rust, "{},", parameter.name);
    }
    let mut arg_counter = 0;
    let mut temp_counter = 0;
    for symbol in &data.symbols {
        match *symbol {
            r::InlinedSymbol::Original(_) => {
                rust!(rust, "{}{},", grammar.prefix, arg_counter);
                arg_counter += 1;
            }
            r::InlinedSymbol::Inlined(_, ref syms) => {
                rust!(rust, "{}temp{},", grammar.prefix, temp_counter);
                temp_counter += 1;
                arg_counter += syms.len();
            }
        }
    }
    rust!(rust, "{}lookbehind,", grammar.prefix);
    rust!(rust, "{}lookahead,", grammar.prefix);
    rust!(rust, ")");

    rust!(rust, "}}");
    Ok(())
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use abra::schema::FieldRef;

use TermRef;

#[derive(Debug, Clone)]
pub enum BooleanQueryOp {
    PushEmpty,
    PushFull,
    PushTermDirectory(FieldRef, TermRef, u8),
    PushDeletionList,
    And,
    Or,
    AndNot,
}

#[derive(Clone, Copy, PartialEq)]
enum BooleanQueryBlockReturnType {
    Full,
    Empty,
    Sparse,
    NegatedSparse,
}

#[derive(Clone)]
enum BooleanQueryBlock {
    Leaf {
        op: BooleanQueryOp,
        return_type: BooleanQueryBlockReturnType,
    },
    Combinator {
        op: BooleanQueryOp,
        child_a: Rc<BooleanQueryBlock>,
        child_b: Rc<BooleanQueryBlock>,
        return_type: BooleanQueryBlockReturnType,
    }
}

impl BooleanQueryBlock {
    fn return_type(&self) -> BooleanQueryBlockReturnType {
        use self::BooleanQueryBlock::*;

        match *self {
            Leaf{ref op, return_type} => return_type,
            Combinator{ref op, ref child_a, ref child_b, return_type} => return_type,
        }
    }

    fn set_return_type(&mut self, new_type: BooleanQueryBlockReturnType) {
        use self::BooleanQueryBlock::*;

        match *self {
            Leaf{ref op, ref mut return_type} => *return_type = new_type,
            Combinator{ref op, ref child_a, ref child_b, ref mut return_type} => *return_type = new_type,
        }
    }

    fn build(&self, boolean_query: &mut Vec<BooleanQueryOp>) {
        use self::BooleanQueryBlock::*;

        match *self {
            Leaf{ref op, ref return_type} => {
                boolean_query.push(op.clone());
            }
            Combinator{ref op, ref child_a, ref child_b, ref return_type} => {
                child_a.build(boolean_query);
                child_b.build(boolean_query);
                boolean_query.push(op.clone());
            }
        }
    }
}

pub struct BooleanQueryBuilder {
    stack: Vec<Rc<BooleanQueryBlock>>,
}

impl BooleanQueryBuilder {
    pub fn new() -> BooleanQueryBuilder {
        BooleanQueryBuilder {
            stack: Vec::new(),
        }
    }

    pub fn push_zero(&mut self) {
        self.stack.push(Rc::new(BooleanQueryBlock::Leaf{
            op: BooleanQueryOp::PushEmpty,
            return_type: BooleanQueryBlockReturnType::Empty,
        }));
    }

    pub fn push_one(&mut self) {
        self.stack.push(Rc::new(BooleanQueryBlock::Leaf{
            op: BooleanQueryOp::PushFull,
            return_type: BooleanQueryBlockReturnType::Full,
        }));
    }

    pub fn push_op(&mut self, op: &BooleanQueryOp) {
        use search::boolean_retrieval::BooleanQueryOp::*;
        use self::BooleanQueryBlock::*;
        use self::BooleanQueryBlockReturnType::*;

        match *op {
            PushEmpty => {
                self.push_zero();
            }
            PushFull => {
                self.push_one();
            }
            PushTermDirectory(field_ref, term_ref, tag) => {
                self.stack.push(Rc::new(Leaf{
                    op: PushTermDirectory(field_ref, term_ref, tag),
                    return_type: Sparse,
                }));
            }
            PushDeletionList => {
                self.stack.push(Rc::new(Leaf{
                    op: PushDeletionList,
                    return_type: Sparse,
                }));
            }
            And => {
                let b = self.stack.pop().expect("stack underflow");
                let a = self.stack.pop().expect("stack underflow");

                match (a.return_type(), b.return_type()) {
                    // If either block is "full", replace this block with the other block
                    (Full, _) => self.stack.push(b),
                    (_, Full) => self.stack.push(a),

                    // If either block is "empty", this block will be empty too
                    (Empty, _) => self.push_zero(),
                    (_, Empty) => self.push_zero(),

                    (Sparse, Sparse) => {  // (a AND b)
                        // Intersection
                        self.stack.push(Rc::new(Combinator{
                            op: And,
                            child_a: a,
                            child_b: b,
                            return_type: Sparse,
                        }));
                    }

                    (Sparse, NegatedSparse) => {  // (a AND NOT b)
                        // Exclusion
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: a,
                            child_b: b,
                            return_type: Sparse,
                        }));
                    }

                    (NegatedSparse, Sparse) => {  // (NOT a AND b)
                        // Exclusion, with operands swapped
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: b,
                            child_b: a,
                            return_type: Sparse,
                        }));
                    }

                    (NegatedSparse, NegatedSparse) => {  // (NOT a AND NOT b)
                        // Negated union (NOT (a OR b))
                        self.stack.push(Rc::new(Combinator{
                            op: Or,
                            child_a: a,
                            child_b: b,
                            return_type: NegatedSparse,
                        }));
                    }
                }
            }
            Or => {
                let b = self.stack.pop().expect("stack underflow");
                let a = self.stack.pop().expect("stack underflow");

                match (a.return_type(), b.return_type()) {
                    // If either block is "full", this block will be full too
                    (Full, _) => self.push_one(),
                    (_, Full) => self.push_one(),

                    // If either block is "empty", replace this block with the other block
                    (Empty, _) => self.stack.push(b),
                    (_, Empty) => self.stack.push(a),

                    (Sparse, Sparse) => {  // (a OR b)
                        // Union
                        self.stack.push(Rc::new(Combinator{
                            op: Or,
                            child_a: a,
                            child_b: b,
                            return_type: Sparse,
                        }));
                    }

                    (Sparse, NegatedSparse) => {  // (a OR NOT b)
                        // Negated exclusion, with operands swapped (NOT (b AND NOT a))
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: b,
                            child_b: a,
                            return_type: NegatedSparse,
                        }));
                    }

                    (NegatedSparse, Sparse) => {  // (NOT a OR b)
                        // Negated exclusion (NOT (a AND NOT b))
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: a,
                            child_b: b,
                            return_type: NegatedSparse,
                        }));
                    }

                    (NegatedSparse, NegatedSparse) => {  // (NOT a OR NOT b)
                        // Negated intersection (NOT (a AND b))
                        self.stack.push(Rc::new(Combinator{
                            op: And,
                            child_a: a,
                            child_b: b,
                            return_type: NegatedSparse,
                        }));
                    }
                }
            }
            AndNot => {
                let b = self.stack.pop().expect("stack underflow");
                let a = self.stack.pop().expect("stack underflow");

                match (a.return_type(), b.return_type()) {
                    // If the right block is full, this block will be empty
                    (_, Full) => self.push_zero(),

                    // If the left block is empty, this block will be empty too
                    (Empty, _) => self.push_zero(),

                    // If the right block is empty, replace this block with the left block
                    (_, Empty) => self.stack.push(a),

                    (Full, Sparse) => {  // (ALL AND NOT b)
                        // Negation of b (NOT b)
                        let mut b_new = Rc::make_mut(&mut b.clone()).clone();
                        b_new.set_return_type(NegatedSparse);
                        self.stack.push(Rc::new(b_new));
                    }

                    (Full, NegatedSparse) => {  // (ALL AND NOT (NOT b))
                        // De-Negation of b (NOT (NOT b))
                        let mut b_new = Rc::make_mut(&mut b.clone()).clone();
                        b_new.set_return_type(Sparse);
                        self.stack.push(Rc::new(b_new));
                    }

                    (Sparse, Sparse) => {  // (a AND NOT b)
                        // Exclusion
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: a,
                            child_b: b,
                            return_type: Sparse,
                        }));
                    }

                    (Sparse, NegatedSparse) => {  // (a AND NOT (NOT b))
                        // Intersection (data AND other_data)
                        self.stack.push(Rc::new(Combinator{
                            op: And,
                            child_a: a,
                            child_b: b,
                            return_type: Sparse,
                        }));
                    }

                    (NegatedSparse, Sparse) => {  // (NOT a AND NOT b)
                        // Negated union (NOT (data OR other_data))
                        self.stack.push(Rc::new(Combinator{
                            op: Or,
                            child_a: a,
                            child_b: b,
                            return_type: NegatedSparse,
                        }));
                    }

                    (NegatedSparse, NegatedSparse) => {  // (NOT a AND NOT (NOT b))
                        // Exclusion, with operands swapped (b AND NOT a)
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: b,
                            child_b: a,
                            return_type: Sparse,
                        }));
                    }
                }
            }
        }
    }

    pub fn build(&self) -> (Vec<BooleanQueryOp>, bool) {
        use self::BooleanQueryBlockReturnType::*;

        let mut boolean_query = Vec::new();

        // If the query was valid, should be exactly one item on the stack
        let root_block = self.stack.last().unwrap();
        root_block.build(&mut boolean_query);

        (boolean_query, root_block.return_type() == NegatedSparse)
    }
}
<commit_msg>Corrected a couple of method names<commit_after>use std::rc::Rc;

use abra::schema::FieldRef;

use TermRef;

#[derive(Debug, Clone)]
pub enum BooleanQueryOp {
    PushEmpty,
    PushFull,
    PushTermDirectory(FieldRef, TermRef, u8),
    PushDeletionList,
    And,
    Or,
    AndNot,
}

#[derive(Clone, Copy, PartialEq)]
enum BooleanQueryBlockReturnType {
    Full,
    Empty,
    Sparse,
    NegatedSparse,
}

#[derive(Clone)]
enum BooleanQueryBlock {
    Leaf {
        op: BooleanQueryOp,
        return_type: BooleanQueryBlockReturnType,
    },
    Combinator {
        op: BooleanQueryOp,
        child_a: Rc<BooleanQueryBlock>,
        child_b: Rc<BooleanQueryBlock>,
        return_type: BooleanQueryBlockReturnType,
    }
}

impl BooleanQueryBlock {
    fn return_type(&self) -> BooleanQueryBlockReturnType {
        use self::BooleanQueryBlock::*;

        match *self {
            Leaf{ref op, return_type} => return_type,
            Combinator{ref op, ref child_a, ref child_b, return_type} => return_type,
        }
    }

    fn set_return_type(&mut self, new_type: BooleanQueryBlockReturnType) {
        use self::BooleanQueryBlock::*;

        match *self {
            Leaf{ref op, ref mut return_type} => *return_type = new_type,
            Combinator{ref op, ref child_a, ref child_b, ref mut return_type} => *return_type = new_type,
        }
    }

    fn build(&self, boolean_query: &mut Vec<BooleanQueryOp>) {
        use self::BooleanQueryBlock::*;

        match *self {
            Leaf{ref op, ref return_type} => {
                boolean_query.push(op.clone());
            }
            Combinator{ref op, ref child_a, ref child_b, ref return_type} => {
                child_a.build(boolean_query);
                child_b.build(boolean_query);
                boolean_query.push(op.clone());
            }
        }
    }
}

pub struct BooleanQueryBuilder {
    stack: Vec<Rc<BooleanQueryBlock>>,
}

impl BooleanQueryBuilder {
    pub fn new() -> BooleanQueryBuilder {
        BooleanQueryBuilder {
            stack: Vec::new(),
        }
    }

    pub fn push_empty(&mut self) {
        self.stack.push(Rc::new(BooleanQueryBlock::Leaf{
            op: BooleanQueryOp::PushEmpty,
            return_type: BooleanQueryBlockReturnType::Empty,
        }));
    }

    pub fn push_full(&mut self) {
        self.stack.push(Rc::new(BooleanQueryBlock::Leaf{
            op: BooleanQueryOp::PushFull,
            return_type: BooleanQueryBlockReturnType::Full,
        }));
    }

    pub fn push_op(&mut self, op: &BooleanQueryOp) {
        use search::boolean_retrieval::BooleanQueryOp::*;
        use self::BooleanQueryBlock::*;
        use self::BooleanQueryBlockReturnType::*;

        match *op {
            PushEmpty => {
                self.push_empty();
            }
            PushFull => {
                self.push_full();
            }
            PushTermDirectory(field_ref, term_ref, tag) => {
                self.stack.push(Rc::new(Leaf{
                    op: PushTermDirectory(field_ref, term_ref, tag),
                    return_type: Sparse,
                }));
            }
            PushDeletionList => {
                self.stack.push(Rc::new(Leaf{
                    op: PushDeletionList,
                    return_type: Sparse,
                }));
            }
            And => {
                let b = self.stack.pop().expect("stack underflow");
                let a = self.stack.pop().expect("stack underflow");

                match (a.return_type(), b.return_type()) {
                    // If either block is "full", replace this block with the other block
                    (Full, _) => self.stack.push(b),
                    (_, Full) => self.stack.push(a),

                    // If either block is "empty", this block will be empty too
                    (Empty, _) => self.push_empty(),
                    (_, Empty) => self.push_empty(),

                    (Sparse, Sparse) => {  // (a AND b)
                        // Intersection
                        self.stack.push(Rc::new(Combinator{
                            op: And,
                            child_a: a,
                            child_b: b,
                            return_type: Sparse,
                        }));
                    }

                    (Sparse, NegatedSparse) => {  // (a AND NOT b)
                        // Exclusion
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: a,
                            child_b: b,
                            return_type: Sparse,
                        }));
                    }

                    (NegatedSparse, Sparse) => {  // (NOT a AND b)
                        // Exclusion, with operands swapped
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: b,
                            child_b: a,
                            return_type: Sparse,
                        }));
                    }

                    (NegatedSparse, NegatedSparse) => {  // (NOT a AND NOT b)
                        // Negated union (NOT (a OR b))
                        self.stack.push(Rc::new(Combinator{
                            op: Or,
                            child_a: a,
                            child_b: b,
                            return_type: NegatedSparse,
                        }));
                    }
                }
            }
            Or => {
                let b = self.stack.pop().expect("stack underflow");
                let a = self.stack.pop().expect("stack underflow");

                match (a.return_type(), b.return_type()) {
                    // If either block is "full", this block will be full too
                    (Full, _) => self.push_full(),
                    (_, Full) => self.push_full(),

                    // If either block is "empty", replace this block with the other block
                    (Empty, _) => self.stack.push(b),
                    (_, Empty) => self.stack.push(a),

                    (Sparse, Sparse) => {  // (a OR b)
                        // Union
                        self.stack.push(Rc::new(Combinator{
                            op: Or,
                            child_a: a,
                            child_b: b,
                            return_type: Sparse,
                        }));
                    }

                    (Sparse, NegatedSparse) => {  // (a OR NOT b)
                        // Negated exclusion, with operands swapped (NOT (b AND NOT a))
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: b,
                            child_b: a,
                            return_type: NegatedSparse,
                        }));
                    }

                    (NegatedSparse, Sparse) => {  // (NOT a OR b)
                        // Negated exclusion (NOT (a AND NOT b))
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: a,
                            child_b: b,
                            return_type: NegatedSparse,
                        }));
                    }

                    (NegatedSparse, NegatedSparse) => {  // (NOT a OR NOT b)
                        // Negated intersection (NOT (a AND b))
                        self.stack.push(Rc::new(Combinator{
                            op: And,
                            child_a: a,
                            child_b: b,
                            return_type: NegatedSparse,
                        }));
                    }
                }
            }
            AndNot => {
                let b = self.stack.pop().expect("stack underflow");
                let a = self.stack.pop().expect("stack underflow");

                match (a.return_type(), b.return_type()) {
                    // If the right block is full, this block will be empty
                    (_, Full) => self.push_empty(),

                    // If the left block is empty, this block will be empty too
                    (Empty, _) => self.push_empty(),

                    // If the right block is empty, replace this block with the left block
                    (_, Empty) => self.stack.push(a),

                    (Full, Sparse) => {  // (ALL AND NOT b)
                        // Negation of b (NOT b)
                        let mut b_new = Rc::make_mut(&mut b.clone()).clone();
                        b_new.set_return_type(NegatedSparse);
                        self.stack.push(Rc::new(b_new));
                    }

                    (Full, NegatedSparse) => {  // (ALL AND NOT (NOT b))
                        // De-Negation of b (NOT (NOT b))
                        let mut b_new = Rc::make_mut(&mut b.clone()).clone();
                        b_new.set_return_type(Sparse);
                        self.stack.push(Rc::new(b_new));
                    }

                    (Sparse, Sparse) => {  // (a AND NOT b)
                        // Exclusion
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: a,
                            child_b: b,
                            return_type: Sparse,
                        }));
                    }

                    (Sparse, NegatedSparse) => {  // (a AND NOT (NOT b))
                        // Intersection (data AND other_data)
                        self.stack.push(Rc::new(Combinator{
                            op: And,
                            child_a: a,
                            child_b: b,
                            return_type: Sparse,
                        }));
                    }

                    (NegatedSparse, Sparse) => {  // (NOT a AND NOT b)
                        // Negated union (NOT (data OR other_data))
                        self.stack.push(Rc::new(Combinator{
                            op: Or,
                            child_a: a,
                            child_b: b,
                            return_type: NegatedSparse,
                        }));
                    }

                    (NegatedSparse, NegatedSparse) => {  // (NOT a AND NOT (NOT b))
                        // Exclusion, with operands swapped (b AND NOT a)
                        self.stack.push(Rc::new(Combinator{
                            op: AndNot,
                            child_a: b,
                            child_b: a,
                            return_type: Sparse,
                        }));
                    }
                }
            }
        }
    }

    pub fn build(&self) -> (Vec<BooleanQueryOp>, bool) {
        use self::BooleanQueryBlockReturnType::*;

        let mut boolean_query = Vec::new();

        // If the query was valid, should be exactly one item on the stack
        let root_block = self.stack.last().unwrap();
        root_block.build(&mut boolean_query);

        (boolean_query, root_block.return_type() == NegatedSparse)
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * This file contains a helper macro includes all supported non-tree-structural
 * pseudo-classes.
 *

 * FIXME: Find a way to autogenerate this file.
 *
 * Expected usage is as follows:
 * ```
 * macro_rules! pseudo_class_macro{
 *     (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
 *      string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
 *      keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
 *         // do stuff
 *     }
 * }
 * apply_non_ts_list!(pseudo_class_macro)
 * ```
 *
 * The `string` and `keyword` variables will be applied to pseudoclasses that are of the form of
 * functions with string or keyword arguments.
 *
 * Pending pseudo-classes:
 *
 *  :-moz-lwtheme, :-moz-lwtheme-brighttext, :-moz-lwtheme-darktext,
 *  :-moz-window-inactive.
 *
 *  :scope -> <style scoped>, pending discussion.
 *
 * This follows the order defined in layout/style/nsCSSPseudoClassList.h when
 * possible.
 *
 * $gecko_type can be either "_" or an ident in Gecko's CSSPseudoClassType.
 * $state can be either "_" or an expression of type ElementState.  If present,
 *        the semantics are that the pseudo-class matches if any of the bits in
 *        $state are set on the element.
 * $flags can be either "_" or an expression of type NonTSPseudoClassFlag,
 * see selector_parser.rs for more details.
 */

macro_rules! apply_non_ts_list {
    ($apply_macro:ident) => {
        $apply_macro! {
            bare: [
                ("unresolved", Unresolved, unresolved, IN_UNRESOLVED_STATE, _),
                ("-moz-table-border-nonzero", MozTableBorderNonzero, mozTableBorderNonzero, _, PSEUDO_CLASS_INTERNAL),
                ("-moz-browser-frame", MozBrowserFrame, mozBrowserFrame, _, PSEUDO_CLASS_INTERNAL),
                ("link", Link, link, IN_UNVISITED_STATE, _),
                ("any-link", AnyLink, anyLink, IN_VISITED_OR_UNVISITED_STATE, _),
                ("visited", Visited, visited, IN_VISITED_STATE, _),
                ("active", Active, active, IN_ACTIVE_STATE, _),
                ("checked", Checked, checked, IN_CHECKED_STATE, _),
                ("disabled", Disabled, disabled, IN_DISABLED_STATE, _),
                ("enabled", Enabled, enabled, IN_ENABLED_STATE, _),
                ("focus", Focus, focus, IN_FOCUS_STATE, _),
                ("focus-within", FocusWithin, focusWithin, IN_FOCUS_WITHIN_STATE, _),
                ("hover", Hover, hover, IN_HOVER_STATE, _),
                ("-moz-drag-over", MozDragOver, mozDragOver, IN_DRAGOVER_STATE, _),
                ("target", Target, target, IN_TARGET_STATE, _),
                ("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _),
                ("-moz-devtools-highlighted", MozDevtoolsHighlighted, mozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, _),
                ("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, mozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, _),
                // TODO(emilio): Needs pref check for
                // full-screen-api.unprefix.enabled!
                ("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_STATE, _),
                // TODO(emilio): This is inconsistently named (the capital R).
                ("-moz-focusring", MozFocusRing, mozFocusRing, IN_FOCUSRING_STATE, _),
                ("-moz-broken", MozBroken, mozBroken, IN_BROKEN_STATE, _),
                ("-moz-loading", MozLoading, mozLoading, IN_LOADING_STATE, _),
                ("-moz-suppressed", MozSuppressed, mozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-autofill", MozAutofill, mozAutofill, IN_AUTOFILL_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-autofill-preview", MozAutofillPreview, mozAutofillPreview, IN_AUTOFILL_PREVIEW_STATE, PSEUDO_CLASS_INTERNAL),

                ("-moz-handler-clicktoplay", MozHandlerClickToPlay, mozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-handler-vulnerable-updatable", MozHandlerVulnerableUpdatable, mozHandlerVulnerableUpdatable, IN_HANDLER_VULNERABLE_UPDATABLE_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-handler-vulnerable-no-update", MozHandlerVulnerableNoUpdate, mozHandlerVulnerableNoUpdate, IN_HANDLER_VULNERABLE_NO_UPDATE_STATE, PSEUDO_CLASS_INTERNAL),

                ("-moz-handler-disabled", MozHandlerDisabled, mozHandlerDisabled, IN_HANDLER_DISABLED_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-handler-blocked", MozHandlerBlocked, mozHandlerBlocked, IN_HANDLER_BLOCKED_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-handler-crashed", MozHandlerCrashed, mozHandlerCrashed, IN_HANDLER_CRASHED_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-math-increment-script-level", MozMathIncrementScriptLevel, mozMathIncrementScriptLevel, IN_INCREMENT_SCRIPT_LEVEL_STATE, _),

                ("required", Required, required, IN_REQUIRED_STATE, _),
                ("optional", Optional, optional, IN_OPTIONAL_STATE, _),
                ("valid", Valid, valid, IN_VALID_STATE, _),
                ("invalid", Invalid, invalid, IN_INVALID_STATE, _),
                ("in-range", InRange, inRange, IN_INRANGE_STATE, _),
                ("out-of-range", OutOfRange, outOfRange, IN_OUTOFRANGE_STATE, _),
                ("default", Default, defaultPseudo, IN_DEFAULT_STATE, _),
                ("placeholder-shown", PlaceholderShown, placeholderShown, IN_PLACEHOLDER_SHOWN_STATE, _),
                ("-moz-read-only", MozReadOnly, mozReadOnly, IN_MOZ_READONLY_STATE, _),
                ("-moz-read-write", MozReadWrite, mozReadWrite, IN_MOZ_READWRITE_STATE, _),
                ("-moz-submit-invalid", MozSubmitInvalid, mozSubmitInvalid, IN_MOZ_SUBMITINVALID_STATE, _),
                ("-moz-ui-valid", MozUIValid, mozUIValid, IN_MOZ_UI_VALID_STATE, _),
                ("-moz-ui-invalid", MozUIInvalid, mozUIInvalid, IN_MOZ_UI_INVALID_STATE, _),
                ("-moz-meter-optimum", MozMeterOptimum, mozMeterOptimum, IN_OPTIMUM_STATE, _),
                ("-moz-meter-sub-optimum", MozMeterSubOptimum, mozMeterSubOptimum, IN_SUB_OPTIMUM_STATE, _),
                ("-moz-meter-sub-sub-optimum", MozMeterSubSubOptimum, mozMeterSubSubOptimum, IN_SUB_SUB_OPTIMUM_STATE, _),

                ("-moz-user-disabled", MozUserDisabled, mozUserDisabled, IN_USER_DISABLED_STATE, PSEUDO_CLASS_INTERNAL),

                ("-moz-first-node", MozFirstNode, firstNode, _, _),
                ("-moz-last-node", MozLastNode, lastNode, _, _),
                ("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _),
                ("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_INTERNAL),
                ("-moz-is-html", MozIsHTML, mozIsHTML, _, _),
                ("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _),
            ],
            string: [
                ("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL),
                ("-moz-empty-except-children-with-localname", MozEmptyExceptChildrenWithLocalname,
                 mozEmptyExceptChildrenWithLocalname, _, PSEUDO_CLASS_INTERNAL),
                ("lang", Lang, lang, _, _),
            ],
            keyword: [
                ("-moz-locale-dir", MozLocaleDir, mozLocaleDir, _, PSEUDO_CLASS_INTERNAL),
                ("dir", Dir, dir, _, _),
            ]
        }
    }
}
<commit_msg>stylo: Make :-moz-locale-dir selector non-internal.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * This file contains a helper macro includes all supported non-tree-structural
 * pseudo-classes.
 *

 * FIXME: Find a way to autogenerate this file.
 *
 * Expected usage is as follows:
 * ```
 * macro_rules! pseudo_class_macro{
 *     (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
 *      string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
 *      keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
 *         // do stuff
 *     }
 * }
 * apply_non_ts_list!(pseudo_class_macro)
 * ```
 *
 * The `string` and `keyword` variables will be applied to pseudoclasses that are of the form of
 * functions with string or keyword arguments.
 *
 * Pending pseudo-classes:
 *
 *  :-moz-lwtheme, :-moz-lwtheme-brighttext, :-moz-lwtheme-darktext,
 *  :-moz-window-inactive.
 *
 *  :scope -> <style scoped>, pending discussion.
 *
 * This follows the order defined in layout/style/nsCSSPseudoClassList.h when
 * possible.
 *
 * $gecko_type can be either "_" or an ident in Gecko's CSSPseudoClassType.
 * $state can be either "_" or an expression of type ElementState.  If present,
 *        the semantics are that the pseudo-class matches if any of the bits in
 *        $state are set on the element.
 * $flags can be either "_" or an expression of type NonTSPseudoClassFlag,
 * see selector_parser.rs for more details.
 */

macro_rules! apply_non_ts_list {
    ($apply_macro:ident) => {
        $apply_macro! {
            bare: [
                ("unresolved", Unresolved, unresolved, IN_UNRESOLVED_STATE, _),
                ("-moz-table-border-nonzero", MozTableBorderNonzero, mozTableBorderNonzero, _, PSEUDO_CLASS_INTERNAL),
                ("-moz-browser-frame", MozBrowserFrame, mozBrowserFrame, _, PSEUDO_CLASS_INTERNAL),
                ("link", Link, link, IN_UNVISITED_STATE, _),
                ("any-link", AnyLink, anyLink, IN_VISITED_OR_UNVISITED_STATE, _),
                ("visited", Visited, visited, IN_VISITED_STATE, _),
                ("active", Active, active, IN_ACTIVE_STATE, _),
                ("checked", Checked, checked, IN_CHECKED_STATE, _),
                ("disabled", Disabled, disabled, IN_DISABLED_STATE, _),
                ("enabled", Enabled, enabled, IN_ENABLED_STATE, _),
                ("focus", Focus, focus, IN_FOCUS_STATE, _),
                ("focus-within", FocusWithin, focusWithin, IN_FOCUS_WITHIN_STATE, _),
                ("hover", Hover, hover, IN_HOVER_STATE, _),
                ("-moz-drag-over", MozDragOver, mozDragOver, IN_DRAGOVER_STATE, _),
                ("target", Target, target, IN_TARGET_STATE, _),
                ("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _),
                ("-moz-devtools-highlighted", MozDevtoolsHighlighted, mozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, _),
                ("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, mozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, _),
                // TODO(emilio): Needs pref check for
                // full-screen-api.unprefix.enabled!
                ("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_STATE, _),
                // TODO(emilio): This is inconsistently named (the capital R).
                ("-moz-focusring", MozFocusRing, mozFocusRing, IN_FOCUSRING_STATE, _),
                ("-moz-broken", MozBroken, mozBroken, IN_BROKEN_STATE, _),
                ("-moz-loading", MozLoading, mozLoading, IN_LOADING_STATE, _),
                ("-moz-suppressed", MozSuppressed, mozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-autofill", MozAutofill, mozAutofill, IN_AUTOFILL_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-autofill-preview", MozAutofillPreview, mozAutofillPreview, IN_AUTOFILL_PREVIEW_STATE, PSEUDO_CLASS_INTERNAL),

                ("-moz-handler-clicktoplay", MozHandlerClickToPlay, mozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-handler-vulnerable-updatable", MozHandlerVulnerableUpdatable, mozHandlerVulnerableUpdatable, IN_HANDLER_VULNERABLE_UPDATABLE_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-handler-vulnerable-no-update", MozHandlerVulnerableNoUpdate, mozHandlerVulnerableNoUpdate, IN_HANDLER_VULNERABLE_NO_UPDATE_STATE, PSEUDO_CLASS_INTERNAL),

                ("-moz-handler-disabled", MozHandlerDisabled, mozHandlerDisabled, IN_HANDLER_DISABLED_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-handler-blocked", MozHandlerBlocked, mozHandlerBlocked, IN_HANDLER_BLOCKED_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-handler-crashed", MozHandlerCrashed, mozHandlerCrashed, IN_HANDLER_CRASHED_STATE, PSEUDO_CLASS_INTERNAL),
                ("-moz-math-increment-script-level", MozMathIncrementScriptLevel, mozMathIncrementScriptLevel, IN_INCREMENT_SCRIPT_LEVEL_STATE, _),

                ("required", Required, required, IN_REQUIRED_STATE, _),
                ("optional", Optional, optional, IN_OPTIONAL_STATE, _),
                ("valid", Valid, valid, IN_VALID_STATE, _),
                ("invalid", Invalid, invalid, IN_INVALID_STATE, _),
                ("in-range", InRange, inRange, IN_INRANGE_STATE, _),
                ("out-of-range", OutOfRange, outOfRange, IN_OUTOFRANGE_STATE, _),
                ("default", Default, defaultPseudo, IN_DEFAULT_STATE, _),
                ("placeholder-shown", PlaceholderShown, placeholderShown, IN_PLACEHOLDER_SHOWN_STATE, _),
                ("-moz-read-only", MozReadOnly, mozReadOnly, IN_MOZ_READONLY_STATE, _),
                ("-moz-read-write", MozReadWrite, mozReadWrite, IN_MOZ_READWRITE_STATE, _),
                ("-moz-submit-invalid", MozSubmitInvalid, mozSubmitInvalid, IN_MOZ_SUBMITINVALID_STATE, _),
                ("-moz-ui-valid", MozUIValid, mozUIValid, IN_MOZ_UI_VALID_STATE, _),
                ("-moz-ui-invalid", MozUIInvalid, mozUIInvalid, IN_MOZ_UI_INVALID_STATE, _),
                ("-moz-meter-optimum", MozMeterOptimum, mozMeterOptimum, IN_OPTIMUM_STATE, _),
                ("-moz-meter-sub-optimum", MozMeterSubOptimum, mozMeterSubOptimum, IN_SUB_OPTIMUM_STATE, _),
                ("-moz-meter-sub-sub-optimum", MozMeterSubSubOptimum, mozMeterSubSubOptimum, IN_SUB_SUB_OPTIMUM_STATE, _),

                ("-moz-user-disabled", MozUserDisabled, mozUserDisabled, IN_USER_DISABLED_STATE, PSEUDO_CLASS_INTERNAL),

                ("-moz-first-node", MozFirstNode, firstNode, _, _),
                ("-moz-last-node", MozLastNode, lastNode, _, _),
                ("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _),
                ("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_INTERNAL),
                ("-moz-is-html", MozIsHTML, mozIsHTML, _, _),
                ("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _),
            ],
            string: [
                ("-moz-system-metric", MozSystemMetric, mozSystemMetric, _, PSEUDO_CLASS_INTERNAL),
                ("-moz-empty-except-children-with-localname", MozEmptyExceptChildrenWithLocalname,
                 mozEmptyExceptChildrenWithLocalname, _, PSEUDO_CLASS_INTERNAL),
                ("lang", Lang, lang, _, _),
            ],
            keyword: [
                ("-moz-locale-dir", MozLocaleDir, mozLocaleDir, _, _),
                ("dir", Dir, dir, _, _),
            ]
        }
    }
}
<|endoftext|>