Files @ e1432caf0735
Branch filter:

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

e1432caf0735 9.9 KiB application/rls-services+xml Show Annotation Show as Raw Download as Raw
MH
Replace reserved keywords with global std lib funcs
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_writer;

use std::sync::Mutex;

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

pub use parser::type_table::TypeId;

/// 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 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 ast_definition = &self.heap[definition_id];
        if !ast_definition.is_procedure() {
            return Err(ComponentCreationError::DefinitionNotComponent);
        }

        // Make sure that the types of the provided value group matches that of
        // the expected types.
        let ast_definition = ast_definition.as_procedure();
        if !ast_definition.poly_vars.is_empty() || ast_definition.kind == ProcedureKind::Function {
            return Err(ComponentCreationError::DefinitionNotComponent);
        }

        // - check number of arguments by retrieving the one instantiated
        //   monomorph
        let concrete_type = ConcreteType{ parts: vec![ConcreteTypePart::Component(ast_definition.this, 0)] };
        let procedure_type_id = self.types.get_procedure_monomorph_type_id(&definition_id, &concrete_type.parts).unwrap();
        let procedure_monomorph_index = self.types.get_monomorph(procedure_type_id).variant.as_procedure().monomorph_index;
        let monomorph_info = &ast_definition.monomorphs[procedure_monomorph_index as usize];
        if monomorph_info.argument_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_id = monomorph_info.argument_types[arg_idx];
            let expected_type = &self.types.get_monomorph(expected_type_id).concrete_type;
            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, ast_definition.this, procedure_type_id, 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::Pointer | 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::Tuple(_) => todo!("implement full type checking on user-supplied arguments"),
            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
    fn performed_select_wait(&mut self) -> Option<u32>; // None if not yet notified runtime of select blocker
}

pub struct ProtocolDescriptionBuilder {
    parser: Parser,
}

impl ProtocolDescriptionBuilder {
    pub fn new() -> Result<Self, String> {
        return Ok(Self{
            parser: Parser::new()?,
        })
    }

    pub fn add(&mut self, filename: String, buffer: Vec<u8>) -> Result<(), ParseError> {
        let input = InputSource::new(filename, buffer);
        self.parser.feed(input)?;

        return Ok(())
    }

    pub fn compile(mut self) -> Result<ProtocolDescription, ParseError> {
        self.parser.parse()?;

        let modules: Vec<Module> = self.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: self.parser.heap,
            types: self.parser.type_table,
            pool: Mutex::new(self.parser.string_pool),
        });
    }
}