Files @ c1b2442f23b2
Branch filter:

Location: CSY/reowolf/src/protocol/mod.rs

c1b2442f23b2 8.2 KiB application/rls-services+xml Show Annotation Show as Raw Download as Raw
MH
Remove references to old runtime and stale code
mod arena;
pub(crate) mod eval;
pub(crate) mod input_source;
mod parser;
#[cfg(test)] mod tests;

pub(crate) mod ast;
pub(crate) mod ast_printer;

use std::sync::Mutex;

use crate::collections::{StringPool, StringRef};
use crate::protocol::ast::*;
use crate::protocol::eval::*;
use crate::protocol::input_source::*;
use crate::protocol::parser::*;
use crate::protocol::type_table::*;

/// A protocol description module
pub struct Module {
    pub(crate) source: InputSource,
    pub(crate) root_id: RootId,
    pub(crate) name: Option<StringRef<'static>>,
}
/// Description of a protocol object, used to configure new connectors.
#[repr(C)]
pub struct ProtocolDescription {
    pub(crate) modules: Vec<Module>,
    pub(crate) heap: Heap,
    pub(crate) types: TypeTable,
    pub(crate) pool: Mutex<StringPool>,
}
#[derive(Debug, Clone)]
pub(crate) struct ComponentState {
    pub(crate) prompt: Prompt,
}

#[derive(Debug)]
pub enum ComponentCreationError {
    ModuleDoesntExist,
    DefinitionDoesntExist,
    DefinitionNotComponent,
    InvalidNumArguments,
    InvalidArgumentType(usize),
    UnownedPort,
    InSync,
}

impl std::fmt::Debug for ProtocolDescription {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "(An opaque protocol description)")
    }
}
impl ProtocolDescription {
    pub fn parse(buffer: &[u8]) -> Result<Self, String> {
        let source = InputSource::new(String::new(), Vec::from(buffer));
        let mut parser = Parser::new();
        parser.feed(source).expect("failed to feed source");
        
        if let Err(err) = parser.parse() {
            println!("ERROR:\n{}", err);
            return Err(format!("{}", err))
        }

        debug_assert_eq!(parser.modules.len(), 1, "only supporting one module here for now");
        let modules: Vec<Module> = parser.modules.into_iter()
            .map(|module| Module{
                source: module.source,
                root_id: module.root_id,
                name: module.name.map(|(_, name)| name)
            })
            .collect();

        return Ok(ProtocolDescription {
            modules,
            heap: parser.heap,
            types: parser.type_table,
            pool: Mutex::new(parser.string_pool),
        });
    }

    pub(crate) fn new_component(
        &self, module_name: &[u8], identifier: &[u8], arguments: ValueGroup
    ) -> Result<Prompt, ComponentCreationError> {
        // Find the module in which the definition can be found
        let module_root = self.lookup_module_root(module_name);
        if module_root.is_none() {
            return Err(ComponentCreationError::ModuleDoesntExist);
        }
        let module_root = module_root.unwrap();

        let root = &self.heap[module_root];
        let definition_id = root.get_definition_ident(&self.heap, identifier);
        if definition_id.is_none() {
            return Err(ComponentCreationError::DefinitionDoesntExist);
        }
        let definition_id = definition_id.unwrap();

        let definition = &self.heap[definition_id];
        if !definition.is_component() {
            return Err(ComponentCreationError::DefinitionNotComponent);
        }

        // Make sure that the types of the provided value group matches that of
        // the expected types.
        let definition = definition.as_component();
        if !definition.poly_vars.is_empty() {
            return Err(ComponentCreationError::DefinitionNotComponent);
        }

        // - check number of arguments
        let expr_data = self.types.get_procedure_expression_data(&definition_id, 0);
        if expr_data.arg_types.len() != arguments.values.len() {
            return Err(ComponentCreationError::InvalidNumArguments);
        }

        // - for each argument try to make sure the types match
        for arg_idx in 0..arguments.values.len() {
            let expected_type = &expr_data.arg_types[arg_idx];
            let provided_value = &arguments.values[arg_idx];
            if !self.verify_same_type(expected_type, 0, &arguments, provided_value) {
                return Err(ComponentCreationError::InvalidArgumentType(arg_idx));
            }
        }

        // By now we're sure that all of the arguments are correct. So create
        // the connector.
        return Ok(Prompt::new(&self.types, &self.heap, definition_id, 0, arguments));
    }

    fn lookup_module_root(&self, module_name: &[u8]) -> Option<RootId> {
        for module in self.modules.iter() {
            match &module.name {
                Some(name) => if name.as_bytes() == module_name {
                    return Some(module.root_id);
                },
                None => if module_name.is_empty() {
                    return Some(module.root_id);
                }
            }
        }

        return None;
    }

    fn verify_same_type(&self, expected: &ConcreteType, expected_idx: usize, arguments: &ValueGroup, argument: &Value) -> bool {
        use ConcreteTypePart as CTP;

        match &expected.parts[expected_idx] {
            CTP::Void | CTP::Message | CTP::Slice | CTP::Function(_, _) | CTP::Component(_, _) => unreachable!(),
            CTP::Bool => if let Value::Bool(_) = argument { true } else { false },
            CTP::UInt8 => if let Value::UInt8(_) = argument { true } else { false },
            CTP::UInt16 => if let Value::UInt16(_) = argument { true } else { false },
            CTP::UInt32 => if let Value::UInt32(_) = argument { true } else { false },
            CTP::UInt64 => if let Value::UInt64(_) = argument { true } else { false },
            CTP::SInt8 => if let Value::SInt8(_) = argument { true } else { false },
            CTP::SInt16 => if let Value::SInt16(_) = argument { true } else { false },
            CTP::SInt32 => if let Value::SInt32(_) = argument { true } else { false },
            CTP::SInt64 => if let Value::SInt64(_) = argument { true } else { false },
            CTP::Character => if let Value::Char(_) = argument { true } else { false },
            CTP::String => {
                // Match outer string type and embedded character types
                if let Value::String(heap_pos) = argument {
                    for element in &arguments.regions[*heap_pos as usize] {
                        if let Value::Char(_) = element {} else {
                            return false;
                        }
                    }
                } else {
                    return false;
                }

                return true;
            },
            CTP::Array => {
                if let Value::Array(heap_pos) = argument {
                    let heap_pos = *heap_pos;
                    for element in &arguments.regions[heap_pos as usize] {
                        if !self.verify_same_type(expected, expected_idx + 1, arguments, element) {
                            return false;
                        }
                    }
                    return true;
                } else {
                    return false;
                }
            },
            CTP::Input => if let Value::Input(_) = argument { true } else { false },
            CTP::Output => if let Value::Output(_) = argument { true } else { false },
            CTP::Instance(definition_id, _num_embedded) => {
                let definition = self.types.get_base_definition(definition_id).unwrap();
                match &definition.definition {
                    DefinedTypeVariant::Enum(definition) => {
                        if let Value::Enum(variant_value) = argument {
                            let is_valid = definition.variants.iter()
                                .any(|v| v.value == *variant_value);
                            return is_valid;
                        }
                    },
                    _ => todo!("implement full type checking on user-supplied arguments"),
                }

                return false;
            },
        }
    }
}

pub trait RunContext {
    fn performed_put(&mut self, port: PortId) -> bool;
    fn performed_get(&mut self, port: PortId) -> Option<ValueGroup>; // None if still waiting on message
    fn fires(&mut self, port: PortId) -> Option<Value>; // None if not yet branched
    fn performed_fork(&mut self) -> Option<bool>; // None if not yet forked
    fn created_channel(&mut self) -> Option<(Value, Value)>; // None if not yet prepared
}