Changeset - c6a9e4f128f2
[Not reviewed]
src/collections/raw_vec.rs
Show inline comments
 
@@ -62,20 +62,6 @@ impl<T: Sized> RawVec<T> {
 
        }
 
    }
 

	
 
    /// Moves the elements in the range [from_idx, from_idx + num_to_move) to
 
    /// the range [to_idx, to_idx + num_to_move). Caller must make sure that all
 
    /// non-overlapping elements of the second range had their destructor called
 
    /// in case those elements were used.
 
    pub fn move_range(&mut self, from_idx: usize, to_idx: usize, num_to_move: usize) {
 
        debug_assert!(from_idx + num_to_move <= self.len);
 
        debug_assert!(to_idx + num_to_move <= self.len); // maybe not in future, for now this is fine
 
        unsafe {
 
            let source = self.base.add(from_idx);
 
            let target = self.base.add(to_idx);
 
            std::ptr::copy(source, target, num_to_move);
 
        }
 
    }
 

	
 
    pub fn len(&self) -> usize {
 
        return self.len;
 
    }
src/protocol/ast.rs
Show inline comments
 
@@ -117,8 +117,7 @@ define_aliased_ast_id!(DefinitionId, Id<Definition>, index(Definition, definitio
 
define_new_ast_id!(StructDefinitionId, DefinitionId, index(StructDefinition, Definition::Struct, definitions), alloc(alloc_struct_definition));
 
define_new_ast_id!(EnumDefinitionId, DefinitionId, index(EnumDefinition, Definition::Enum, definitions), alloc(alloc_enum_definition));
 
define_new_ast_id!(UnionDefinitionId, DefinitionId, index(UnionDefinition, Definition::Union, definitions), alloc(alloc_union_definition));
 
define_new_ast_id!(ComponentDefinitionId, DefinitionId, index(ComponentDefinition, Definition::Component, definitions), alloc(alloc_component_definition));
 
define_new_ast_id!(FunctionDefinitionId, DefinitionId, index(FunctionDefinition, Definition::Function, definitions), alloc(alloc_function_definition));
 
define_new_ast_id!(ProcedureDefinitionId, DefinitionId, index(ProcedureDefinition, Definition::Procedure, definitions), alloc(alloc_procedure_definition));
 

	
 
define_aliased_ast_id!(StatementId, Id<Statement>, index(Statement, statements));
 
define_new_ast_id!(BlockStatementId, StatementId, index(BlockStatement, Statement::Block, statements), alloc(alloc_block_statement));
 
@@ -214,14 +213,20 @@ impl Heap {
 
impl Index<MemoryStatementId> for Heap {
 
    type Output = MemoryStatement;
 
    fn index(&self, index: MemoryStatementId) -> &Self::Output {
 
        &self.statements[index.0.0].as_memory()
 
        match &self.statements[index.0.0] {
 
            Statement::Local(LocalStatement::Memory(v)) => v,
 
            _ => unreachable!(),
 
        }
 
    }
 
}
 

	
 
impl Index<ChannelStatementId> for Heap {
 
    type Output = ChannelStatement;
 
    fn index(&self, index: ChannelStatementId) -> &Self::Output {
 
        &self.statements[index.0.0].as_channel()
 
        match &self.statements[index.0.0] {
 
            Statement::Local(LocalStatement::Channel(v)) => v,
 
            _ => unreachable!(),
 
        }
 
    }
 
}
 

	
 
@@ -515,8 +520,8 @@ pub enum ConcreteTypePart {
 
    Tuple(u32),
 
    // User defined type with any number of nested types
 
    Instance(DefinitionId, u32),    // instance of data type
 
    Function(DefinitionId, u32),    // instance of function
 
    Component(DefinitionId, u32),   // instance of a connector
 
    Function(ProcedureDefinitionId, u32),    // instance of function
 
    Component(ProcedureDefinitionId, u32),   // instance of a connector
 
}
 

	
 
impl ConcreteTypePart {
 
@@ -651,27 +656,35 @@ impl ConcreteType {
 
                }
 
                target.push(')');
 
            },
 
            CTP::Instance(definition_id, num_poly_args) |
 
            CTP::Instance(definition_id, num_poly_args) => {
 
                idx = Self::render_definition_type_parts_at(parts, heap, definition_id, num_poly_args, idx, target);
 
            }
 
            CTP::Function(definition_id, num_poly_args) |
 
            CTP::Component(definition_id, num_poly_args) => {
 
                let definition = &heap[definition_id];
 
                target.push_str(definition.identifier().value.as_str());
 

	
 
                if num_poly_args != 0 {
 
                    target.push('<');
 
                    for poly_arg_idx in 0..num_poly_args {
 
                        if poly_arg_idx != 0 {
 
                            target.push(',');
 
                        }
 
                        idx = Self::render_type_part_at(parts, heap, idx, target);
 
                    }
 
                    target.push('>');
 
                }
 
                idx = Self::render_definition_type_parts_at(parts, heap, definition_id.upcast(), num_poly_args, idx, target);
 
            }
 
        }
 

	
 
        idx
 
    }
 

	
 
    fn render_definition_type_parts_at(parts: &[ConcreteTypePart], heap: &Heap, definition_id: DefinitionId, num_poly_args: u32, mut idx: usize, target: &mut String) -> usize {
 
        let definition = &heap[definition_id];
 
        target.push_str(definition.identifier().value.as_str());
 

	
 
        if num_poly_args != 0 {
 
            target.push('<');
 
            for poly_arg_idx in 0..num_poly_args {
 
                if poly_arg_idx != 0 {
 
                    target.push(',');
 
                }
 
                idx = Self::render_type_part_at(parts, heap, idx, target);
 
            }
 
            target.push('>');
 
        }
 

	
 
        return idx;
 
    }
 
}
 

	
 
#[derive(Debug)]
 
@@ -798,8 +811,7 @@ pub enum Definition {
 
    Struct(StructDefinition),
 
    Enum(EnumDefinition),
 
    Union(UnionDefinition),
 
    Component(ComponentDefinition),
 
    Function(FunctionDefinition),
 
    Procedure(ProcedureDefinition),
 
}
 

	
 
impl Definition {
 
@@ -851,71 +863,50 @@ impl Definition {
 
            _ => panic!("Unable to cast 'Definition' to 'UnionDefinition'"),
 
        }
 
    }
 

	
 
    pub(crate) fn as_union_mut(&mut self) -> &mut UnionDefinition {
 
        match self {
 
            Definition::Union(result) => result,
 
            _ => panic!("Unable to cast 'Definition' to 'UnionDefinition'"),
 
        }
 
    }
 
    pub fn is_component(&self) -> bool {
 
        match self {
 
            Definition::Component(_) => true,
 
            _ => false,
 
        }
 
    }
 
    pub(crate) fn as_component(&self) -> &ComponentDefinition {
 
        match self {
 
            Definition::Component(result) => result,
 
            _ => panic!("Unable to cast `Definition` to `Component`"),
 
        }
 
    }
 
    pub(crate) fn as_component_mut(&mut self) -> &mut ComponentDefinition {
 
        match self {
 
            Definition::Component(result) => result,
 
            _ => panic!("Unable to cast `Definition` to `Component`"),
 
        }
 
    }
 
    pub fn is_function(&self) -> bool {
 

	
 
    pub fn is_procedure(&self) -> bool {
 
        match self {
 
            Definition::Function(_) => true,
 
            Definition::Procedure(_) => true,
 
            _ => false,
 
        }
 
    }
 
    pub(crate) fn as_function(&self) -> &FunctionDefinition {
 

	
 
    pub(crate) fn as_procedure(&self) -> &ProcedureDefinition {
 
        match self {
 
            Definition::Function(result) => result,
 
            Definition::Procedure(result) => result,
 
            _ => panic!("Unable to cast `Definition` to `Function`"),
 
        }
 
    }
 
    pub(crate) fn as_function_mut(&mut self) -> &mut FunctionDefinition {
 

	
 
    pub(crate) fn as_procedure_mut(&mut self) -> &mut ProcedureDefinition {
 
        match self {
 
            Definition::Function(result) => result,
 
            Definition::Procedure(result) => result,
 
            _ => panic!("Unable to cast `Definition` to `Function`"),
 
        }
 
    }
 
    pub fn parameters(&self) -> &Vec<VariableId> {
 
        match self {
 
            Definition::Component(def) => &def.parameters,
 
            Definition::Function(def) => &def.parameters,
 
            _ => panic!("Called parameters() on {:?}", self)
 
        }
 
    }
 

	
 
    pub fn defined_in(&self) -> RootId {
 
        match self {
 
            Definition::Struct(def) => def.defined_in,
 
            Definition::Enum(def) => def.defined_in,
 
            Definition::Union(def) => def.defined_in,
 
            Definition::Component(def) => def.defined_in,
 
            Definition::Function(def) => def.defined_in,
 
            Definition::Procedure(def) => def.defined_in,
 
        }
 
    }
 

	
 
    pub fn identifier(&self) -> &Identifier {
 
        match self {
 
            Definition::Struct(def) => &def.identifier,
 
            Definition::Enum(def) => &def.identifier,
 
            Definition::Union(def) => &def.identifier,
 
            Definition::Component(def) => &def.identifier,
 
            Definition::Function(def) => &def.identifier,
 
            Definition::Procedure(def) => &def.identifier,
 
        }
 
    }
 
    pub fn poly_vars(&self) -> &Vec<Identifier> {
 
@@ -923,8 +914,7 @@ impl Definition {
 
            Definition::Struct(def) => &def.poly_vars,
 
            Definition::Enum(def) => &def.poly_vars,
 
            Definition::Union(def) => &def.poly_vars,
 
            Definition::Component(def) => &def.poly_vars,
 
            Definition::Function(def) => &def.poly_vars,
 
            Definition::Procedure(def) => &def.poly_vars,
 
        }
 
    }
 
}
 
@@ -1018,75 +1008,49 @@ impl UnionDefinition {
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy)]
 
pub enum ComponentVariant {
 
    Primitive,
 
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 
pub enum ProcedureKind {
 
    Function, // with return type
 
    Primitive, // without return type
 
    Composite,
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ComponentDefinition {
 
    pub this: ComponentDefinitionId,
 
    pub defined_in: RootId,
 
    // Symbol scanning
 
    pub span: InputSpan,
 
    pub variant: ComponentVariant,
 
    pub identifier: Identifier,
 
    pub poly_vars: Vec<Identifier>,
 
    // Parsing
 
    pub parameters: Vec<VariableId>,
 
    pub scope: ScopeId,
 
    pub body: BlockStatementId,
 
    // Validation/linking
 
    pub num_expressions_in_body: i32,
 
}
 

	
 
impl ComponentDefinition {
 
    // Used for preallocation during symbol scanning
 
    pub(crate) fn new_empty(
 
        this: ComponentDefinitionId, defined_in: RootId, span: InputSpan,
 
        variant: ComponentVariant, identifier: Identifier, poly_vars: Vec<Identifier>
 
    ) -> Self {
 
        Self{ 
 
            this, defined_in, span, variant, identifier, poly_vars,
 
            parameters: Vec::new(),
 
            scope: ScopeId::new_invalid(),
 
            body: BlockStatementId::new_invalid(),
 
            num_expressions_in_body: -1,
 
        }
 
    }
 
}
 

	
 
/// Generic storage for functions, primitive components and composite
 
/// components.
 
// Note that we will have function definitions for builtin functions as well. In
 
// that case the span, the identifier span and the body are all invalid.
 
#[derive(Debug, Clone)]
 
pub struct FunctionDefinition {
 
    pub this: FunctionDefinitionId,
 
pub struct ProcedureDefinition {
 
    pub this: ProcedureDefinitionId,
 
    pub defined_in: RootId,
 
    // Symbol scanning
 
    pub builtin: bool,
 
    pub kind: ProcedureKind,
 
    pub span: InputSpan,
 
    pub identifier: Identifier,
 
    pub poly_vars: Vec<Identifier>,
 
    // Parser
 
    pub return_type: ParserType,
 
    pub return_type: Option<ParserType>, // present on functions, not components
 
    pub parameters: Vec<VariableId>,
 
    pub scope: ScopeId,
 
    pub body: BlockStatementId,
 
    // Monomorphization of typed procedures
 

	
 
    // Validation/linking
 
    pub num_expressions_in_body: i32,
 
}
 

	
 
impl FunctionDefinition {
 
impl ProcedureDefinition {
 
    pub(crate) fn new_empty(
 
        this: FunctionDefinitionId, defined_in: RootId, span: InputSpan,
 
        identifier: Identifier, poly_vars: Vec<Identifier>
 
        this: ProcedureDefinitionId, defined_in: RootId, span: InputSpan,
 
        kind: ProcedureKind, identifier: Identifier, poly_vars: Vec<Identifier>
 
    ) -> Self {
 
        Self {
 
            this, defined_in,
 
            builtin: false,
 
            span, identifier, poly_vars,
 
            return_type: ParserType{ elements: Vec::new(), full_span: InputSpan::new() },
 
            span,
 
            kind, identifier, poly_vars,
 
            return_type: None,
 
            parameters: Vec::new(),
 
            scope: ScopeId::new_invalid(),
 
            body: BlockStatementId::new_invalid(),
 
@@ -1120,25 +1084,6 @@ pub enum Statement {
 
}
 

	
 
impl Statement {
 
    pub fn as_block(&self) -> &BlockStatement {
 
        match self {
 
            Statement::Block(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `BlockStatement`"),
 
        }
 
    }
 
    pub fn as_local(&self) -> &LocalStatement {
 
        match self {
 
            Statement::Local(result) => result,
 
            _ => panic!("Unable to cast `Statement` to `LocalStatement`"),
 
        }
 
    }
 
    pub fn as_memory(&self) -> &MemoryStatement {
 
        self.as_local().as_memory()
 
    }
 
    pub fn as_channel(&self) -> &ChannelStatement {
 
        self.as_local().as_channel()
 
    }
 

	
 
    pub fn as_new(&self) -> &NewStatement {
 
        match self {
 
            Statement::New(result) => result,
 
@@ -1234,18 +1179,6 @@ impl LocalStatement {
 
            LocalStatement::Channel(stmt) => stmt.this.upcast(),
 
        }
 
    }
 
    pub fn as_memory(&self) -> &MemoryStatement {
 
        match self {
 
            LocalStatement::Memory(result) => result,
 
            _ => panic!("Unable to cast `LocalStatement` to `MemoryStatement`"),
 
        }
 
    }
 
    pub fn as_channel(&self) -> &ChannelStatement {
 
        match self {
 
            LocalStatement::Channel(result) => result,
 
            _ => panic!("Unable to cast `LocalStatement` to `ChannelStatement`"),
 
        }
 
    }
 
    pub fn span(&self) -> InputSpan {
 
        match self {
 
            LocalStatement::Channel(v) => v.span,
 
@@ -1791,7 +1724,7 @@ pub struct CallExpression {
 
    pub parser_type: ParserType, // of the function call, not the return type
 
    pub method: Method,
 
    pub arguments: Vec<ExpressionId>,
 
    pub definition: DefinitionId,
 
    pub procedure: ProcedureDefinitionId,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
@@ -1812,7 +1745,7 @@ pub enum Method {
 
    SelectRegisterCasePort, // SelectRegisterCasePort(case_index, port_index, port_id)
 
    SelectWait, // SelectWait() -> u32
 
    // User-defined
 
    UserFunction,
 
    UserProcedure,
 
    UserComponent,
 
}
 

	
src/protocol/ast_printer.rs
Show inline comments
 
@@ -345,7 +345,7 @@ impl ASTWriter {
 
                    }
 
                }
 
            }
 
            Definition::Function(def) => {
 
            Definition::Procedure(def) => {
 
                self.kv(indent).with_id(PREFIX_FUNCTION_ID, def.this.0.index)
 
                    .with_s_key("DefinitionFunction");
 

	
 
@@ -354,8 +354,11 @@ impl ASTWriter {
 
                    self.kv(indent3).with_s_key("PolyVar").with_identifier_val(&poly_var_id);
 
                }
 

	
 
                self.kv(indent2).with_s_key("ReturnParserType")
 
                    .with_custom_val(|s| write_parser_type(s, heap, &def.return_type));
 
                self.kv(indent2).with_s_key("Kind").with_debug_val(&def.kind);
 
                if let Some(parser_type) = &def.return_type {
 
                    self.kv(indent2).with_s_key("ReturnParserType")
 
                        .with_custom_val(|s| write_parser_type(s, heap, parser_type));
 
                }
 

	
 
                self.kv(indent2).with_s_key("Parameters");
 
                for variable_id in &def.parameters {
 
@@ -365,26 +368,6 @@ impl ASTWriter {
 
                self.kv(indent2).with_s_key("Body");
 
                self.write_stmt(heap, def.body.upcast(), indent3);
 
            },
 
            Definition::Component(def) => {
 
                self.kv(indent).with_id(PREFIX_COMPONENT_ID,def.this.0.index)
 
                    .with_s_key("DefinitionComponent");
 

	
 
                self.kv(indent2).with_s_key("Name").with_identifier_val(&def.identifier);
 
                self.kv(indent2).with_s_key("Variant").with_debug_val(&def.variant);
 

	
 
                self.kv(indent2).with_s_key("PolymorphicVariables");
 
                for poly_var_id in &def.poly_vars {
 
                    self.kv(indent3).with_s_key("PolyVar").with_identifier_val(&poly_var_id);
 
                }
 

	
 
                self.kv(indent2).with_s_key("Parameters");
 
                for variable_id in &def.parameters {
 
                    self.write_variable(heap, *variable_id, indent3)
 
                }
 

	
 
                self.kv(indent2).with_s_key("Body");
 
                self.write_stmt(heap, def.body.upcast(), indent3);
 
            }
 
        }
 
    }
 

	
 
@@ -782,19 +765,11 @@ impl ASTWriter {
 
                    .with_s_key("CallExpr");
 

	
 
                self.kv(indent2).with_s_key("UniqueId").with_disp_val(&expr.unique_id_in_definition);
 
                let definition = &heap[expr.definition];
 
                match definition {
 
                    Definition::Component(definition) => {
 
                        self.kv(indent2).with_s_key("BuiltIn").with_disp_val(&false);
 
                        self.kv(indent2).with_s_key("Variant").with_debug_val(&definition.variant);
 
                    },
 
                    Definition::Function(definition) => {
 
                        self.kv(indent2).with_s_key("BuiltIn").with_disp_val(&definition.builtin);
 
                        self.kv(indent2).with_s_key("Variant").with_s_val("Function");
 
                    },
 
                    _ => unreachable!()
 
                }
 
                self.kv(indent2).with_s_key("MethodName").with_identifier_val(definition.identifier());
 

	
 
                let definition = &heap[expr.procedure];
 
                self.kv(indent2).with_s_key("BuiltIn").with_disp_val(&false);
 
                self.kv(indent2).with_s_key("Variant").with_debug_val(&definition.kind);
 
                self.kv(indent2).with_s_key("MethodName").with_identifier_val(&definition.identifier);
 
                self.kv(indent2).with_s_key("ParserType")
 
                    .with_custom_val(|t| write_parser_type(t, heap, &expr.parser_type));
 

	
src/protocol/eval/error.rs
Show inline comments
 
@@ -52,18 +52,8 @@ impl EvalError {
 
            let statement = &heap[frame.position];
 
            let statement_span = statement.span();
 

	
 
            let (root_id, procedure, is_func) = match definition {
 
                Definition::Function(def) => {
 
                    (def.defined_in, def.identifier.value.as_str().to_string(), true)
 
                },
 
                Definition::Component(def) => {
 
                    (def.defined_in, def.identifier.value.as_str().to_string(), false)
 
                },
 
                _ => unreachable!("construct stack frame with definition pointing to data type")
 
            };
 

	
 
            // Lookup module name, if it has one
 
            let module = modules.iter().find(|m| m.root_id == root_id).unwrap();
 
            let module = modules.iter().find(|m| m.root_id == definition.defined_in).unwrap();
 
            let module_name = if let Some(name) = &module.name {
 
                name.as_str().to_string()
 
            } else {
 
@@ -74,8 +64,8 @@ impl EvalError {
 
            frames.push(EvalFrame{
 
                line: statement_span.begin.line,
 
                module_name,
 
                procedure,
 
                is_func
 
                procedure: definition.identifier.value.as_str().to_string(),
 
                is_func: definition.kind == ProcedureKind::Function,
 
            });
 
        }
 

	
src/protocol/eval/executor.rs
Show inline comments
 
@@ -26,7 +26,7 @@ pub(crate) enum ExprInstruction {
 

	
 
#[derive(Debug, Clone)]
 
pub(crate) struct Frame {
 
    pub(crate) definition: DefinitionId,
 
    pub(crate) definition: ProcedureDefinitionId,
 
    pub(crate) monomorph_type_id: TypeId,
 
    pub(crate) position: StatementId,
 
    pub(crate) expr_stack: VecDeque<ExprInstruction>, // hack for expression evaluation, evaluated by popping from back
 
@@ -36,13 +36,10 @@ pub(crate) struct Frame {
 

	
 
impl Frame {
 
    /// Creates a new execution frame. Does not modify the stack in any way.
 
    pub fn new(heap: &Heap, definition_id: DefinitionId, monomorph_type_id: TypeId) -> Self {
 
    pub fn new(heap: &Heap, definition_id: ProcedureDefinitionId, monomorph_type_id: TypeId) -> Self {
 
        let definition = &heap[definition_id];
 
        let (outer_scope_id, first_statement_id) = match definition {
 
            Definition::Component(definition) => (definition.scope, definition.body),
 
            Definition::Function(definition) => (definition.scope, definition.body),
 
            _ => unreachable!("initializing frame with {:?} instead of a function/component", definition),
 
        };
 
        let outer_scope_id = definition.scope;
 
        let first_statement_id = definition.body;
 

	
 
        // Another not-so-pretty thing that has to be replaced somewhere in the
 
        // future...
 
@@ -211,7 +208,7 @@ pub enum EvalContinuation {
 
    // Returned only in non-sync mode
 
    ComponentTerminated,
 
    SyncBlockStart,
 
    NewComponent(DefinitionId, TypeId, ValueGroup),
 
    NewComponent(ProcedureDefinitionId, TypeId, ValueGroup),
 
    NewChannel,
 
}
 

	
 
@@ -224,7 +221,7 @@ pub struct Prompt {
 
}
 

	
 
impl Prompt {
 
    pub fn new(_types: &TypeTable, heap: &Heap, def: DefinitionId, type_id: TypeId, args: ValueGroup) -> Self {
 
    pub fn new(_types: &TypeTable, heap: &Heap, def: ProcedureDefinitionId, type_id: TypeId, args: ValueGroup) -> Self {
 
        let mut prompt = Self{
 
            frames: Vec::new(),
 
            store: Store::new(),
 
@@ -291,7 +288,7 @@ impl Prompt {
 
        // Checking if we're at the end of execution
 
        let cur_frame = self.frames.last_mut().unwrap();
 
        if cur_frame.position.is_invalid() {
 
            if heap[cur_frame.definition].is_function() {
 
            if heap[cur_frame.definition].kind == ProcedureKind::Function {
 
                todo!("End of function without return, return an evaluation error");
 
            }
 
            return Ok(EvalContinuation::ComponentTerminated);
 
@@ -745,10 +742,10 @@ impl Prompt {
 
                                Method::UserComponent => {
 
                                    // This is actually handled by the evaluation
 
                                    // of the statement.
 
                                    debug_assert_eq!(heap[expr.definition].parameters().len(), cur_frame.expr_values.len());
 
                                    debug_assert_eq!(heap[expr.procedure].parameters.len(), cur_frame.expr_values.len());
 
                                    debug_assert_eq!(heap[cur_frame.position].as_new().expression, expr.this)
 
                                },
 
                                Method::UserFunction => {
 
                                Method::UserProcedure => {
 
                                    // Push a new frame. Note that all expressions have
 
                                    // been pushed to the front, so they're in the order
 
                                    // of the definition.
 
@@ -770,7 +767,7 @@ impl Prompt {
 
                                    let call_data = &mono_data.expr_data[expr.unique_id_in_definition as usize];
 

	
 
                                    // Push the new frame and reserve its stack size
 
                                    let new_frame = Frame::new(heap, expr.definition, call_data.type_id);
 
                                    let new_frame = Frame::new(heap, expr.procedure, call_data.type_id);
 
                                    let new_stack_size = new_frame.max_stack_size;
 
                                    self.frames.push(new_frame);
 
                                    self.store.cur_stack_boundary = new_stack_boundary;
 
@@ -779,7 +776,7 @@ impl Prompt {
 
                                    // To simplify the logic a little bit we will now
 
                                    // return and ask our caller to call us again
 
                                    return Ok(EvalContinuation::Stepping);
 
                                },
 
                                }
 
                            }
 
                        },
 
                        Expression::Variable(expr) => {
 
@@ -977,7 +974,6 @@ impl Prompt {
 
                Ok(EvalContinuation::Stepping)
 
            },
 
            Statement::Return(_stmt) => {
 
                debug_assert!(heap[cur_frame.definition].is_function());
 
                debug_assert_eq!(cur_frame.expr_values.len(), 1, "expected one expr value for return statement");
 

	
 
                // The preceding frame has executed a call, so is expecting the
 
@@ -1024,9 +1020,8 @@ impl Prompt {
 
            },
 
            Statement::New(stmt) => {
 
                let call_expr = &heap[stmt.expression];
 
                debug_assert!(heap[call_expr.definition].is_component());
 
                debug_assert_eq!(
 
                    cur_frame.expr_values.len(), heap[call_expr.definition].parameters().len(),
 
                    cur_frame.expr_values.len(), heap[call_expr.procedure].parameters.len(),
 
                    "mismatch in expr stack size and number of arguments for new statement"
 
                );
 

	
 
@@ -1052,7 +1047,7 @@ impl Prompt {
 

	
 
                cur_frame.position = stmt.next;
 

	
 
                Ok(EvalContinuation::NewComponent(call_expr.definition, expr_data.type_id, argument_group))
 
                Ok(EvalContinuation::NewComponent(call_expr.procedure, expr_data.type_id, argument_group))
 
            },
 
            Statement::Expression(stmt) => {
 
                // The expression has just been completely evaluated. Some
src/protocol/mod.rs
Show inline comments
 
@@ -94,20 +94,20 @@ impl ProtocolDescription {
 
        let definition_id = definition_id.unwrap();
 

	
 
        let ast_definition = &self.heap[definition_id];
 
        if !ast_definition.is_component() {
 
        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_component();
 
        if !ast_definition.poly_vars.is_empty() {
 
        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(definition_id, 0)] };
 
        let concrete_type = ConcreteType{ parts: vec![ConcreteTypePart::Component(ast_definition.this, 0)] };
 
        let mono_index = self.types.get_procedure_monomorph_type_id(&definition_id, &concrete_type.parts).unwrap();
 
        let mono_type = self.types.get_procedure_monomorph(mono_index);
 
        if mono_type.arg_types.len() != arguments.values.len() {
 
@@ -125,7 +125,7 @@ impl ProtocolDescription {
 

	
 
        // 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, mono_index, arguments));
 
        return Ok(Prompt::new(&self.types, &self.heap, ast_definition.this, mono_index, arguments));
 
    }
 

	
 
    fn lookup_module_root(&self, module_name: &[u8]) -> Option<RootId> {
src/protocol/parser/mod.rs
Show inline comments
 
@@ -324,8 +324,8 @@ impl Parser {
 
                types: &mut self.type_table,
 
                arch: &self.arch,
 
            };
 
            self.pass_rewriting.visit_module(&mut ctx);
 
            self.pass_stack_size.visit_module(&mut ctx);
 
            self.pass_rewriting.visit_module(&mut ctx)?;
 
            self.pass_stack_size.visit_module(&mut ctx)?;
 
        }
 

	
 
        // Write out desired information
 
@@ -356,7 +356,7 @@ fn insert_builtin_type(type_table: &mut TypeTable, parts: Vec<ConcreteTypePart>,
 
}
 

	
 
// Note: args and return type need to be a function because we need to know the function ID.
 
fn insert_builtin_function<T: Fn(FunctionDefinitionId) -> (Vec<(&'static str, ParserType)>, ParserType)> (
 
fn insert_builtin_function<T: Fn(ProcedureDefinitionId) -> (Vec<(&'static str, ParserType)>, ParserType)> (
 
    p: &mut Parser, func_name: &str, polymorphic: &[&str], arg_and_return_fn: T
 
) {
 
    let mut poly_vars = Vec::with_capacity(polymorphic.len());
 
@@ -365,21 +365,22 @@ fn insert_builtin_function<T: Fn(FunctionDefinitionId) -> (Vec<(&'static str, Pa
 
    }
 

	
 
    let func_ident_ref = p.string_pool.intern(func_name.as_bytes());
 
    let func_id = p.heap.alloc_function_definition(|this| FunctionDefinition{
 
    let procedure_id = p.heap.alloc_procedure_definition(|this| ProcedureDefinition {
 
        this,
 
        defined_in: RootId::new_invalid(),
 
        builtin: true,
 
        kind: ProcedureKind::Function,
 
        span: InputSpan::new(),
 
        identifier: Identifier{ span: InputSpan::new(), value: func_ident_ref.clone() },
 
        poly_vars,
 
        return_type: ParserType{ elements: Vec::new(), full_span: InputSpan::new() },
 
        return_type: None,
 
        parameters: Vec::new(),
 
        scope: ScopeId::new_invalid(),
 
        body: BlockStatementId::new_invalid(),
 
        num_expressions_in_body: -1,
 
    });
 

	
 
    let (arguments, return_type) = arg_and_return_fn(func_id);
 
    let (arguments, return_type) = arg_and_return_fn(procedure_id);
 

	
 
    let mut parameters = Vec::with_capacity(arguments.len());
 
    for (arg_name, arg_type) in arguments {
 
@@ -395,9 +396,9 @@ fn insert_builtin_function<T: Fn(FunctionDefinitionId) -> (Vec<(&'static str, Pa
 
        parameters.push(param_id);
 
    }
 

	
 
    let func = &mut p.heap[func_id];
 
    let func = &mut p.heap[procedure_id];
 
    func.parameters = parameters;
 
    func.return_type = return_type;
 
    func.return_type = Some(return_type);
 

	
 
    p.symbol_table.insert_symbol(SymbolScope::Global, Symbol{
 
        name: func_ident_ref,
 
@@ -408,7 +409,7 @@ fn insert_builtin_function<T: Fn(FunctionDefinitionId) -> (Vec<(&'static str, Pa
 
            identifier_span: InputSpan::new(),
 
            imported_at: None,
 
            class: DefinitionClass::Function,
 
            definition_id: func_id.upcast(),
 
            definition_id: procedure_id.upcast(),
 
        })
 
    }).unwrap();
 
}
 
\ No newline at end of file
src/protocol/parser/pass_definitions.rs
Show inline comments
 
@@ -284,8 +284,8 @@ impl PassDefinitions {
 
        let scope_id = ctx.heap.alloc_scope(|this| Scope::new(this, ScopeAssociation::Definition(definition_id)));
 

	
 
        // Assign everything in the preallocated AST node
 
        let function = ctx.heap[definition_id].as_function_mut();
 
        function.return_type = parser_type;
 
        let function = ctx.heap[definition_id].as_procedure_mut();
 
        function.return_type = Some(parser_type);
 
        function.parameters = parameters;
 
        function.scope = scope_id;
 
        function.body = body_id;
 
@@ -321,7 +321,8 @@ impl PassDefinitions {
 
        let scope_id = ctx.heap.alloc_scope(|this| Scope::new(this, ScopeAssociation::Definition(definition_id)));
 

	
 
        // Assign everything in the AST node
 
        let component = ctx.heap[definition_id].as_component_mut();
 
        let component = ctx.heap[definition_id].as_procedure_mut();
 
        debug_assert!(component.return_type.is_none());
 
        component.parameters = parameters;
 
        component.scope = scope_id;
 
        component.body = body_id;
 
@@ -758,7 +759,7 @@ impl PassDefinitions {
 
        if let Expression::Call(expression) = expression {
 
            // Allow both components and functions, as it makes more sense to
 
            // check their correct use in the validation and linking pass
 
            if expression.method == Method::UserComponent || expression.method == Method::UserFunction {
 
            if expression.method == Method::UserComponent || expression.method == Method::UserProcedure {
 
                call_id = expression.this;
 
                valid = true;
 
            }
 
@@ -1576,28 +1577,11 @@ impl PassDefinitions {
 
                                    unique_id_in_definition: -1,
 
                                }).upcast()
 
                            },
 
                            Definition::Component(_) => {
 
                                // Component instantiation
 
                                let func_span = parser_type.full_span;
 
                                let mut full_span = func_span;
 
                                let arguments = self.consume_expression_list(
 
                                    module, iter, ctx, Some(&mut full_span.end)
 
                                )?;
 

	
 
                                ctx.heap.alloc_call_expression(|this| CallExpression{
 
                                    this, func_span, full_span,
 
                                    parser_type,
 
                                    method: Method::UserComponent,
 
                                    arguments,
 
                                    definition: target_definition_id,
 
                                    parent: ExpressionParent::None,
 
                                    unique_id_in_definition: -1,
 
                                }).upcast()
 
                            },
 
                            Definition::Function(function_definition) => {
 
                            Definition::Procedure(proc_def) => {
 
                                // Check whether it is a builtin function
 
                                let method = if function_definition.builtin {
 
                                    match function_definition.identifier.value.as_bytes() {
 
                                let procedure_id = proc_def.this;
 
                                let method = if proc_def.builtin {
 
                                    match proc_def.identifier.value.as_bytes() {
 
                                        KW_FUNC_GET => Method::Get,
 
                                        KW_FUNC_PUT => Method::Put,
 
                                        KW_FUNC_FIRES => Method::Fires,
 
@@ -1607,8 +1591,10 @@ impl PassDefinitions {
 
                                        KW_FUNC_PRINT => Method::Print,
 
                                        _ => unreachable!(),
 
                                    }
 
                                } else if proc_def.kind == ProcedureKind::Function {
 
                                    Method::UserProcedure
 
                                } else {
 
                                    Method::UserFunction
 
                                    Method::UserComponent
 
                                };
 

	
 
                                // Function call: consume the arguments
 
@@ -1620,7 +1606,7 @@ impl PassDefinitions {
 

	
 
                                ctx.heap.alloc_call_expression(|this| CallExpression{
 
                                    this, func_span, full_span, parser_type, method, arguments,
 
                                    definition: target_definition_id,
 
                                    procedure: procedure_id,
 
                                    parent: ExpressionParent::None,
 
                                    unique_id_in_definition: -1,
 
                                }).upcast()
src/protocol/parser/pass_rewriting.rs
Show inline comments
 
@@ -45,17 +45,10 @@ impl Visitor for PassRewriting {
 

	
 
    // --- Visiting procedures
 

	
 
    fn visit_component_definition(&mut self, ctx: &mut Ctx, id: ComponentDefinitionId) -> VisitorResult {
 
        let def = &ctx.heap[id];
 
        let body_id = def.body;
 
        self.current_scope = def.scope;
 
        return self.visit_block_stmt(ctx, body_id);
 
    }
 

	
 
    fn visit_function_definition(&mut self, ctx: &mut Ctx, id: FunctionDefinitionId) -> VisitorResult {
 
        let def = &ctx.heap[id];
 
        let body_id = def.body;
 
        self.current_scope = def.scope;
 
    fn visit_procedure_definition(&mut self, ctx: &mut Ctx, id: ProcedureDefinitionId) -> VisitorResult {
 
        let definition = &ctx.heap[id];
 
        let body_id = definition.body;
 
        self.current_scope = definition.scope;
 
        return self.visit_block_stmt(ctx, body_id);
 
    }
 

	
 
@@ -162,7 +155,7 @@ impl Visitor for PassRewriting {
 
        let total_num_cases = select_stmt.cases.len();
 
        let mut total_num_ports = 0;
 
        let end_select_stmt_id = select_stmt.end_select;
 
        let end_select = &ctx.heap[end_select_stmt_id];
 
        let _end_select = &ctx.heap[end_select_stmt_id];
 

	
 
        // Put heap IDs into temporary buffers to handle borrowing rules
 
        let mut call_id_section = self.call_expr_buffer.start_section();
 
@@ -313,7 +306,7 @@ impl PassRewriting {
 
            },
 
            method,
 
            arguments,
 
            definition: DefinitionId::new_invalid(),
 
            procedure: ProcedureDefinitionId::new_invalid(),
 
            parent: ExpressionParent::None,
 
            unique_id_in_definition: -1,
 
        });
 
@@ -376,7 +369,7 @@ fn create_ast_call_expr(ctx: &mut Ctx, method: Method, buffer: &mut ScopedBuffer
 
        },
 
        method,
 
        arguments,
 
        definition: DefinitionId::new_invalid(),
 
        procedure: ProcedureDefinitionId::new_invalid(),
 
        parent: ExpressionParent::None,
 
        unique_id_in_definition: -1,
 
    });
src/protocol/parser/pass_stack_size.rs
Show inline comments
 
@@ -43,20 +43,12 @@ impl Visitor for PassStackSize {
 
        return Ok(())
 
    }
 

	
 
    fn visit_function_definition(&mut self, ctx: &mut Ctx, id: FunctionDefinitionId) -> VisitorResult {
 
    fn visit_procedure_definition(&mut self, ctx: &mut Ctx, id: ProcedureDefinitionId) -> VisitorResult {
 
        let definition = &ctx.heap[id];
 
        let scope_id = definition.scope;
 

	
 
        self.visit_scope_and_assign_local_ids(ctx, scope_id, 0);
 
        return Ok(())
 
    }
 

	
 
    fn visit_component_definition(&mut self, ctx: &mut Ctx, id: ComponentDefinitionId) -> VisitorResult {
 
        let definition = &ctx.heap[id];
 
        let scope_id = definition.scope;
 

	
 
        self.visit_scope_and_assign_local_ids(ctx, scope_id, 0);
 
        return Ok(())
 
        return Ok(());
 
    }
 
}
 

	
src/protocol/parser/pass_symbols.rs
Show inline comments
 
@@ -230,23 +230,23 @@ impl PassSymbols {
 
                ast_definition_id = union_def_id.upcast()
 
            },
 
            KW_FUNCTION => {
 
                let func_def_id = ctx.heap.alloc_function_definition(|this| {
 
                    FunctionDefinition::new_empty(this, module.root_id, definition_span, identifier, poly_vars)
 
                let proc_def_id = ctx.heap.alloc_procedure_definition(|this| {
 
                    ProcedureDefinition::new_empty(this, module.root_id, definition_span, ProcedureKind::Function, identifier, poly_vars)
 
                });
 
                definition_class = DefinitionClass::Function;
 
                ast_definition_id = func_def_id.upcast();
 
                ast_definition_id = proc_def_id.upcast();
 
            },
 
            KW_PRIMITIVE | KW_COMPOSITE => {
 
                let component_variant = if kw_text == KW_PRIMITIVE {
 
                    ComponentVariant::Primitive
 
                let procedure_kind = if kw_text == KW_PRIMITIVE {
 
                    ProcedureKind::Primitive
 
                } else {
 
                    ComponentVariant::Composite
 
                    ProcedureKind::Composite
 
                };
 
                let comp_def_id = ctx.heap.alloc_component_definition(|this| {
 
                    ComponentDefinition::new_empty(this, module.root_id, definition_span, component_variant, identifier, poly_vars)
 
                let proc_def_id = ctx.heap.alloc_procedure_definition(|this| {
 
                    ProcedureDefinition::new_empty(this, module.root_id, definition_span, procedure_kind, identifier, poly_vars)
 
                });
 
                definition_class = DefinitionClass::Component;
 
                ast_definition_id = comp_def_id.upcast();
 
                ast_definition_id = proc_def_id.upcast();
 
            },
 
            _ => unreachable!("encountered keyword '{}' in definition range", String::from_utf8_lossy(kw_text)),
 
        }
src/protocol/parser/pass_typing.rs
Show inline comments
 
@@ -810,20 +810,6 @@ type InferNodeIndex = usize;
 
type PolyDataIndex = isize;
 
type VarDataIndex = usize;
 

	
 
enum DefinitionType{
 
    Component(ComponentDefinitionId),
 
    Function(FunctionDefinitionId),
 
}
 

	
 
impl DefinitionType {
 
    fn definition_id(&self) -> DefinitionId {
 
        match self {
 
            DefinitionType::Component(v) => v.upcast(),
 
            DefinitionType::Function(v) => v.upcast(),
 
        }
 
    }
 
}
 

	
 
pub(crate) struct ResolveQueueElement {
 
    // Note that using the `definition_id` and the `monomorph_idx` one may
 
    // query the type table for the full procedure type, thereby retrieving
 
@@ -1014,7 +1000,8 @@ struct InferenceRuleVariableExpr {
 
pub(crate) struct PassTyping {
 
    // Current definition we're typechecking.
 
    reserved_type_id: TypeId,
 
    definition_type: DefinitionType,
 
    procedure_id: ProcedureDefinitionId,
 
    procedure_kind: ProcedureKind,
 
    poly_vars: Vec<ConcreteType>,
 
    // Temporary variables during construction of inference rulesr
 
    parent_index: Option<InferNodeIndex>,
 
@@ -1092,7 +1079,8 @@ impl PassTyping {
 
    pub(crate) fn new() -> Self {
 
        PassTyping {
 
            reserved_type_id: TypeId::new_invalid(),
 
            definition_type: DefinitionType::Function(FunctionDefinitionId::new_invalid()),
 
            procedure_id: ProcedureDefinitionId::new_invalid(),
 
            procedure_kind: ProcedureKind::Function,
 
            poly_vars: Vec::new(),
 
            parent_index: None,
 
            var_buffer: ScopedBuffer::with_capacity(BUFFER_INIT_CAP_LARGE),
 
@@ -1116,20 +1104,17 @@ impl PassTyping {
 
            let definition = &ctx.heap[*definition_id];
 

	
 
            let first_concrete_part = match definition {
 
                Definition::Function(definition) => {
 
                Definition::Procedure(definition) => {
 
                    if definition.poly_vars.is_empty() {
 
                        Some(ConcreteTypePart::Function(*definition_id, 0))
 
                        if definition.kind == ProcedureKind::Function {
 
                            Some(ConcreteTypePart::Function(definition.this, 0))
 
                        } else {
 
                            Some(ConcreteTypePart::Component(definition.this, 0))
 
                        }
 
                    } else {
 
                        None
 
                    }
 
                }
 
                Definition::Component(definition) => {
 
                    if definition.poly_vars.is_empty() {
 
                        Some(ConcreteTypePart::Component(*definition_id, 0))
 
                    } else {
 
                        None
 
                    }
 
                },
 
                Definition::Enum(_) | Definition::Struct(_) | Definition::Union(_) => None,
 
            };
 

	
 
@@ -1172,7 +1157,8 @@ impl PassTyping {
 

	
 
    fn reset(&mut self) {
 
        self.reserved_type_id = TypeId::new_invalid();
 
        self.definition_type = DefinitionType::Function(FunctionDefinitionId::new_invalid());
 
        self.procedure_id = ProcedureDefinitionId::new_invalid();
 
        self.procedure_kind = ProcedureKind::Function;
 
        self.poly_vars.clear();
 
        self.parent_index = None;
 

	
 
@@ -1201,60 +1187,19 @@ impl PassTyping {
 
    fn visit_struct_definition(&mut self, _: &mut Ctx, _: StructDefinitionId) -> VisitorResult { return Ok(()) }
 
    fn visit_union_definition(&mut self, _: &mut Ctx, _: UnionDefinitionId) -> VisitorResult { return Ok(()) }
 

	
 
    fn visit_component_definition(&mut self, ctx: &mut Ctx, id: ComponentDefinitionId) -> VisitorResult {
 
        self.definition_type = DefinitionType::Component(id);
 

	
 
        let comp_def = &ctx.heap[id];
 
        debug_assert_eq!(comp_def.poly_vars.len(), self.poly_vars.len(), "component polyvars do not match imposed polyvars");
 

	
 
        debug_log!("{}", "-".repeat(50));
 
        debug_log!("Visiting component '{}': {}", comp_def.identifier.value.as_str(), id.0.index);
 
        debug_log!("{}", "-".repeat(50));
 

	
 
        // Visit parameters
 
        let section = self.var_buffer.start_section_initialized(comp_def.parameters.as_slice());
 
        for param_id in section.iter_copied() {
 
            let param = &ctx.heap[param_id];
 
            let var_type = self.determine_inference_type_from_parser_type_elements(&param.parser_type.elements, true);
 
            debug_assert!(var_type.is_done, "expected component arguments to be concrete types");
 
            self.var_data.push(VarData{
 
                var_id: param_id,
 
                var_type,
 
                used_at: Vec::new(),
 
                linked_var: None
 
            });
 
        }
 
        section.forget();
 

	
 
        // Visit the body and all of its expressions
 
        let body_stmt_id = ctx.heap[id].body;
 
        self.parent_index = None;
 
        self.visit_block_stmt(ctx, body_stmt_id)
 
    }
 

	
 
    fn visit_function_definition(&mut self, ctx: &mut Ctx, id: FunctionDefinitionId) -> VisitorResult {
 
        self.definition_type = DefinitionType::Function(id);
 
    fn visit_procedure_definition(&mut self, ctx: &mut Ctx, id: ProcedureDefinitionId) -> VisitorResult {
 
        let procedure_def = &ctx.heap[id];
 

	
 
        let func_def = &ctx.heap[id];
 
        debug_assert_eq!(func_def.poly_vars.len(), self.poly_vars.len(), "function polyvars do not match imposed polyvars");
 
        self.procedure_id = id;
 
        self.procedure_kind = procedure_def.kind;
 
        let body_id = procedure_def.body;
 

	
 
        debug_log!("{}", "-".repeat(50));
 
        debug_log!("Visiting function '{}': {}", func_def.identifier.value.as_str(), id.0.index);
 
        if debug_log_enabled!() {
 
            debug_log!("Polymorphic variables:");
 
            for (_idx, poly_var) in self.poly_vars.iter().enumerate() {
 
                let mut infer_type_parts = Vec::new();
 
                Self::determine_inference_type_from_concrete_type(
 
                    &mut infer_type_parts, &poly_var.parts
 
                );
 
                let _infer_type = InferenceType::new(false, true, infer_type_parts);
 
                debug_log!(" - [{:03}] {:?}", _idx, _infer_type.display_name(&ctx.heap));
 
            }
 
        }
 
        debug_log!("Visiting procedure: '{}' (id: {}, kind: {:?})", procedure_def.identifier.value.as_str(), id.0.index, procedure_def.kind);
 
        debug_log!("{}", "-".repeat(50));
 

	
 
        // Visit parameters
 
        let section = self.var_buffer.start_section_initialized(func_def.parameters.as_slice());
 
        let section = self.var_buffer.start_section_initialized(procedure_def.parameters.as_slice());
 
        for param_id in section.iter_copied() {
 
            let param = &ctx.heap[param_id];
 
            let var_type = self.determine_inference_type_from_parser_type_elements(&param.parser_type.elements, true);
 
@@ -1269,9 +1214,8 @@ impl PassTyping {
 
        section.forget();
 

	
 
        // Visit all of the expressions within the body
 
        let body_stmt_id = ctx.heap[id].body;
 
        self.parent_index = None;
 
        self.visit_block_stmt(ctx, body_stmt_id)
 
        return self.visit_block_stmt(ctx, body_id);
 
    }
 

	
 
    // Statements
 
@@ -2021,7 +1965,7 @@ impl PassTyping {
 
                if !poly_type.is_done {
 
                    let expr = &ctx.heap[expr_id];
 
                    let definition = match expr {
 
                        Expression::Call(expr) => expr.definition,
 
                        Expression::Call(expr) => expr.procedure.upcast(),
 
                        Expression::Literal(expr) => match &expr.value {
 
                            Literal::Enum(lit) => lit.definition,
 
                            Literal::Union(lit) => lit.definition,
 
@@ -2072,16 +2016,16 @@ impl PassTyping {
 
                Expression::Call(expr) => {
 
                    // Check if it is not a builtin function. If not, then
 
                    // construct the first part of the concrete type.
 
                    let first_concrete_part = if expr.method == Method::UserFunction {
 
                        ConcreteTypePart::Function(expr.definition, poly_data.poly_vars.len() as u32)
 
                    let first_concrete_part = if expr.method == Method::UserProcedure {
 
                        ConcreteTypePart::Function(expr.procedure, poly_data.poly_vars.len() as u32)
 
                    } else if expr.method == Method::UserComponent {
 
                        ConcreteTypePart::Component(expr.definition, poly_data.poly_vars.len() as u32)
 
                        ConcreteTypePart::Component(expr.procedure, poly_data.poly_vars.len() as u32)
 
                    } else {
 
                        // Builtin function
 
                        continue;
 
                    };
 

	
 
                    let definition_id = expr.definition;
 
                    let definition_id = expr.procedure.upcast();
 
                    let concrete_type = inference_type_to_concrete_type(
 
                        ctx, infer_expr.expr_id, &poly_data.poly_vars, first_concrete_part
 
                    )?;
 
@@ -2128,16 +2072,7 @@ impl PassTyping {
 

	
 
        // Every expression checked, and new monomorphs are queued. Transfer the
 
        // expression information to the type table.
 
        let procedure_arguments = match &self.definition_type {
 
            DefinitionType::Component(id) => {
 
                let definition = &ctx.heap[*id];
 
                &definition.parameters
 
            },
 
            DefinitionType::Function(id) => {
 
                let definition = &ctx.heap[*id];
 
                &definition.parameters
 
            },
 
        };
 
        let procedure_arguments = &ctx.heap[self.procedure_id].parameters;
 

	
 
        let target = ctx.types.get_procedure_monomorph_mut(self.reserved_type_id);
 
        debug_assert!(target.arg_types.is_empty()); // makes sure we never queue a procedure's type inferencing twice
 
@@ -3022,7 +2957,10 @@ impl PassTyping {
 
        while part_index < expr_type.parts.len() {
 
            let part = &expr_type.parts[part_index];
 

	
 
            if part.is_marker() { continue; }
 
            if part.is_marker() {
 
                part_index += 1;
 
                continue;
 
            }
 
            if !part.is_concrete() { break; }
 

	
 
            if *part == InferenceTypePart::String {
 
@@ -3218,7 +3156,7 @@ impl PassTyping {
 
    /// type, then we should also progress the associated expression, hence the
 
    /// `associated_node_index`.
 
    fn apply_polydata_polyvar_constraint(
 
        &mut self, ctx: &Ctx,
 
        &mut self, _ctx: &Ctx,
 
        outer_node_index: InferNodeIndex, poly_data_type_index: PolyDataTypeIndex,
 
        associated_node_index: InferNodeIndex, poly_progress_section: &ScopedSection<u32>
 
    ) -> bool {
 
@@ -3441,16 +3379,12 @@ impl PassTyping {
 
            EP::If(_) | EP::While(_) =>
 
                // Must be a boolean
 
                InferenceType::new(false, true, vec![ITP::Bool]),
 
            EP::Return(_) =>
 
            EP::Return(_) => {
 
                // Must match the return type of the function
 
                if let DefinitionType::Function(func_id) = self.definition_type {
 
                    let returned = &ctx.heap[func_id].return_type;
 
                    self.determine_inference_type_from_parser_type_elements(&returned.elements, true)
 
                } else {
 
                    // Cannot happen: definition always set upon body traversal
 
                    // and "return" calls in components are illegal.
 
                    unreachable!();
 
                },
 
                debug_assert_eq!(self.procedure_kind, ProcedureKind::Function);
 
                let returned = &ctx.heap[self.procedure_id].return_type.as_ref().unwrap();
 
                self.determine_inference_type_from_parser_type_elements(&returned.elements, true)
 
            },
 
            EP::New(_) =>
 
                // Must be a component call, which we assign a "Void" return
 
                // type
 
@@ -3493,33 +3427,25 @@ impl PassTyping {
 
        }
 

	
 
        // Handle the arguments and return types
 
        let definition = &ctx.heap[call.definition];
 
        let (parameters, returned) = match definition {
 
            Definition::Component(definition) => {
 
                debug_assert_eq!(poly_args.len(), definition.poly_vars.len());
 
                (&definition.parameters, None)
 
            },
 
            Definition::Function(definition) => {
 
                debug_assert_eq!(poly_args.len(), definition.poly_vars.len());
 
                (&definition.parameters, Some(&definition.return_type))
 
            },
 
            Definition::Struct(_) | Definition::Enum(_) | Definition::Union(_) => {
 
                unreachable!("insert_initial_call_polymorph data for non-procedure type");
 
            },
 
        };
 
        let definition = &ctx.heap[call.procedure];
 
        debug_assert_eq!(poly_args.len(), definition.poly_vars.len());
 

	
 
        let mut parameter_types = Vec::with_capacity(parameters.len());
 
        for parameter_id in parameters.clone().into_iter() { // TODO: @Performance @Now
 
        let mut parameter_types = Vec::with_capacity(definition.parameters.len());
 
        let parameter_section = self.var_buffer.start_section_initialized(&definition.parameters);
 
        for parameter_id in parameter_section.iter_copied() {
 
            let param = &ctx.heap[parameter_id];
 
            parameter_types.push(self.determine_inference_type_from_parser_type_elements(&param.parser_type.elements, false));
 
        }
 
        parameter_section.forget();
 

	
 
        let return_type = match returned {
 
        let return_type = match &definition.return_type {
 
            None => {
 
                // Component, so returns a "Void"
 
                debug_assert_ne!(definition.kind, ProcedureKind::Function);
 
                InferenceType::new(false, true, vec![InferenceTypePart::Void])
 
            },
 
            Some(returned) => {
 
                debug_assert_eq!(definition.kind, ProcedureKind::Function);
 
                self.determine_inference_type_from_parser_type_elements(&returned.elements, false)
 
            }
 
        };
 
@@ -3527,7 +3453,7 @@ impl PassTyping {
 
        let extra_data_idx = self.poly_data.len() as PolyDataIndex;
 
        self.poly_data.push(PolyData {
 
            first_rule_application: true,
 
            definition_id: call.definition,
 
            definition_id: call.procedure.upcast(),
 
            poly_vars: poly_args,
 
            expr_types: PolyDataTypes {
 
                associated: parameter_types,
 
@@ -3825,7 +3751,7 @@ impl PassTyping {
 
                    if use_definitions_known_poly_args {
 
                        // Refers to polymorphic argument on procedure we're currently processing.
 
                        // This argument is already known.
 
                        debug_assert_eq!(*belongs_to_definition, self.definition_type.definition_id());
 
                        debug_assert_eq!(*belongs_to_definition, self.procedure_id.upcast());
 
                        debug_assert!((poly_arg_idx as usize) < self.poly_vars.len());
 

	
 
                        Self::determine_inference_type_from_concrete_type(
src/protocol/parser/pass_validation_linking.rs
Show inline comments
 
@@ -50,26 +50,6 @@ use super::visitor::{
 
};
 
use crate::protocol::parser::ModuleCompilationPhase;
 

	
 
#[derive(PartialEq, Eq)]
 
enum DefinitionType {
 
    Primitive(ComponentDefinitionId),
 
    Composite(ComponentDefinitionId),
 
    Function(FunctionDefinitionId)
 
}
 

	
 
impl DefinitionType {
 
    fn is_primitive(&self) -> bool { if let Self::Primitive(_) = self { true } else { false } }
 
    fn is_composite(&self) -> bool { if let Self::Composite(_) = self { true } else { false } }
 
    fn is_function(&self) -> bool { if let Self::Function(_) = self { true } else { false } }
 
    fn definition_id(&self) -> DefinitionId {
 
        match self {
 
            DefinitionType::Primitive(v) => v.upcast(),
 
            DefinitionType::Composite(v) => v.upcast(),
 
            DefinitionType::Function(v) => v.upcast(),
 
        }
 
    }
 
}
 

	
 
struct ControlFlowStatement {
 
    in_sync: SynchronousStatementId,
 
    in_while: WhileStatementId,
 
@@ -103,7 +83,8 @@ pub(crate) struct PassValidationLinking {
 
    // Traversal state, current scope (which can be used to find the parent
 
    // scope) and the definition variant we are considering.
 
    cur_scope: ScopeId,
 
    def_type: DefinitionType,
 
    proc_id: ProcedureDefinitionId,
 
    proc_kind: ProcedureKind,
 
    // "Trailing" traversal state, set be child/prev stmt/expr used by next one
 
    prev_stmt: StatementId,
 
    expr_parent: ExpressionParent,
 
@@ -139,7 +120,8 @@ impl PassValidationLinking {
 
            cur_scope: ScopeId::new_invalid(),
 
            prev_stmt: StatementId::new_invalid(),
 
            expr_parent: ExpressionParent::None,
 
            def_type: DefinitionType::Function(FunctionDefinitionId::new_invalid()),
 
            proc_id: ProcedureDefinitionId::new_invalid(),
 
            proc_kind: ProcedureKind::Function,
 
            must_be_assignable: None,
 
            relative_pos_in_parent: 0,
 
            next_expr_index: 0,
 
@@ -160,7 +142,8 @@ impl PassValidationLinking {
 
        self.in_binding_expr = BindingExpressionId::new_invalid();
 
        self.in_binding_expr_lhs = false;
 
        self.cur_scope = ScopeId::new_invalid();
 
        self.def_type = DefinitionType::Function(FunctionDefinitionId::new_invalid());
 
        self.proc_id = ProcedureDefinitionId::new_invalid();
 
        self.proc_kind = ProcedureKind::Function;
 
        self.prev_stmt = StatementId::new_invalid();
 
        self.expr_parent = ExpressionParent::None;
 
        self.must_be_assignable = None;
 
@@ -206,56 +189,17 @@ impl Visitor for PassValidationLinking {
 
    // Definition visitors
 
    //--------------------------------------------------------------------------
 

	
 
    fn visit_component_definition(&mut self, ctx: &mut Ctx, id: ComponentDefinitionId) -> VisitorResult {
 
    fn visit_procedure_definition(&mut self, ctx: &mut Ctx, id: ProcedureDefinitionId) -> VisitorResult {
 
        self.reset_state();
 

	
 
        let definition = &ctx.heap[id];
 
        self.def_type = match &definition.variant {
 
            ComponentVariant::Primitive => DefinitionType::Primitive(id),
 
            ComponentVariant::Composite => DefinitionType::Composite(id),
 
        };
 
        self.expr_parent = ExpressionParent::None;
 

	
 
        // Visit parameters and assign a unique scope ID
 
        let definition_scope_id = definition.scope;
 
        let old_scope = self.push_scope(ctx, true, definition_scope_id);
 

	
 
        let definition = &ctx.heap[id];
 
        let body_id = definition.body;
 
        let section = self.variable_buffer.start_section_initialized(&definition.parameters);
 
        for variable_idx in 0..section.len() {
 
            let variable_id = section[variable_idx];
 
            self.checked_at_single_scope_add_local(ctx, self.cur_scope, -1, variable_id)?;
 
        }
 
        self.relative_pos_in_parent = section.len() as i32;
 

	
 
        section.forget();
 

	
 
        // Visit statements in component body
 
        self.visit_block_stmt(ctx, body_id)?;
 
        self.pop_scope(old_scope);
 

	
 
        // Assign total number of expressions and assign an in-block unique ID
 
        // to each of the locals in the procedure.
 
        let definition = &mut ctx.heap[id];
 
        definition.num_expressions_in_body = self.next_expr_index;
 

	
 
        self.resolve_pending_control_flow_targets(ctx)?;
 

	
 
        Ok(())
 
    }
 

	
 
    fn visit_function_definition(&mut self, ctx: &mut Ctx, id: FunctionDefinitionId) -> VisitorResult {
 
        self.reset_state();
 

	
 
        // Set internal statement indices
 
        self.def_type = DefinitionType::Function(id);
 
        self.proc_id = id;
 
        self.proc_kind = definition.kind;
 
        self.expr_parent = ExpressionParent::None;
 

	
 
        // Visit parameters and assign a unique scope ID
 
        let definition = &ctx.heap[id];
 
        let definition_scope_id = definition.scope;
 
        let old_scope = self.push_scope(ctx, true, definition_scope_id);
 
        // Visit parameters
 
        let scope_id = definition.scope;
 
        let old_scope = self.push_scope(ctx, true, scope_id);
 

	
 
        let definition = &ctx.heap[id];
 
        let body_id = definition.body;
 
@@ -460,7 +404,7 @@ impl Visitor for PassValidationLinking {
 
            ));
 
        }
 

	
 
        if !self.def_type.is_primitive() {
 
        if self.proc_kind != ProcedureKind::Primitive {
 
            return Err(ParseError::new_error_str_at_span(
 
                &ctx.module().source, cur_sync_span,
 
                "synchronous statements may only be used in primitive components"
 
@@ -532,7 +476,7 @@ impl Visitor for PassValidationLinking {
 
            ));
 
        }
 

	
 
        if !self.def_type.is_primitive() {
 
        if self.proc_kind != ProcedureKind::Primitive {
 
            return Err(ParseError::new_error_str_at_span(
 
                &ctx.module().source, select_stmt.span,
 
                "select statements may only be used in primitive components"
 
@@ -587,7 +531,7 @@ impl Visitor for PassValidationLinking {
 
    fn visit_return_stmt(&mut self, ctx: &mut Ctx, id: ReturnStatementId) -> VisitorResult {
 
        // Check if "return" occurs within a function
 
        let stmt = &ctx.heap[id];
 
        if !self.def_type.is_function() {
 
        if self.proc_kind != ProcedureKind::Function {
 
            return Err(ParseError::new_error_str_at_span(
 
                &ctx.module().source, stmt.span,
 
                "return statements may only appear in function bodies"
 
@@ -619,7 +563,7 @@ impl Visitor for PassValidationLinking {
 

	
 
    fn visit_new_stmt(&mut self, ctx: &mut Ctx, id: NewStatementId) -> VisitorResult {
 
        // Make sure the new statement occurs inside a composite component
 
        if !self.def_type.is_composite() {
 
        if self.proc_kind != ProcedureKind::Composite {
 
            let new_stmt = &ctx.heap[id];
 
            return Err(ParseError::new_error_str_at_span(
 
                &ctx.module().source, new_stmt.span,
 
@@ -1228,7 +1172,7 @@ impl Visitor for PassValidationLinking {
 
            Method::Assert => {
 
                expecting_wrapping_sync_stmt = true;
 
                expecting_no_select_stmt = true;
 
                if self.def_type.is_function() {
 
                if self.proc_kind == ProcedureKind::Function {
 
                    let call_span = call_expr.func_span;
 
                    return Err(ParseError::new_error_str_at_span(
 
                        &ctx.module().source, call_span,
 
@@ -1240,7 +1184,7 @@ impl Visitor for PassValidationLinking {
 
            Method::SelectStart
 
            | Method::SelectRegisterCasePort
 
            | Method::SelectWait => unreachable!(), // not usable by programmer directly
 
            Method::UserFunction => {},
 
            Method::UserProcedure => {}
 
            Method::UserComponent => {
 
                expecting_wrapping_new_stmt = true;
 
            },
 
@@ -1255,7 +1199,7 @@ impl Visitor for PassValidationLinking {
 
            return (span, name);
 
        }
 
        if expecting_primitive_def {
 
            if !self.def_type.is_primitive() {
 
            if self.proc_kind != ProcedureKind::Primitive {
 
                let (call_span, func_name) = get_span_and_name(ctx, id);
 
                return Err(ParseError::new_error_at_span(
 
                    &ctx.module().source, call_span,
 
@@ -1303,11 +1247,10 @@ impl Visitor for PassValidationLinking {
 
        }
 

	
 
        // Check the number of arguments
 
        let call_definition = ctx.types.get_base_definition(&call_expr.definition).unwrap();
 
        let call_definition = ctx.types.get_base_definition(&call_expr.procedure.upcast()).unwrap();
 
        let num_expected_args = match &call_definition.definition {
 
            DefinedTypeVariant::Function(definition) => definition.arguments.len(),
 
            DefinedTypeVariant::Component(definition) => definition.arguments.len(),
 
            v => unreachable!("encountered {} type in call expression", v.type_class()),
 
            DefinedTypeVariant::Procedure(definition) => definition.arguments.len(),
 
            _ => unreachable!(),
 
        };
 

	
 
        let num_provided_args = call_expr.arguments.len();
 
@@ -1595,7 +1538,7 @@ impl PassValidationLinking {
 
    ) -> Result<(), ParseError> {
 
        // Check the symbol table for conflicts
 
        {
 
            let cur_scope = SymbolScope::Definition(self.def_type.definition_id());
 
            let cur_scope = SymbolScope::Definition(self.proc_id.upcast());
 
            let ident = &ctx.heap[new_variable_id].identifier;
 
            if let Some(symbol) = ctx.symbols.get_symbol_by_name(cur_scope, &ident.value.as_bytes()) {
 
                return Err(ParseError::new_error_str_at_span(
src/protocol/parser/type_table.rs
Show inline comments
 
@@ -36,7 +36,6 @@
 
 * layout.
 
 */
 

	
 
use std::fmt::{Formatter, Result as FmtResult};
 
use std::collections::HashMap;
 
use std::hash::{Hash, Hasher};
 

	
 
@@ -49,40 +48,6 @@ use crate::protocol::parser::*;
 
// Defined Types
 
//------------------------------------------------------------------------------
 

	
 
#[derive(Copy, Clone, PartialEq, Eq)]
 
pub enum TypeClass {
 
    Enum,
 
    Union,
 
    Struct,
 
    Function,
 
    Component
 
}
 

	
 
impl TypeClass {
 
    pub(crate) fn display_name(&self) -> &'static str {
 
        match self {
 
            TypeClass::Enum => "enum",
 
            TypeClass::Union => "union",
 
            TypeClass::Struct => "struct",
 
            TypeClass::Function => "function",
 
            TypeClass::Component => "component",
 
        }
 
    }
 

	
 
    pub(crate) fn is_data_type(&self) -> bool {
 
        match self {
 
            TypeClass::Enum | TypeClass::Union | TypeClass::Struct => true,
 
            TypeClass::Function | TypeClass::Component => false,
 
        }
 
    }
 
}
 

	
 
impl std::fmt::Display for TypeClass {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
 
        write!(f, "{}", self.display_name())
 
    }
 
}
 

	
 
/// Struct wrapping around a potentially polymorphic type. If the type does not
 
/// have any polymorphic arguments then it will not have any monomorphs and
 
/// `is_polymorph` will be set to `false`. A type with polymorphic arguments
 
@@ -102,39 +67,37 @@ pub enum DefinedTypeVariant {
 
    Enum(EnumType),
 
    Union(UnionType),
 
    Struct(StructType),
 
    Function(FunctionType),
 
    Component(ComponentType)
 
    Procedure(ProcedureType),
 
}
 

	
 
impl DefinedTypeVariant {
 
    pub(crate) fn type_class(&self) -> TypeClass {
 
    pub(crate) fn is_data_type(&self) -> bool {
 
        use DefinedTypeVariant as DTV;
 

	
 
        match self {
 
            DefinedTypeVariant::Enum(_) => TypeClass::Enum,
 
            DefinedTypeVariant::Union(_) => TypeClass::Union,
 
            DefinedTypeVariant::Struct(_) => TypeClass::Struct,
 
            DefinedTypeVariant::Function(_) => TypeClass::Function,
 
            DefinedTypeVariant::Component(_) => TypeClass::Component
 
            DTV::Struct(_) | DTV::Enum(_) | DTV::Union(_) => return true,
 
            DTV::Procedure(_) => return false,
 
        }
 
    }
 

	
 
    pub(crate) fn as_struct(&self) -> &StructType {
 
        match self {
 
            DefinedTypeVariant::Struct(v) => v,
 
            _ => unreachable!("Cannot convert {} to struct variant", self.type_class())
 
            _ => unreachable!()
 
        }
 
    }
 

	
 
    pub(crate) fn as_enum(&self) -> &EnumType {
 
        match self {
 
            DefinedTypeVariant::Enum(v) => v,
 
            _ => unreachable!("Cannot convert {} to enum variant", self.type_class())
 
            _ => unreachable!()
 
        }
 
    }
 

	
 
    pub(crate) fn as_union(&self) -> &UnionType {
 
        match self {
 
            DefinedTypeVariant::Union(v) => v,
 
            _ => unreachable!("Cannot convert {} to union variant", self.type_class())
 
            _ => unreachable!()
 
        }
 
    }
 
}
 
@@ -197,19 +160,14 @@ pub struct StructField {
 
    pub parser_type: ParserType,
 
}
 

	
 
/// `FunctionType` is what you expect it to be: a particular function's
 
/// signature.
 
pub struct FunctionType {
 
    pub return_type: ParserType,
 
    pub arguments: Vec<FunctionArgument>,
 
}
 

	
 
pub struct ComponentType {
 
    pub variant: ComponentVariant,
 
    pub arguments: Vec<FunctionArgument>,
 
/// `ProcedureType` is the signature of a procedure/component
 
pub struct ProcedureType {
 
    pub kind: ProcedureKind,
 
    pub return_type: Option<ParserType>,
 
    pub arguments: Vec<ProcedureArgument>,
 
}
 

	
 
pub struct FunctionArgument {
 
pub struct ProcedureArgument {
 
    identifier: Identifier,
 
    parser_type: ParserType,
 
}
 
@@ -674,8 +632,7 @@ impl TypeTable {
 
                Definition::Enum(_) => self.build_base_enum_definition(modules, ctx, definition_id)?,
 
                Definition::Union(_) => self.build_base_union_definition(modules, ctx, definition_id)?,
 
                Definition::Struct(_) => self.build_base_struct_definition(modules, ctx, definition_id)?,
 
                Definition::Function(_) => self.build_base_function_definition(modules, ctx, definition_id)?,
 
                Definition::Component(_) => self.build_base_component_definition(modules, ctx, definition_id)?,
 
                Definition::Procedure(_) => self.build_base_procedure_definition(modules, ctx, definition_id)?,
 
            }
 
        }
 

	
 
@@ -691,7 +648,7 @@ impl TypeTable {
 
            let definition_id = ctx.heap.definitions.get_id(definition_idx);
 
            let poly_type = self.definition_lookup.get(&definition_id).unwrap();
 

	
 
            if !poly_type.definition.type_class().is_data_type() || !poly_type.poly_vars.is_empty() {
 
            if !poly_type.definition.is_data_type() || !poly_type.poly_vars.is_empty() {
 
                continue;
 
            }
 

	
 
@@ -1000,73 +957,27 @@ impl TypeTable {
 
        return Ok(())
 
    }
 

	
 
    /// Builds base function type.
 
    fn build_base_function_definition(&mut self, modules: &[Module], ctx: &mut PassCtx, definition_id: DefinitionId) -> Result<(), ParseError> {
 
    /// Builds base procedure type.
 
    fn build_base_procedure_definition(&mut self, modules: &[Module], ctx: &mut PassCtx, definition_id: DefinitionId) -> Result<(), ParseError> {
 
        debug_assert!(!self.definition_lookup.contains_key(&definition_id), "base function already built");
 
        let definition = ctx.heap[definition_id].as_function();
 
        let definition = ctx.heap[definition_id].as_procedure();
 
        let root_id = definition.defined_in;
 

	
 
        // Check and construct return types and argument types.
 
        Self::check_member_parser_type(
 
            modules, ctx, root_id, &definition.return_type, definition.builtin
 
        )?;
 

	
 
        let mut arguments = Vec::with_capacity(definition.parameters.len());
 
        for parameter_id in &definition.parameters {
 
            let parameter = &ctx.heap[*parameter_id];
 
        if let Some(return_type) = &definition.return_type {
 
            Self::check_member_parser_type(
 
                modules, ctx, root_id, &parameter.parser_type, definition.builtin
 
                modules, ctx, root_id, return_type, definition.builtin
 
            )?;
 

	
 
            arguments.push(FunctionArgument{
 
                identifier: parameter.identifier.clone(),
 
                parser_type: parameter.parser_type.clone(),
 
            });
 
        }
 

	
 
        // Check conflict of identifiers
 
        Self::check_identifier_collision(
 
            modules, root_id, &arguments, |arg| &arg.identifier, "function argument"
 
        )?;
 
        Self::check_poly_args_collision(modules, ctx, root_id, &definition.poly_vars)?;
 

	
 
        // Construct internal representation of function type
 
        let mut poly_vars = Self::create_polymorphic_variables(&definition.poly_vars);
 

	
 
        Self::mark_used_polymorphic_variables(&mut poly_vars, &definition.return_type);
 
        for argument in &arguments {
 
            Self::mark_used_polymorphic_variables(&mut poly_vars, &argument.parser_type);
 
        }
 

	
 
        let is_polymorph = poly_vars.iter().any(|arg| arg.is_in_use);
 

	
 
        self.definition_lookup.insert(definition_id, DefinedType{
 
            ast_root: root_id,
 
            ast_definition: definition_id,
 
            definition: DefinedTypeVariant::Function(FunctionType{ return_type: definition.return_type.clone(), arguments }),
 
            poly_vars,
 
            is_polymorph
 
        });
 

	
 
        return Ok(());
 
    }
 

	
 
    /// Builds base component type.
 
    fn build_base_component_definition(&mut self, modules: &[Module], ctx: &mut PassCtx, definition_id: DefinitionId) -> Result<(), ParseError> {
 
        debug_assert!(!self.definition_lookup.contains_key(&definition_id), "base component already built");
 

	
 
        let definition = &ctx.heap[definition_id].as_component();
 
        let root_id = definition.defined_in;
 

	
 
        // Check the argument types
 
        let mut arguments = Vec::with_capacity(definition.parameters.len());
 
        for parameter_id in &definition.parameters {
 
            let parameter = &ctx.heap[*parameter_id];
 
            Self::check_member_parser_type(
 
                modules, ctx, root_id, &parameter.parser_type, false
 
                modules, ctx, root_id, &parameter.parser_type, definition.builtin
 
            )?;
 

	
 
            arguments.push(FunctionArgument{
 
            arguments.push(ProcedureArgument{
 
                identifier: parameter.identifier.clone(),
 
                parser_type: parameter.parser_type.clone(),
 
            });
 
@@ -1074,18 +985,17 @@ impl TypeTable {
 

	
 
        // Check conflict of identifiers
 
        Self::check_identifier_collision(
 
            modules, root_id, &arguments, |arg| &arg.identifier, "connector argument"
 
            modules, root_id, &arguments, |arg| &arg.identifier, "procedure argument"
 
        )?;
 
        Self::check_poly_args_collision(modules, ctx, root_id, &definition.poly_vars)?;
 

	
 
        // Construct internal representation of component
 
        // TODO: Marking used polymorphic variables on procedures requires
 
        //  making sure that each is used in the body. For now, mark them all
 
        //  as required.
 
        // Construct internal representation of function type
 
        // TODO: Marking used polymorphic variables should take statements in
 
        //  the body into account. But currently we don't. Hence mark them all
 
        //  as being in-use. Note to self: true condition should be that the
 
        //  polymorphic variables are used in places where the resulting types
 
        //  are themselves truly polymorphic types (e.g. not a phantom type).
 
        let mut poly_vars = Self::create_polymorphic_variables(&definition.poly_vars);
 
        // for argument in &arguments {
 
        //     Self::mark_used_polymorphic_variables(&mut poly_vars, &argument.parser_type);
 
        // }
 
        for poly_var in &mut poly_vars {
 
            poly_var.is_in_use = true;
 
        }
 
@@ -1095,12 +1005,16 @@ impl TypeTable {
 
        self.definition_lookup.insert(definition_id, DefinedType{
 
            ast_root: root_id,
 
            ast_definition: definition_id,
 
            definition: DefinedTypeVariant::Component(ComponentType{ variant: definition.variant, arguments }),
 
            definition: DefinedTypeVariant::Procedure(ProcedureType{
 
                kind: definition.kind,
 
                return_type: definition.return_type.clone(),
 
                arguments
 
            }),
 
            poly_vars,
 
            is_polymorph
 
        });
 

	
 
        Ok(())
 
        return Ok(());
 
    }
 

	
 
    /// Will check if the member type (field of a struct, embedded type in a
 
@@ -1550,15 +1464,17 @@ impl TypeTable {
 
                let type_id = mono_type_map.get(&mono_key).copied();
 
                (DefinitionId::new_invalid(), type_id)
 
            },
 
            CTP::Instance(definition_id, _) |
 
            CTP::Function(definition_id, _) |
 
            CTP::Component(definition_id, _) => {
 
            CTP::Instance(definition_id, _) => {
 
                let definition_type = definition_map.get(definition_id).unwrap();
 
                mono_key.set(&concrete_type.parts, &definition_type.poly_vars);
 
                let type_id = mono_type_map.get(&mono_key).copied();
 

	
 
                (*definition_id, type_id)
 
            },
 
            CTP::Function(_, _) |
 
            CTP::Component(_, _) => {
 
                todo!("function pointers")
 
            },
 
            _ => {
 
                return TypeLoopResult::TypeExists
 
            },
 
@@ -1689,7 +1605,7 @@ impl TypeTable {
 

	
 
                        type_id
 
                    },
 
                    DTV::Function(_) | DTV::Component(_) => {
 
                    DTV::Procedure(_) => {
 
                        unreachable!("pushing type resolving breadcrumb for procedure type")
 
                    },
 
                };
 
@@ -2265,10 +2181,12 @@ fn align_offset_to(offset: &mut usize, alignment: usize) {
 
#[inline]
 
fn get_concrete_type_definition(concrete_parts: &[ConcreteTypePart]) -> Option<DefinitionId> {
 
    match concrete_parts[0] {
 
        ConcreteTypePart::Instance(definition_id, _) |
 
        ConcreteTypePart::Instance(definition_id, _) => {
 
            return Some(definition_id)
 
        },
 
        ConcreteTypePart::Function(definition_id, _) |
 
        ConcreteTypePart::Component(definition_id, _) => {
 
            return Some(definition_id);
 
            return Some(definition_id.upcast());
 
        },
 
        _ => {
 
            return None;
src/protocol/parser/visitor.rs
Show inline comments
 
@@ -137,13 +137,9 @@ macro_rules! visitor_recursive_definition_impl {
 
                let def = def.this;
 
                $this.visit_struct_definition($ctx, def)
 
            },
 
            Definition::Component(def) => {
 
            Definition::Procedure(def) => {
 
                let def = def.this;
 
                $this.visit_component_definition($ctx, def)
 
            },
 
            Definition::Function(def) => {
 
                let def = def.this;
 
                $this.visit_function_definition($ctx, def)
 
                $this.visit_procedure_definition($ctx, def)
 
            },
 
        }
 
    }
 
@@ -238,8 +234,7 @@ pub(crate) trait Visitor {
 
    fn visit_enum_definition(&mut self, _ctx: &mut Ctx, _id: EnumDefinitionId) -> VisitorResult { Ok(()) }
 
    fn visit_union_definition(&mut self, _ctx: &mut Ctx, _id: UnionDefinitionId) -> VisitorResult{ Ok(()) }
 
    fn visit_struct_definition(&mut self, _ctx: &mut Ctx, _id: StructDefinitionId) -> VisitorResult { Ok(()) }
 
    fn visit_component_definition(&mut self, _ctx: &mut Ctx, _id: ComponentDefinitionId) -> VisitorResult { Ok(()) }
 
    fn visit_function_definition(&mut self, _ctx: &mut Ctx, _id: FunctionDefinitionId) -> VisitorResult { Ok(()) }
 
    fn visit_procedure_definition(&mut self, _ctx: &mut Ctx, _id: ProcedureDefinitionId) -> VisitorResult { Ok(()) }
 

	
 
    // Statements
 
    // --- enum matching
src/protocol/tests/utils.rs
Show inline comments
 
@@ -218,7 +218,7 @@ impl AstOkTester {
 
    pub(crate) fn for_function<F: FnOnce(FunctionTester)>(self, name: &str, f: F) -> Self {
 
        let mut found = false;
 
        for definition in self.heap.definitions.iter() {
 
            if let Definition::Function(definition) = definition {
 
            if let Definition::Procedure(definition) = definition {
 
                if definition.identifier.value.as_str() != name {
 
                    continue;
 
                }
 
@@ -507,11 +507,11 @@ impl<'a> UnionTester<'a> {
 

	
 
pub(crate) struct FunctionTester<'a> {
 
    ctx: TestCtx<'a>,
 
    def: &'a FunctionDefinition,
 
    def: &'a ProcedureDefinition,
 
}
 

	
 
impl<'a> FunctionTester<'a> {
 
    fn new(ctx: TestCtx<'a>, def: &'a FunctionDefinition) -> Self {
 
    fn new(ctx: TestCtx<'a>, def: &'a ProcedureDefinition) -> Self {
 
        Self{ ctx, def }
 
    }
 

	
 
@@ -700,11 +700,11 @@ impl<'a> FunctionTester<'a> {
 
        use crate::protocol::*;
 

	
 
        // Assuming the function is not polymorphic
 
        let definition_id = self.def.this.upcast();
 
        let definition_id = self.def.this;
 
        let func_type = [ConcreteTypePart::Function(definition_id, 0)];
 
        let mono_index = self.ctx.types.get_procedure_monomorph_type_id(&definition_id, &func_type).unwrap();
 
        let mono_index = self.ctx.types.get_procedure_monomorph_type_id(&definition_id.upcast(), &func_type).unwrap();
 

	
 
        let mut prompt = Prompt::new(&self.ctx.types, &self.ctx.heap, self.def.this.upcast(), mono_index, ValueGroup::new_stack(Vec::new()));
 
        let mut prompt = Prompt::new(&self.ctx.types, &self.ctx.heap, definition_id, mono_index, ValueGroup::new_stack(Vec::new()));
 
        let mut call_context = FakeRunContext{};
 
        loop {
 
            let result = prompt.step(&self.ctx.types, &self.ctx.heap, &self.ctx.modules, &mut call_context);
 
@@ -806,14 +806,11 @@ impl<'a> ExpressionTester<'a> {
 
}
 

	
 
fn get_procedure_monomorph<'a>(heap: &Heap, types: &'a TypeTable, definition_id: DefinitionId) -> &'a ProcedureMonomorph {
 
    let ast_definition = &heap[definition_id];
 
    let func_type = if ast_definition.is_function() {
 
        [ConcreteTypePart::Function(definition_id, 0)]
 
    } else if ast_definition.is_component() {
 
        [ConcreteTypePart::Component(definition_id, 0)]
 
    let ast_definition = heap[definition_id].as_procedure();
 
    let func_type = if ast_definition.kind == ProcedureKind::Function {
 
        [ConcreteTypePart::Function(ast_definition.this, 0)]
 
    } else {
 
        assert!(false);
 
        unreachable!()
 
        [ConcreteTypePart::Component(ast_definition.this, 0)]
 
    };
 

	
 
    let mono_index = types.get_procedure_monomorph_type_id(&definition_id, &func_type).unwrap();
 
@@ -928,10 +925,14 @@ fn has_equal_num_monomorphs(ctx: TestCtx, num: usize, definition_id: DefinitionI
 

	
 
    for mono in &ctx.types.mono_types {
 
        match &mono.concrete_type.parts[0] {
 
            ConcreteTypePart::Instance(def_id, _) |
 
            ConcreteTypePart::Instance(def_id, _) => {
 
                if *def_id == definition_id {
 
                    num_on_type += 1;
 
                }
 
            }
 
            ConcreteTypePart::Function(def_id, _) |
 
            ConcreteTypePart::Component(def_id, _) => {
 
                if *def_id == definition_id {
 
                if def_id.upcast() == definition_id {
 
                    num_on_type += 1;
 
                }
 
            },
 
@@ -964,11 +965,11 @@ fn has_monomorph(ctx: TestCtx, definition_id: DefinitionId, serialized_monomorph
 
    };
 

	
 
    // Bit wasteful, but this is (temporary?) testing code:
 
    for (mono_idx, mono) in ctx.types.mono_types.iter().enumerate() {
 
    for (_mono_idx, mono) in ctx.types.mono_types.iter().enumerate() {
 
        let got_definition_id = match &mono.concrete_type.parts[0] {
 
            ConcreteTypePart::Instance(v, _) |
 
            ConcreteTypePart::Instance(v, _) => *v,
 
            ConcreteTypePart::Function(v, _) |
 
            ConcreteTypePart::Component(v, _) => *v,
 
            ConcreteTypePart::Component(v, _) => v.upcast(),
 
            _ => DefinitionId::new_invalid(),
 
        };
 
        if got_definition_id == definition_id {
src/runtime2/component/component_pdl.rs
Show inline comments
 
use crate::protocol::*;
 
use crate::protocol::ast::DefinitionId;
 
use crate::protocol::ast::ProcedureDefinitionId;
 
use crate::protocol::eval::{
 
    PortId as EvalPortId, Prompt,
 
    ValueGroup, Value,
 
@@ -598,7 +598,7 @@ impl CompPDL {
 
    fn create_component_and_transfer_ports(
 
        &mut self,
 
        sched_ctx: &SchedulerCtx, creator_ctx: &mut CompCtx,
 
        definition_id: DefinitionId, type_id: TypeId, mut arguments: ValueGroup
 
        definition_id: ProcedureDefinitionId, type_id: TypeId, mut arguments: ValueGroup
 
    ) {
 
        struct PortPair{
 
            creator_handle: LocalPortHandle,
0 comments (0 inline, 0 general)