oftlisp 0.1.3

A compiler and interpreter for OftLisp, in Rust.
Documentation
use std::collections::HashMap;

use gc::Gc;

use context::InterpreterContext;
use symbol::Symbol;
use value::Value;

macro_rules! define_primitives {
    ($($(#[doc = $m:expr])* ($prim:ident : $name:expr))*) => {
        /// A helper struct to define the
        /// [`InterpreterContext::primitives`](../trait.InterpreterContext.html#tymethod.primitives)
        /// method.
        #[derive(Clone, Debug)]
        pub struct Primitives<C: 'static + InterpreterContext> {
            $($(#[doc = $m])* pub $prim: C::BuiltinFunction,)*
        }

        impl<C: 'static + InterpreterContext> Into<HashMap<Symbol, Gc<Value<C>>>> for Primitives<C> {
            fn into(self) -> HashMap<Symbol, Gc<Value<C>>> {
                let fields = vec![
                    $(($name.into(), self.$prim),)*
                ];
                fields.into_iter()
                    .map(|(k, v)| (k, Gc::new(Value::BuiltinFunction(k, v, C::ValueMeta::default()))))
                    .collect()
            }
        }
    }
}

define_primitives! {
    /// Applies arguments to a function.
    (apply: "apply")

    /// The compare-and-swap operation on atomic words.
    (atomic_word_cas: "atomic-word.cas")

    /// Loads the value from an atomic word as a fixnum.
    (atomic_word_load: "atomic-word.load")

    /// Creates a new atomic word, initialized to the given fixnum.
    (atomic_word_new: "atomic-word")

    /// Stores a value into an atomic word as a fixnum.
    (atomic_word_store: "atomic-word.store")

    /// Converts a fixnum to a byte, returning nil if it's out of range.
    (byte_of_fixnum: "byte<-fixnum")

    /// Converts a string to a bytes object.
    (bytes_of_string: "bytes<-string")

    /// Returns the first item (head) of a cons.
    (car: "car")

    /// Returns the second item (tail) of a cons.
    (cdr: "cdr")

    /// Compares two values, returning the symbol:
    ///
    ///  - `>` if the first is greater than the second,
    ///  - `=` if the first is equal to the second,
    ///  - `<` if the first is less than the second,
    ///  - `<>` if the values are incomparable.
    ///
    /// Values are incomparable if they are of incompatible types, although
    /// what this means is implementation-defined.
    (compare: "compare")

    /// Concatenates one or more strings.
    (concat_strings: "concat-strings")

    /// Creates a cons cell from the arguments.
    (cons: "cons")

    /// Outputs a value and returns it. In what manner the value is outputted
    /// is implementation-defined.
    (debug: "debug")

    /// Checks if two values are equal. The check does *not* return true for
    /// two values of different types; that is, `(eq 0 0.0)` returns false.
    (eq: "eq")

    /// Exits with the given exit code.
    (exit_with: "exit-with")

    /// Converts a byte to a fixnum.
    (fixnum_of_byte: "fixnum<-byte")

    /// Generates a new symbol, guaranteed to be unique.
    (gensym: "gensym")

    /// Returns whether the given value is a byte.
    (is_byte: "byte?")

    /// Returns whether the given value is a cons cell.
    (is_cons: "cons?")

    /// Returns whether the given value is a fixnum.
    (is_fixnum: "fixnum?")

    /// Returns whether the given value is nil.
    (is_nil: "nil?")

    /// Returns whether the given value is an object.
    (is_object: "object?")

    /// Returns whether the given value is a string.
    (is_string: "string?")

    /// Returns whether the given value is a symbol.
    (is_symbol: "symbol?")

    /// Returns whether the given value is a vector.
    (is_vector: "vector?")

    /// Converts a vector to a list.
    (list_of_vector: "list<-vector")

    /// Creates a vector of the given length, filled with nils.
    (make_vector: "make-vector")

    /// Returns the number of data items in the given object.
    (object_data_len: "object-data-len")

    /// Gets the nth data item in the given object.
    (object_get_data: "object-get-data")

    /// Returns the named function from the given object.
    (object_get_func: "object-get-func")

    /// Returns whether a function with the given name from the given object.
    (object_has_func: "object-has-func?")

    /// Seals an assoc of names to functions and a vector of data items into an
    /// object.
    (object_seal: "object-seal")

    /// Unseals an object, returning the vtable as an assoc of names to
    /// functions and the data items in a vector.
    (object_unseal: "object-unseal")

    /// Adds two numbers.
    ///
    /// TODO: Document the interaction with types.
    (op_add: "+/2")

    /// Compares two numbers. Unlike `compare`, it can compare across types,
    /// but compares them strictly numerically. If a non-numeric type is given,
    /// this function will panic.
    (op_cmp: "<>")

    /// Divides two numbers.
    ///
    /// TODO: Document the interaction with types.
    (op_div: "//2")

    /// Checks two numbers for equality. Unlike `eq`, it will compare
    /// numerically equal values of different types as equal. If a non-numeric
    /// type is given, this function will panic.
    (op_equ: "=")

    /// Takes the modulo operation of two numbers.
    ///
    /// TODO: Document the interaction with types.
    (op_mod: "mod/2")

    /// Multiplies two numbers.
    ///
    /// TODO: Document the interaction with types.
    (op_mul: "*/2")

    /// Subtracts two numbers.
    ///
    /// TODO: Document the interaction with types.
    (op_sub: "-/2")

    /// Causes a panic with the given reason (as a string).
    (panic: "panic")

    /// Converts a symbol into a string.
    (string_of_symbol: "string<-symbol")

    /// Converts a string to a symbol. If the given string is an invalid
    /// symbol, returns nil.
    (symbol_of_string: "symbol<-string")

    /// Shows a non-object value as a string. Behavior when an object is passed
    /// is implementation-defined.
    (show_primitive: "show-primitive")

    /// Takes two zero-argument functions, immediately calling the first.
    /// Regardless of whether the first function panics, the second function
    /// will be executed afterwards, before control flow leaves the
    /// `unwind-protect` form.
    ///
    /// If both the first and second functions panic, only the second panic will
    /// be observable.
    ///
    /// Evaluates to the value returned by the first function.
    (unwind_protect: "unwind-protect")

    /// Converts a list to a vector.
    (vector_of_list: "vector<-list")

    /// Writes a bytes to stdout (or the nearest equivalent).
    (write_bytes: "write-bytes")
}