Changeset - 379cffa23df8
[Not reviewed]
0 8 0
mh - 4 years ago 2021-01-15 18:21:28
contact@maxhenger.nl
WIP on type table
8 files changed with 826 insertions and 214 deletions:
0 comments (0 inline, 0 general)
language_spec.md
Show inline comments
 
@@ -98,13 +98,13 @@ keyword =
 
    type-primitive | "true" | "false" | "null" |
 
    "struct" | "enum" |
 
    "if" | "else" |
 
    "while" | "break" | "continue" | "return" |
 
    "synchronous" | "assert" |
 
    "goto" | "skip" | "new" | "let"
 
builtin = "put" | "get" | "fires" | "create" | "sizeof" | "assert"
 
builtin = "put" | "get" | "fires" | "create" | "assert"
 
identifier = identifier-any WITHOUT (keyword | builtin)
 

	
 
// Identifier with any number of prefixed namespaces
 
ns-identifier = (identifier "::")* identifier
 
```
 

	
src/protocol/arena.rs
Show inline comments
 
@@ -49,12 +49,15 @@ impl<T> Arena<T> {
 
        self.store.push(f(id));
 
        id
 
    }
 
    pub fn iter(&self) -> impl Iterator<Item = &T> {
 
        self.store.iter()
 
    }
 
    pub fn len(&self) -> usize {
 
        self.store.len()
 
    }
 
}
 
impl<T> core::ops::Index<Id<T>> for Arena<T> {
 
    type Output = T;
 
    fn index(&self, id: Id<T>) -> &Self::Output {
 
        self.store.index(id.index as usize)
 
    }
src/protocol/ast.rs
Show inline comments
 
@@ -37,13 +37,13 @@ pub struct LocalId(VariableId);
 
impl LocalId {
 
    pub fn upcast(self) -> VariableId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
 
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
 
pub struct DefinitionId(Id<Definition>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
 
pub struct StructId(DefinitionId);
 

	
 
impl StructId {
 
@@ -76,30 +76,12 @@ pub struct FunctionId(DefinitionId);
 
impl FunctionId {
 
    pub fn upcast(self) -> DefinitionId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
 
pub struct CompositeId(ComponentId);
 

	
 
impl CompositeId {
 
    pub fn upcast(self) -> ComponentId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
 
pub struct PrimitiveId(ComponentId);
 

	
 
impl PrimitiveId {
 
    pub fn upcast(self) -> ComponentId {
 
        self.0
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
 
pub struct StatementId(Id<Statement>);
 

	
 
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
 
pub struct BlockStatementId(StatementId);
 

	
 
@@ -403,13 +385,13 @@ impl ImportedDeclarationId {
 
    }
 
}
 

	
 
#[derive(Debug, serde::Serialize, serde::Deserialize)]
 
pub struct Heap {
 
    // Allocators
 
    // #[serde[skip]] string_alloc: StringAllocator,
 
    // #[serde(skip)] string_alloc: StringAllocator,
 
    // Root arena, contains the entry point for different modules. Each root
 
    // contains lists of IDs that correspond to the other arenas.
 
    protocol_descriptions: Arena<Root>,
 
    // Contents of a file, these are the elements the `Root` elements refer to
 
    pragmas: Arena<Pragma>,
 
    pub(crate) imports: Arena<Import>,
 
@@ -730,25 +712,18 @@ impl Heap {
 
    }
 
    pub fn alloc_enum_definition(&mut self, f: impl FnOnce(EnumId) -> EnumDefinition) -> EnumId {
 
        EnumId(DefinitionId(self.definitions.alloc_with_id(|id| {
 
            Definition::Enum(f(EnumId(DefinitionId(id))))
 
        })))
 
    }
 
    pub fn alloc_composite(&mut self, f: impl FnOnce(CompositeId) -> Composite) -> CompositeId {
 
        CompositeId(ComponentId(DefinitionId(self.definitions.alloc_with_id(|id| {
 
            Definition::Component(Component::Composite(f(CompositeId(ComponentId(DefinitionId(
 
                id,
 
            ))))))
 
        }))))
 
    }
 
    pub fn alloc_primitive(&mut self, f: impl FnOnce(PrimitiveId) -> Primitive) -> PrimitiveId {
 
        PrimitiveId(ComponentId(DefinitionId(self.definitions.alloc_with_id(|id| {
 
            Definition::Component(Component::Primitive(f(PrimitiveId(ComponentId(DefinitionId(
 
                id,
 
            ))))))
 
        }))))
 
    pub fn alloc_component(&mut self, f: impl FnOnce(ComponentId) -> Component) -> ComponentId {
 
        ComponentId(DefinitionId(self.definitions.alloc_with_id(|id| {
 
            Definition::Component(f(ComponentId(
 
                DefinitionId(id),
 
            )))
 
        })))
 
    }
 
    pub fn alloc_function(&mut self, f: impl FnOnce(FunctionId) -> Function) -> FunctionId {
 
        FunctionId(DefinitionId(
 
            self.definitions
 
                .alloc_with_id(|id| Definition::Function(f(FunctionId(DefinitionId(id))))),
 
        ))
 
@@ -861,26 +836,12 @@ impl Index<FunctionId> for Heap {
 
    type Output = Function;
 
    fn index(&self, index: FunctionId) -> &Self::Output {
 
        &self.definitions[(index.0).0].as_function()
 
    }
 
}
 

	
 
impl Index<CompositeId> for Heap {
 
    type Output = Composite;
 
    fn index(&self, index: CompositeId) -> &Self::Output {
 
        &self.definitions[((index.0).0).0].as_composite()
 
    }
 
}
 

	
 
impl Index<PrimitiveId> for Heap {
 
    type Output = Primitive;
 
    fn index(&self, index: PrimitiveId) -> &Self::Output {
 
        &self.definitions[((index.0).0).0].as_primitive()
 
    }
 
}
 

	
 
impl Index<StatementId> for Heap {
 
    type Output = Statement;
 
    fn index(&self, index: StatementId) -> &Self::Output {
 
        &self.statements[index.0]
 
    }
 
}
 
@@ -1196,12 +1157,22 @@ impl Root {
 
            if declaration.identifier().value == id.value {
 
                return Some(*declaration_id);
 
            }
 
        }
 
        None
 
    }
 
    pub fn get_declaration_namespaced(&self, h: &Heap, id: &NamespacedIdentifier) -> Option<DeclarationId> {
 
        for declaration_id in self.declarations.iter() {
 
            let declaration = &h[*declaration_id];
 
            // TODO: @fixme
 
            if declaration.identifier().value == id.value {
 
                return Some(*declaration_id);
 
            }
 
        }
 
        None
 
    }
 
}
 

	
 
impl SyntaxElement for Root {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
@@ -1320,29 +1291,46 @@ pub struct NamespacedIdentifier {
 
    pub position: InputPosition,
 
    pub num_namespaces: u8,
 
    pub value: Vec<u8>,
 
}
 

	
 
impl NamespacedIdentifier {
 
    fn iter(&self) -> NamespacedIdentifierIter {
 
    pub(crate) fn iter(&self) -> NamespacedIdentifierIter {
 
        NamespacedIdentifierIter{
 
            value: &self.value,
 
            cur_offset: 0,
 
            num_returned: 0,
 
            num_total: self.num_namespaces
 
        }
 
    }
 
}
 

	
 
struct NamespacedIdentifierIter<'a> {
 
impl PartialEq for NamespacedIdentifier {
 
    fn eq(&self, other: &Self) -> bool {
 
        return self.value == other.value
 
    }
 
}
 
impl Eq for NamespacedIdentifier{}
 

	
 
// TODO: Just keep ref to NamespacedIdentifier
 
pub(crate) struct NamespacedIdentifierIter<'a> {
 
    value: &'a Vec<u8>,
 
    cur_offset: usize,
 
    num_returned: u8,
 
    num_total: u8,
 
}
 

	
 
impl<'a> NamespacedIdentifierIter<'a> {
 
    pub(crate) fn num_returned(&self) -> u8 {
 
        return self.num_returned;
 
    }
 
    pub(crate) fn num_remaining(&self) -> u8 {
 
        return self.num_total - self.num_returned
 
    }
 
}
 

	
 
impl<'a> Iterator for NamespacedIdentifierIter<'a> {
 
    type Item = &'a [u8];
 
    fn next(&mut self) -> Option<Self::Item> {
 
        if self.cur_offset >= self.value.len() {
 
            debug_assert_eq!(self.num_returned, self.num_total);
 
            None
 
@@ -1374,27 +1362,41 @@ impl Display for Identifier {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        // A source identifier is in ASCII range.
 
        write!(f, "{}", String::from_utf8_lossy(&self.value))
 
    }
 
}
 

	
 
type TypeData = Vec<u8>;
 

	
 
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
 
pub enum PrimitiveType {
 
    Input,
 
    Output,
 
    Message,
 
    Boolean,
 
    Byte,
 
    Short,
 
    Int,
 
    Long,
 
    Symbolic(TypeData),
 
    Symbolic(PrimitiveSymbolic)
 
}
 

	
 
// TODO: @cleanup, remove PartialEq implementations
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct PrimitiveSymbolic {
 
    // Phase 1: parser
 
    pub(crate) identifier: NamespacedIdentifier,
 
    // Phase 2: typing
 
    pub(crate) definition: Option<DefinitionId>
 
}
 

	
 
impl PartialEq for PrimitiveSymbolic {
 
    fn eq(&self, other: &Self) -> bool {
 
        self.identifier == other.identifier
 
    }
 
}
 
impl Eq for PrimitiveSymbolic{}
 

	
 
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
 
pub struct Type {
 
    pub primitive: PrimitiveType,
 
    pub array: bool,
 
}
 

	
 
@@ -1445,13 +1447,24 @@ impl Display for Type {
 
            }
 
            PrimitiveType::Long => {
 
                write!(f, "long")?;
 
            }
 
            PrimitiveType::Symbolic(data) => {
 
                // Type data is in ASCII range.
 
                write!(f, "{}", String::from_utf8_lossy(&data))?;
 
                if let Some(id) = &data.definition {
 
                    write!(
 
                        f, "Symbolic({}, id: {})", 
 
                        String::from_utf8_lossy(&data.identifier.value),
 
                        id.0.index
 
                    )?;
 
                } else {
 
                    write!(
 
                        f, "Symbolic({}, id: Unresolved)",
 
                        String::from_utf8_lossy(&data.identifier.value)
 
                    )?;
 
                }
 
            }
 
        }
 
        if self.array {
 
            write!(f, "[]")
 
        } else {
 
            Ok(())
 
@@ -1487,13 +1500,19 @@ pub enum Constant {
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum Method {
 
    Get,
 
    Fires,
 
    Create,
 
    Symbolic(Identifier),
 
    Symbolic(MethodSymbolic)
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct MethodSymbolic {
 
    pub(crate) identifier: NamespacedIdentifier,
 
    pub(crate) definition: Option<DefinitionId>
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum Field {
 
    Length,
 
    Symbolic(Identifier),
 
@@ -1670,39 +1689,33 @@ impl Definition {
 
    pub fn as_function(&self) -> &Function {
 
        match self {
 
            Definition::Function(result) => result,
 
            _ => panic!("Unable to cast `Definition` to `Function`"),
 
        }
 
    }
 
    pub fn as_composite(&self) -> &Composite {
 
        self.as_component().as_composite()
 
    }
 
    pub fn as_primitive(&self) -> &Primitive {
 
        self.as_component().as_primitive()
 
    }
 
    pub fn identifier(&self) -> &Identifier {
 
        match self {
 
            Definition::Struct(def) => &def.identifier,
 
            Definition::Enum(def) => &def.identifier,
 
            Definition::Component(com) => com.identifier(),
 
            Definition::Component(com) => &com.identifier,
 
            Definition::Function(fun) => &fun.identifier,
 
        }
 
    }
 
    pub fn parameters(&self) -> &Vec<ParameterId> {
 
        // TODO: Fix this
 
        static EMPTY_VEC: Vec<ParameterId> = Vec::new();
 
        match self {
 
            Definition::Component(com) => com.parameters(),
 
            Definition::Component(com) => &com.parameters,
 
            Definition::Function(fun) => &fun.parameters,
 
            _ => &EMPTY_VEC,
 
        }
 
    }
 
    pub fn body(&self) -> StatementId {
 
        // TODO: Fix this
 
        match self {
 
            Definition::Component(com) => com.body(),
 
            Definition::Component(com) => com.body,
 
            Definition::Function(fun) => fun.body,
 
            _ => panic!("cannot retrieve body (for EnumDefinition or StructDefinition)")
 
        }
 
    }
 
}
 

	
 
@@ -1768,93 +1781,30 @@ pub struct EnumDefinition {
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub identifier: Identifier,
 
    pub variants: Vec<EnumVariantDefinition>,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum Component {
 
    Composite(Composite),
 
    Primitive(Primitive),
 
}
 

	
 
impl Component {
 
    pub fn this(&self) -> ComponentId {
 
        match self {
 
            Component::Composite(com) => com.this.upcast(),
 
            Component::Primitive(prim) => prim.this.upcast(),
 
        }
 
    }
 
    pub fn as_composite(&self) -> &Composite {
 
        match self {
 
            Component::Composite(result) => result,
 
            _ => panic!("Unable to cast `Component` to `Composite`"),
 
        }
 
    }
 
    pub fn as_primitive(&self) -> &Primitive {
 
        match self {
 
            Component::Primitive(result) => result,
 
            _ => panic!("Unable to cast `Component` to `Primitive`"),
 
        }
 
    }
 
    fn identifier(&self) -> &Identifier {
 
        match self {
 
            Component::Composite(com) => &com.identifier,
 
            Component::Primitive(prim) => &prim.identifier,
 
        }
 
    }
 
    pub fn parameters(&self) -> &Vec<ParameterId> {
 
        match self {
 
            Component::Composite(com) => &com.parameters,
 
            Component::Primitive(prim) => &prim.parameters,
 
        }
 
    }
 
    pub fn body(&self) -> StatementId {
 
        match self {
 
            Component::Composite(com) => com.body,
 
            Component::Primitive(prim) => prim.body,
 
        }
 
    }
 
}
 

	
 
impl SyntaxElement for Component {
 
    fn position(&self) -> InputPosition {
 
        match self {
 
            Component::Composite(def) => def.position(),
 
            Component::Primitive(def) => def.position(),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct Composite {
 
    pub this: CompositeId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub identifier: Identifier,
 
    pub parameters: Vec<ParameterId>,
 
    pub body: StatementId,
 
}
 

	
 
impl SyntaxElement for Composite {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
 
pub enum ComponentVariant {
 
    Primitive,
 
    Composite,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct Primitive {
 
    pub this: PrimitiveId,
 
pub struct Component {
 
    pub this: ComponentId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub variant: ComponentVariant,
 
    pub identifier: Identifier,
 
    pub parameters: Vec<ParameterId>,
 
    pub body: StatementId,
 
}
 

	
 
impl SyntaxElement for Primitive {
 
impl SyntaxElement for Component {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
@@ -1928,14 +1878,14 @@ pub enum Signature {
 

	
 
impl Signature {
 
    pub fn from_definition(h: &Heap, def: DefinitionId) -> Signature {
 
        // TODO: Fix this
 
        match &h[def] {
 
            Definition::Component(com) => Signature::Component(ComponentSignature {
 
                identifier: com.identifier().clone(), // TODO: @fix
 
                arity: Signature::convert_parameters(h, com.parameters()),
 
                identifier: com.identifier.clone(), // TODO: @fix
 
                arity: Signature::convert_parameters(h, &com.parameters),
 
            }),
 
            Definition::Function(fun) => Signature::Function(FunctionSignature {
 
                return_type: h[fun.return_type].the_type.clone(),
 
                identifier: fun.identifier.clone(), // TODO: @fix
 
                arity: Signature::convert_parameters(h, &fun.parameters),
 
            }),
src/protocol/containers.rs
Show inline comments
 
/// Containers.rs
 
///
 
/// Contains specialized containers for the parser/compiler
 
/// TODO: Actually implement, I really want to remove all of the identifier
 
///     allocations.
 

	
 
use std::collections::LinkedList;
 

	
 
const PAGE_SIZE: usize = 4096;
 

	
 
struct StringPage {
 
    buffer: [u8; PAGE_SIZE],
 
    remaining: usize,
 
    next_page: Option<Box<StringPage>>,
 
}
 

	
 
impl StringPage {
 
    fn new() -> Self{
 
        let res = Self{
 
        Self{
 
            buffer: [0; PAGE_SIZE],
 
            remaining: PAGE_SIZE,
 
            next_page: None
 
        };
 
        res
 
        }
 
    }
 
}
 

	
 
/// Custom allocator for strings that are copied and remain valid during the
 
/// complete compilation phase. May perform multiple allocations but the
 
/// previously allocated strings remain valid. Because we will usually allocate
 
@@ -28,12 +31,14 @@ impl StringPage {
 
/// StringAllocator.
 
pub(crate) struct StringAllocator {
 
    first_page: Box<StringPage>,
 
    last_page: *mut StringPage,
 
}
 

	
 
unsafe impl Send for StringAllocator {}
 

	
 
impl StringAllocator {
 
    pub(crate) fn new() -> StringAllocator {
 
        let mut page = Box::new(StringPage::new());
 
        let page_ptr = unsafe { page.as_mut() as *mut StringPage };
 
        StringAllocator{
 
            first_page: page,
 
@@ -87,16 +92,20 @@ mod tests {
 
    fn test_alloc() {
 
        // Make sure pointers are somewhat correct
 
        let mut alloc = StringAllocator::new();
 
        assert!(alloc.first_page.next_page.is_none());
 
        assert_eq!(alloc.first_page.as_ref() as *const StringPage, alloc.last_page);
 

	
 
        // Insert and make page full, should not allocate another page yet
 
        let input = "I am a simple static string";
 
        let filler = " ".repeat(PAGE_SIZE - input.len());
 
        let ref_first = alloc.alloc(input.as_bytes()).expect("alloc first");
 
        let ref_filler = alloc.alloc(filler.as_bytes()).expect("alloc filler");
 
        assert!(alloc.first_page.next_page.is_none());
 
        assert_eq!(alloc.first_page.as_ref() as *const StringPage, alloc.last_page);
 

	
 
        let ref_second = alloc.alloc(input.as_bytes()).expect("alloc second");
 

	
 
        assert!(alloc.first_page.next_page.is_some());
 
        assert!(alloc.first_page.next_page.as_ref().unwrap().next_page.is_none());
 
        let last_page_ptr = alloc.first_page.next_page.as_ref().unwrap().as_ref() as *const StringPage;
 
        assert_eq!(last_page_ptr, alloc.last_page);
src/protocol/lexer.rs
Show inline comments
 
use crate::protocol::ast::*;
 
use crate::protocol::inputsource::*;
 

	
 
const MAX_LEVEL: usize = 128;
 
const MAX_NAMESPACES: u8 = 8; // only three levels are supported at the moment
 

	
 
fn is_vchar(x: Option<u8>) -> bool {
 
    if let Some(c) = x {
 
        c >= 0x21 && c <= 0x7E
 
    } else {
 
        false
 
@@ -256,26 +257,26 @@ impl Lexer<'_> {
 

	
 
            Ok(parsed.unwrap())
 
        }
 
    }
 

	
 
    // Statement keywords
 

	
 
    // TODO: Clean up these functions
 
    fn has_statement_keyword(&self) -> bool {
 
        self.has_keyword(b"channel")
 
            || self.has_keyword(b"skip")
 
            || self.has_keyword(b"if")
 
            || self.has_keyword(b"while")
 
            || self.has_keyword(b"break")
 
            || self.has_keyword(b"continue")
 
            || self.has_keyword(b"synchronous")
 
            || self.has_keyword(b"return")
 
            || self.has_keyword(b"assert")
 
            || self.has_keyword(b"goto")
 
            || self.has_keyword(b"new")
 
            || self.has_keyword(b"put")
 
            || self.has_keyword(b"put") // TODO: @fix, should be a function, even though it has sideeffects
 
    }
 
    fn has_type_keyword(&self) -> bool {
 
        self.has_keyword(b"in")
 
            || self.has_keyword(b"out")
 
            || self.has_keyword(b"msg")
 
            || self.has_keyword(b"boolean")
 
@@ -287,23 +288,34 @@ impl Lexer<'_> {
 
    fn has_builtin_keyword(&self) -> bool {
 
        self.has_keyword(b"get")
 
            || self.has_keyword(b"fires")
 
            || self.has_keyword(b"create")
 
            || self.has_keyword(b"length")
 
    }
 
    fn has_reserved(&self) -> bool {
 
        self.has_statement_keyword()
 
            || self.has_type_keyword()
 
            || self.has_builtin_keyword()
 
            || self.has_keyword(b"let")
 
            || self.has_keyword(b"struct")
 
            || self.has_keyword(b"enum")
 
            || self.has_keyword(b"true")
 
            || self.has_keyword(b"false")
 
            || self.has_keyword(b"null")
 
    }
 

	
 
    // Identifiers
 

	
 
    fn has_identifier(&self) -> bool {
 
        if self.has_statement_keyword() || self.has_type_keyword() || self.has_builtin_keyword() {
 
            return false;
 
        }
 
        let next = self.source.next();
 
        is_ident_start(next)
 
    }
 
    fn consume_identifier(&mut self, h: &mut Heap) -> Result<Identifier, ParseError2> {
 
    fn consume_identifier(&mut self) -> Result<Identifier, ParseError2> {
 
        if self.has_statement_keyword() || self.has_type_keyword() || self.has_builtin_keyword() {
 
            return Err(self.error_at_pos("Expected identifier"));
 
        }
 
        let position = self.source.pos();
 
        let value = self.consume_ident()?;
 
        Ok(Identifier{ position, value })
 
@@ -312,15 +324,39 @@ impl Lexer<'_> {
 
        if self.has_statement_keyword() || self.has_type_keyword() || self.has_builtin_keyword() {
 
            return Err(self.error_at_pos("Expected identifier"));
 
        }
 
        self.consume_ident()?;
 
        Ok(())
 
    }
 
    fn has_namespaced_identifier(&self) -> bool { 
 
        self.has_identifier() 
 
    }
 
    fn consume_namespaced_identifier(&mut self) -> Result<NamespacedIdentifier, ParseError2> {
 
        if self.has_reserved() {
 
            return Err(self.error_at_pos("Encountered reserved keyword"));
 
        }
 

	
 
    // Types and type annotations
 
        let position = self.source.pos();
 
        let mut ns_ident = self.consume_ident()?;
 
        let mut num_namespaces = 1;
 
        while self.has_string(b"::") {
 
            if num_namespaces >= MAX_NAMESPACES {
 
                return Err(self.error_at_pos("Too many namespaces in identifier"));
 
            }
 
            let new_ident = self.consume_ident()?;
 
            num_namespaces += 1;
 
        }
 

	
 
        Ok(NamespacedIdentifier{
 
            position,
 
            value: ns_ident,
 
            num_namespaces,
 
        })
 
    }
 

	
 
    // Types and type annotations
 
    fn consume_primitive_type(&mut self) -> Result<PrimitiveType, ParseError2> {
 
        if self.has_keyword(b"in") {
 
            self.consume_keyword(b"in")?;
 
            Ok(PrimitiveType::Input)
 
        } else if self.has_keyword(b"out") {
 
            self.consume_keyword(b"out")?;
 
@@ -340,15 +376,20 @@ impl Lexer<'_> {
 
        } else if self.has_keyword(b"int") {
 
            self.consume_keyword(b"int")?;
 
            Ok(PrimitiveType::Int)
 
        } else if self.has_keyword(b"long") {
 
            self.consume_keyword(b"long")?;
 
            Ok(PrimitiveType::Long)
 
        } else if self.has_keyword(b"let") {
 
            return Err(self.error_at_pos("inferred types using 'let' are reserved, but not yet implemented"));
 
        } else {
 
            let data = self.consume_ident()?;
 
            Ok(PrimitiveType::Symbolic(data))
 
            let identifier = self.consume_namespaced_identifier()?;
 
            Ok(PrimitiveType::Symbolic(PrimitiveSymbolic{
 
                identifier,
 
                definition: None
 
            }))
 
        }
 
    }
 
    fn has_array(&mut self) -> bool {
 
        let backup_pos = self.source.pos();
 
        let mut result = false;
 
        match self.consume_whitespace(false) {
 
@@ -395,13 +436,13 @@ impl Lexer<'_> {
 
    // Parameters
 

	
 
    fn consume_parameter(&mut self, h: &mut Heap) -> Result<ParameterId, ParseError2> {
 
        let position = self.source.pos();
 
        let type_annotation = self.consume_type_annotation(h)?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        let identifier = self.consume_identifier()?;
 
        let id =
 
            h.alloc_parameter(|this| Parameter { this, position, type_annotation, identifier });
 
        Ok(id)
 
    }
 
    fn consume_parameters(
 
        &mut self,
 
@@ -976,13 +1017,13 @@ impl Lexer<'_> {
 
                let subject = result;
 
                let field;
 
                if self.has_keyword(b"length") {
 
                    self.consume_keyword(b"length")?;
 
                    field = Field::Length;
 
                } else {
 
                    field = Field::Symbolic(self.consume_identifier(h)?);
 
                    field = Field::Symbolic(self.consume_identifier()?);
 
                }
 
                result = h
 
                    .alloc_select_expression(|this| SelectExpression {
 
                        this,
 
                        position,
 
                        subject,
 
@@ -1103,14 +1144,17 @@ impl Lexer<'_> {
 
            self.consume_keyword(b"fires")?;
 
            method = Method::Fires;
 
        } else if self.has_keyword(b"create") {
 
            self.consume_keyword(b"create")?;
 
            method = Method::Create;
 
        } else {
 
            let identifier = self.consume_identifier(h)?;
 
            method = Method::Symbolic(identifier)
 
            let identifier = self.consume_namespaced_identifier()?;
 
            method = Method::Symbolic(MethodSymbolic{
 
                identifier,
 
                definition: None
 
            })
 
        }
 
        self.consume_whitespace(false)?;
 
        let mut arguments = Vec::new();
 
        self.consume_string(b"(")?;
 
        self.consume_whitespace(false)?;
 
        if !self.has_string(b")") {
 
@@ -1135,13 +1179,13 @@ impl Lexer<'_> {
 
    }
 
    fn consume_variable_expression(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<VariableExpressionId, ParseError2> {
 
        let position = self.source.pos();
 
        let identifier = self.consume_identifier(h)?;
 
        let identifier = self.consume_identifier()?;
 
        Ok(h.alloc_variable_expression(|this| VariableExpression {
 
            this,
 
            position,
 
            identifier,
 
            declaration: None,
 
        }))
 
@@ -1274,18 +1318,18 @@ impl Lexer<'_> {
 
        h: &mut Heap,
 
    ) -> Result<ChannelStatementId, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"channel")?;
 
        self.consume_whitespace(true)?;
 
        let from_annotation = self.create_type_annotation_output(h)?;
 
        let from_identifier = self.consume_identifier(h)?;
 
        let from_identifier = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b"->")?;
 
        self.consume_whitespace(false)?;
 
        let to_annotation = self.create_type_annotation_input(h)?;
 
        let to_identifier = self.consume_identifier(h)?;
 
        let to_identifier = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        let from = h.alloc_local(|this| Local {
 
            this,
 
            position,
 
            type_annotation: from_annotation,
 
@@ -1306,13 +1350,13 @@ impl Lexer<'_> {
 
        }))
 
    }
 
    fn consume_memory_statement(&mut self, h: &mut Heap) -> Result<MemoryStatementId, ParseError2> {
 
        let position = self.source.pos();
 
        let type_annotation = self.consume_type_annotation(h)?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        let identifier = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b"=")?;
 
        self.consume_whitespace(false)?;
 
        let initial = self.consume_expression(h)?;
 
        let variable = h.alloc_local(|this| Local { this, position, type_annotation, identifier });
 
        self.consume_whitespace(false)?;
 
@@ -1327,13 +1371,13 @@ impl Lexer<'_> {
 
    }
 
    fn consume_labeled_statement(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<LabeledStatementId, ParseError2> {
 
        let position = self.source.pos();
 
        let label = self.consume_identifier(h)?;
 
        let label = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b":")?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_statement(h)?;
 
        Ok(h.alloc_labeled_statement(|this| LabeledStatement {
 
            this,
 
@@ -1386,13 +1430,13 @@ impl Lexer<'_> {
 
    fn consume_break_statement(&mut self, h: &mut Heap) -> Result<BreakStatementId, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"break")?;
 
        self.consume_whitespace(false)?;
 
        let label;
 
        if self.has_identifier() {
 
            label = Some(self.consume_identifier(h)?);
 
            label = Some(self.consume_identifier()?);
 
            self.consume_whitespace(false)?;
 
        } else {
 
            label = None;
 
        }
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_break_statement(|this| BreakStatement { this, position, label, target: None }))
 
@@ -1403,13 +1447,13 @@ impl Lexer<'_> {
 
    ) -> Result<ContinueStatementId, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"continue")?;
 
        self.consume_whitespace(false)?;
 
        let label;
 
        if self.has_identifier() {
 
            label = Some(self.consume_identifier(h)?);
 
            label = Some(self.consume_identifier()?);
 
            self.consume_whitespace(false)?;
 
        } else {
 
            label = None;
 
        }
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_continue_statement(|this| ContinueStatement {
 
@@ -1474,13 +1518,13 @@ impl Lexer<'_> {
 
        }))
 
    }
 
    fn consume_goto_statement(&mut self, h: &mut Heap) -> Result<GotoStatementId, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"goto")?;
 
        self.consume_whitespace(false)?;
 
        let label = self.consume_identifier(h)?;
 
        let label = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_goto_statement(|this| GotoStatement { this, position, label, target: None }))
 
    }
 
    fn consume_new_statement(&mut self, h: &mut Heap) -> Result<NewStatementId, ParseError2> {
 
        let position = self.source.pos();
 
@@ -1546,13 +1590,13 @@ impl Lexer<'_> {
 
    }
 
    fn consume_struct_definition(&mut self, h: &mut Heap) -> Result<StructId, ParseError2> {
 
        // Parse "struct" keyword and its identifier
 
        let struct_pos = self.source.pos();
 
        self.consume_keyword(b"struct")?;
 
        self.consume_whitespace(true)?;
 
        let struct_ident = self.consume_identifier(h)?;
 
        let struct_ident = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 

	
 
        // Parse struct fields
 
        self.consume_string(b"{")?;
 
        let mut next = self.source.next();
 
        let mut fields = Vec::new();
 
@@ -1564,13 +1608,13 @@ impl Lexer<'_> {
 

	
 
            // Consume field definition
 
            self.consume_whitespace(false)?;
 
            let field_position = self.source.pos();
 
            let field_type = self.consume_type_annotation(h)?;
 
            self.consume_whitespace(true)?;
 
            let field_ident = self.consume_identifier(h)?;
 
            let field_ident = self.consume_identifier()?;
 
            self.consume_whitespace(false)?;
 

	
 
            fields.push(StructFieldDefinition{
 
                position: field_position,
 
                field: field_ident,
 
                the_type: field_type,
 
@@ -1602,13 +1646,13 @@ impl Lexer<'_> {
 
    }
 
    fn consume_enum_definition(&mut self, h: &mut Heap) -> Result<EnumId, ParseError2> {
 
        // Parse "enum" keyword and its identifier
 
        let enum_pos = self.source.pos();
 
        self.consume_keyword(b"enum")?;
 
        self.consume_whitespace(true)?;
 
        let enum_ident = self.consume_identifier(h)?;
 
        let enum_ident = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 

	
 
        // Parse enum variants
 
        self.consume_string(b"{")?;
 
        let mut next = self.source.next();
 
        let mut variants = Vec::new();
 
@@ -1618,13 +1662,13 @@ impl Lexer<'_> {
 
                break;
 
            }
 

	
 
            // Consume variant identifier
 
            self.consume_whitespace(false)?;
 
            let variant_position = self.source.pos();
 
            let variant_ident = self.consume_identifier(h)?;
 
            let variant_ident = self.consume_identifier()?;
 
            self.consume_whitespace(false)?;
 

	
 
            // Consume variant (tag) value: may be nothing, in which case it is
 
            // assigned automatically, may be a constant integer, or an embedded
 
            // type as value, resulting in a tagged union
 
            next = self.source.next();
 
@@ -1682,47 +1726,52 @@ impl Lexer<'_> {
 
            position: enum_pos,
 
            identifier: enum_ident,
 
            variants,
 
        }))
 
    }
 
    fn consume_component_definition(&mut self, h: &mut Heap) -> Result<ComponentId, ParseError2> {
 
        // TODO: Cleanup
 
        if self.has_keyword(b"composite") {
 
            Ok(self.consume_composite_definition(h)?.upcast())
 
            Ok(self.consume_composite_definition(h)?)
 
        } else {
 
            Ok(self.consume_primitive_definition(h)?.upcast())
 
            Ok(self.consume_primitive_definition(h)?)
 
        }
 
    }
 
    fn consume_composite_definition(&mut self, h: &mut Heap) -> Result<CompositeId, ParseError2> {
 
    fn consume_composite_definition(&mut self, h: &mut Heap) -> Result<ComponentId, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"composite")?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        let identifier = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        self.consume_parameters(h, &mut parameters)?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_block_statement(h)?;
 
        Ok(h.alloc_composite(|this| Composite { this, position, identifier, parameters, body }))
 
        Ok(h.alloc_component(|this| Component { 
 
            this, variant: ComponentVariant::Composite, position, identifier, parameters, body 
 
        }))
 
    }
 
    fn consume_primitive_definition(&mut self, h: &mut Heap) -> Result<PrimitiveId, ParseError2> {
 
    fn consume_primitive_definition(&mut self, h: &mut Heap) -> Result<ComponentId, ParseError2> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"primitive")?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        let identifier = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        self.consume_parameters(h, &mut parameters)?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_block_statement(h)?;
 
        Ok(h.alloc_primitive(|this| Primitive { this, position, identifier, parameters, body }))
 
        Ok(h.alloc_component(|this| Component { 
 
            this, variant: ComponentVariant::Primitive, position, identifier, parameters, body 
 
        }))
 
    }
 
    fn consume_function_definition(&mut self, h: &mut Heap) -> Result<FunctionId, ParseError2> {
 
        let position = self.source.pos();
 
        let return_type = self.consume_type_annotation(h)?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        let identifier = self.consume_identifier()?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        self.consume_parameters(h, &mut parameters)?;
 
        self.consume_whitespace(false)?;
 
        let body = self.consume_block_statement(h)?;
 
        Ok(h.alloc_function(|this| Function {
 
@@ -2069,32 +2118,47 @@ mod tests {
 
        }
 
        let lexed = lexed.unwrap();
 
        let root = &h[lexed];
 

	
 
        assert_eq!(root.definitions.len(), 2);
 

	
 
        let symbolic_type = |v: &PrimitiveType| -> Vec<u8> {
 
            if let PrimitiveType::Symbolic(v) = v {
 
                v.identifier.value.clone()
 
            } else {
 
                assert!(false);
 
                unreachable!();
 
            }
 
        };
 

	
 
        let foo_def = h[root.definitions[0]].as_struct();
 
        assert_eq!(foo_def.identifier.value, b"Foo");
 
        assert_eq!(foo_def.fields.len(), 3);
 
        assert_eq!(foo_def.fields[0].field.value, b"one");
 
        assert_eq!(h[foo_def.fields[0].the_type].the_type, Type::BYTE);
 
        assert_eq!(foo_def.fields[1].field.value, b"two");
 
        assert_eq!(h[foo_def.fields[1].the_type].the_type, Type::SHORT);
 
        assert_eq!(foo_def.fields[2].field.value, b"three");
 
        assert_eq!(h[foo_def.fields[2].the_type].the_type.primitive, PrimitiveType::Symbolic(Vec::from("Bar".as_bytes())));
 
        assert_eq!(
 
            symbolic_type(&h[foo_def.fields[2].the_type].the_type.primitive), 
 
            Vec::from("Bar".as_bytes())
 
        );
 

	
 
        let bar_def = h[root.definitions[1]].as_struct();
 
        assert_eq!(bar_def.identifier.value, b"Bar");
 
        assert_eq!(bar_def.fields.len(), 3);
 
        assert_eq!(bar_def.fields[0].field.value, b"one");
 
        assert_eq!(h[bar_def.fields[0].the_type].the_type, Type::INT_ARRAY);
 
        assert_eq!(bar_def.fields[1].field.value, b"two");
 
        assert_eq!(h[bar_def.fields[1].the_type].the_type, Type::INT_ARRAY);
 
        assert_eq!(bar_def.fields[2].field.value, b"three");
 
        assert_eq!(h[bar_def.fields[2].the_type].the_type.array, true);
 
        assert_eq!(h[bar_def.fields[2].the_type].the_type.primitive, PrimitiveType::Symbolic(Vec::from("Qux".as_bytes())));
 
        assert_eq!(
 
            symbolic_type(&h[bar_def.fields[2].the_type].the_type.primitive), 
 
            Vec::from("Qux".as_bytes())
 
        );
 
    }
 

	
 
    #[test]
 
    fn test_enum_definition() {
 
        let mut h = Heap::new();
 
        let mut input = InputSource::from_string("
 
@@ -2148,13 +2212,16 @@ mod tests {
 
        assert_eq!(qux_def.identifier.value, b"Qux");
 
        assert_eq!(qux_def.variants.len(), 3);
 
        assert_eq!(qux_def.variants[0].identifier.value, b"A");
 
        assert_eq!(enum_type(&qux_def.variants[0].value).the_type, Type::BYTE_ARRAY);
 
        assert_eq!(qux_def.variants[1].identifier.value, b"B");
 
        assert_eq!(enum_type(&qux_def.variants[1].value).the_type.array, true);
 
        assert_eq!(enum_type(&qux_def.variants[1].value).the_type.primitive, PrimitiveType::Symbolic(Vec::from("Bar".as_bytes())));
 
        if let PrimitiveType::Symbolic(t) = &enum_type(&qux_def.variants[1].value).the_type.primitive {
 
            assert_eq!(t.identifier.value, Vec::from("Bar".as_bytes()));
 
        } else { assert!(false) }
 

	
 
        assert_eq!(qux_def.variants[2].identifier.value, b"C");
 
        assert_eq!(enum_type(&qux_def.variants[2].value).the_type, Type::BYTE);
 
    }
 

	
 
//     #[test]
 
//     fn test_lowercase() {
src/protocol/parser/depth_visitor.rs
Show inline comments
 
@@ -27,16 +27,16 @@ pub(crate) trait Visitor: Sized {
 
    fn visit_enum_definition(&mut self, h: &mut Heap, def: EnumId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_component_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        recursive_component_definition(self, h, def)
 
    }
 
    fn visit_composite_definition(&mut self, h: &mut Heap, def: CompositeId) -> VisitorResult {
 
    fn visit_composite_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        recursive_composite_definition(self, h, def)
 
    }
 
    fn visit_primitive_definition(&mut self, h: &mut Heap, def: PrimitiveId) -> VisitorResult {
 
    fn visit_primitive_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        recursive_primitive_definition(self, h, def)
 
    }
 
    fn visit_function_definition(&mut self, h: &mut Heap, def: FunctionId) -> VisitorResult {
 
        recursive_function_definition(self, h, def)
 
    }
 

	
 
@@ -233,43 +233,44 @@ fn recursive_symbol_definition<T: Visitor>(
 
) -> VisitorResult {
 
    // We clone the definition in case it is modified
 
    // TODO: Fix me
 
    match h[def].clone() {
 
        Definition::Struct(def) => this.visit_struct_definition(h, def.this),
 
        Definition::Enum(def) => this.visit_enum_definition(h, def.this),
 
        Definition::Component(cdef) => this.visit_component_definition(h, cdef.this()),
 
        Definition::Component(cdef) => this.visit_component_definition(h, cdef.this),
 
        Definition::Function(fdef) => this.visit_function_definition(h, fdef.this),
 
    }
 
}
 

	
 
fn recursive_component_definition<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    def: ComponentId,
 
) -> VisitorResult {
 
    match h[def].clone() {
 
        Component::Composite(cdef) => this.visit_composite_definition(h, cdef.this),
 
        Component::Primitive(pdef) => this.visit_primitive_definition(h, pdef.this),
 
    let component_variant = h[def].variant;
 
    match component_variant {
 
        ComponentVariant::Primitive => this.visit_primitive_definition(h, def),
 
        ComponentVariant::Composite => this.visit_composite_definition(h, def),
 
    }
 
}
 

	
 
fn recursive_composite_definition<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    def: CompositeId,
 
    def: ComponentId,
 
) -> VisitorResult {
 
    for &param in h[def].parameters.clone().iter() {
 
        recursive_parameter_as_variable(this, h, param)?;
 
    }
 
    this.visit_statement(h, h[def].body)
 
}
 

	
 
fn recursive_primitive_definition<T: Visitor>(
 
    this: &mut T,
 
    h: &mut Heap,
 
    def: PrimitiveId,
 
    def: ComponentId,
 
) -> VisitorResult {
 
    for &param in h[def].parameters.clone().iter() {
 
        recursive_parameter_as_variable(this, h, param)?;
 
    }
 
    this.visit_statement(h, h[def].body)
 
}
 
@@ -548,13 +549,13 @@ impl NestedSynchronousStatements {
 
    pub(crate) fn new() -> Self {
 
        NestedSynchronousStatements { illegal: false }
 
    }
 
}
 

	
 
impl Visitor for NestedSynchronousStatements {
 
    fn visit_composite_definition(&mut self, h: &mut Heap, def: CompositeId) -> VisitorResult {
 
    fn visit_composite_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        assert!(!self.illegal);
 
        self.illegal = true;
 
        recursive_composite_definition(self, h, def)?;
 
        self.illegal = false;
 
        Ok(())
 
    }
 
@@ -594,13 +595,13 @@ impl ChannelStatementOccurrences {
 
    pub(crate) fn new() -> Self {
 
        ChannelStatementOccurrences { illegal: false }
 
    }
 
}
 

	
 
impl Visitor for ChannelStatementOccurrences {
 
    fn visit_primitive_definition(&mut self, h: &mut Heap, def: PrimitiveId) -> VisitorResult {
 
    fn visit_primitive_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        assert!(!self.illegal);
 
        self.illegal = true;
 
        recursive_primitive_definition(self, h, def)?;
 
        self.illegal = false;
 
        Ok(())
 
    }
 
@@ -692,13 +693,13 @@ impl Visitor for ComponentStatementReturnNew {
 
        assert!(!(self.illegal_new || self.illegal_return));
 
        self.illegal_return = true;
 
        recursive_component_definition(self, h, def)?;
 
        self.illegal_return = false;
 
        Ok(())
 
    }
 
    fn visit_primitive_definition(&mut self, h: &mut Heap, def: PrimitiveId) -> VisitorResult {
 
    fn visit_primitive_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        assert!(!self.illegal_new);
 
        self.illegal_new = true;
 
        recursive_primitive_definition(self, h, def)?;
 
        self.illegal_new = false;
 
        Ok(())
 
    }
 
@@ -846,22 +847,31 @@ impl LinkCallExpressions {
 
    ) -> Result<DeclarationId, VisitorError> {
 
        match h[self.pd.unwrap()].get_declaration(h, &id) {
 
            Some(id) => Ok(id),
 
            None => Err((id.position, "Unresolved method".to_string())),
 
        }
 
    }
 
    fn get_declaration_namespaced(
 
        &self, h: &Heap, id: &NamespacedIdentifier
 
    ) -> Result<DeclarationId, VisitorError> {
 
        // TODO: @fixme
 
        match h[self.pd.unwrap()].get_declaration_namespaced(h, id) {
 
            Some(id) => Ok(id),
 
            None => Err((id.position, "Unresolved method".to_string()))
 
        }
 
    }
 
}
 

	
 
impl Visitor for LinkCallExpressions {
 
    fn visit_protocol_description(&mut self, h: &mut Heap, pd: RootId) -> VisitorResult {
 
        self.pd = Some(pd);
 
        recursive_protocol_description(self, h, pd)?;
 
        self.pd = None;
 
        Ok(())
 
    }
 
    fn visit_composite_definition(&mut self, h: &mut Heap, def: CompositeId) -> VisitorResult {
 
    fn visit_composite_definition(&mut self, h: &mut Heap, def: ComponentId) -> VisitorResult {
 
        assert!(!self.composite);
 
        self.composite = true;
 
        recursive_composite_definition(self, h, def)?;
 
        self.composite = false;
 
        Ok(())
 
    }
 
@@ -873,18 +883,18 @@ impl Visitor for LinkCallExpressions {
 
        self.new_statement = false;
 
        Ok(())
 
    }
 
    fn visit_call_expression(&mut self, h: &mut Heap, expr: CallExpressionId) -> VisitorResult {
 
        if let Method::Symbolic(id) = &h[expr].method {
 
            // TODO: @symbol_table
 
            let decl = self.get_declaration(h, id)?;
 
            let decl = self.get_declaration_namespaced(h, &id.identifier)?;
 
            if self.new_statement && h[decl].is_function() {
 
                return Err((id.position, "Illegal call expression".to_string()));
 
                return Err((id.identifier.position, "Illegal call expression".to_string()));
 
            }
 
            if !self.new_statement && h[decl].is_component() {
 
                return Err((id.position, "Illegal call expression".to_string()));
 
                return Err((id.identifier.position, "Illegal call expression".to_string()));
 
            }
 
            // Set the corresponding declaration of the call
 
            h[expr].declaration = Some(decl);
 
        }
 
        // A new statement's call expression may have as arguments function calls
 
        let old = self.new_statement;
src/protocol/parser/symbol_table.rs
Show inline comments
 
// TODO: Maybe allow namespaced-aliased imports. It is currently not possible
 
//  to express the following:
 
//      import Module.Submodule as SubMod
 
//      import SubMod::{Symbol}
 
//  And it is especially not possible to express the following:
 
//      import SubMod::{Symbol}
 
//      import Module.Submodule as SubMod
 
use crate::protocol::ast::*;
 
use crate::protocol::inputsource::*;
 

	
 
use std::collections::{HashMap, hash_map::Entry};
 
use crate::protocol::parser::LexedModule;
 

	
 
@@ -15,17 +22,23 @@ pub(crate) enum Symbol {
 
    Definition((RootId, DefinitionId)),
 
}
 

	
 
pub(crate) struct SymbolValue {
 
    // Position refers to the origin of the symbol definition (i.e. the module's
 
    // RootId that is in the key being used to lookup this value)
 
    position: InputPosition,
 
    symbol: Symbol,
 
    pub(crate) position: InputPosition,
 
    pub(crate) symbol: Symbol,
 
}
 

	
 
impl SymbolValue {
 
    pub(crate) fn is_namespace(&self) -> bool {
 
        match &self.symbol {
 
            Symbol::Namespace(_) => true,
 
            _ => false
 
        }
 
    }
 
    pub(crate) fn as_namespace(&self) -> Option<RootId> {
 
        match &self.symbol {
 
            Symbol::Namespace(root_id) => Some(*root_id),
 
            _ => None,
 
        }
 
    }
 
@@ -45,16 +58,12 @@ impl SymbolValue {
 
/// or if a symbol cannot be resolved this will be an error.
 
///
 
/// Within the compilation process the symbol table is responsible for resolving
 
/// namespaced identifiers (e.g. Module::Enum::EnumVariant) to the appropriate
 
/// definition (i.e. not namespaces; as the language has no way to use
 
/// namespaces except for using them in namespaced identifiers).
 
// TODO: Maybe allow namespaced-aliased imports. It is currently not possible
 
//  to express the following:
 
//  import Module.Submodule as ModSub
 
//  import SubMod::{Symbol}
 
pub(crate) struct SymbolTable {
 
    // Lookup from module name (not any aliases) to the root id
 
    module_lookup: HashMap<Vec<u8>, RootId>,
 
    // Lookup from within a module, to a particular imported (potentially
 
    // aliased) or defined symbol. Basically speaking: if the source code of a
 
    // module contains correctly imported/defined symbols, then this lookup
 
@@ -280,22 +289,89 @@ impl SymbolTable {
 
    /// actually finding a definition or a namespace. So a namespace might be
 
    /// resolved, after it which it finds an actual definition. It may be that
 
    /// the namespaced identifier has more elements that should be checked
 
    /// (i.e. an enum variant, or simply an erroneous instance of too many
 
    /// chained identifiers). This function will return None if nothing could be
 
    /// resolved at all.
 
    pub(crate) fn resolve_namespaced_symbol(&self, _within_module_id: RootId) {
 
        todo!("implement")
 
    pub(crate) fn resolve_namespaced_symbol<'t, 'i>(
 
        &'t self, root_module_id: RootId, identifier: &'i NamespacedIdentifier
 
    ) -> Option<(&SymbolValue, NamespacedIdentifierIter<'i>)> {
 
        let mut iter = identifier.iter();
 
        let mut symbol: Option<&SymbolValue> = None;
 
        let mut within_module_id = root_module_id;
 
        while let Some(partial) = iter.next() {
 
            // Lookup the symbol within the currently iterated upon module
 
            let lookup_key = SymbolKey{ module_id: within_module_id, symbol_name: Vec::from(partial) };
 
            let new_symbol = self.symbol_lookup.get(&lookup_key);
 
            
 
            match new_symbol {
 
                None => {
 
                    // Can't find anything
 
                    break; 
 
                },
 
                Some(new_symbol) => {
 
                    // Found something, but if we already moved to another
 
                    // module then we don't want to keep jumping across modules,
 
                    // we're only interested in symbols defined within that
 
                    // module.
 
                    match &new_symbol.symbol {
 
                        Symbol::Namespace(new_root_id) => {
 
                            if root_module_id != within_module_id {
 
                                // Don't jump from module to module, keep the
 
                                // old symbol (which must be a Namespace) and
 
                                // break
 
                                debug_assert!(symbol.is_some());
 
                                debug_assert!(symbol.unwrap().is_namespace());
 
                                debug_assert!(iter.num_returned() > 1);
 

	
 
                                // For handling this error, we need to revert
 
                                // the iterator by one
 
                                let to_skip = iter.num_returned() - 1;
 
                                iter = identifier.iter();
 
                                for _ in 0..to_skip { iter.next(); }
 
                                break;
 
                            }
 

	
 
                            within_module_id = *new_root_id;
 
                            symbol = Some(new_symbol);
 
                        },
 
                        Symbol::Definition((definition_root_id, _)) => {
 
                            // Found a definition, but if we already jumped
 
                            // modules, then this must be defined within that
 
                            // module.
 
                            if root_module_id != within_module_id && within_module_id != *definition_root_id {
 
                                // This is an imported definition within the module
 
                                // TODO: Maybe factor out? Dunno...
 
                                debug_assert!(symbol.is_some());
 
                                debug_assert!(symbol.unwrap().is_namespace());
 
                                debug_assert!(iter.num_returned() > 1);
 
                                let to_skip = iter.num_returned() - 1;
 
                                iter = identifier.iter();
 
                                for _ in 0..to_skip { iter.next(); }
 
                                break;
 
                            }
 
                            symbol = Some(new_symbol);
 
                            break;
 
                        }
 
                    }
 
                }
 
            }
 
        }
 

	
 
        match symbol {
 
            None => None,
 
            Some(symbol) => Some((symbol, iter))
 
        }
 
    }
 

	
 
    /// Attempts to add a namespace symbol. Returns `Ok` if the symbol was
 
    /// inserted. If the symbol already exists then `Err` will be returned
 
    /// together with the previous definition's source position (in the origin
 
    /// module's source file).
 
    // Note: I would love to return a reference to the value, but Rust is
 
    // preventing me from doing so...
 
    // preventing me from doing so... That, or I'm not smart enough...
 
    fn add_namespace_symbol(
 
        &mut self, origin_module_id: RootId, origin_position: InputPosition, symbol_name: &Vec<u8>, target_module_id: RootId
 
    ) -> Result<(), InputPosition> {
 
        let key = SymbolKey{
 
            module_id: origin_module_id,
 
            symbol_name: symbol_name.clone()
src/protocol/parser/type_table.rs
Show inline comments
 
// TODO: @fix PrimitiveType for enums/unions
 
use crate::protocol::ast::*;
 
use crate::protocol::parser::symbol_table::*;
 
use crate::protocol::parser::symbol_table::{SymbolTable, Symbol};
 
use crate::protocol::inputsource::*;
 
use crate::protocol::parser::*;
 

	
 
use std::collections::HashMap;
 

	
 

	
 
enum DefinedType {
 
pub enum DefinedType {
 
    Enum(EnumType),
 
    Union(UnionType),
 
    Struct(StructType),
 
    Function(FunctionType),
 
    Component(ComponentType)
 
}
 

	
 
// TODO: Also support maximum u64 value
 
struct EnumVariant {
 
pub struct EnumVariant {
 
    identifier: Identifier,
 
    value: i64,
 
}
 

	
 
/// `EnumType` is the classical C/C++ enum type. It has various variants with
 
/// an assigned integer value. The integer values may be user-defined,
 
/// compiler-defined, or a mix of the two. If a user assigns the same enum
 
/// value multiple times, we assume the user is an expert and we consider both
 
/// variants to be equal to one another.
 
struct EnumType {
 
    definition: DefinitionId,
 
pub struct EnumType {
 
    variants: Vec<EnumVariant>,
 
    representation: PrimitiveType,
 
}
 

	
 
struct UnionVariant {
 
pub struct UnionVariant {
 
    identifier: Identifier,
 
    embedded_type: Option<DefinitionId>,
 
    embedded_type: Option<TypeAnnotationId>,
 
    tag_value: i64,
 
}
 

	
 
struct UnionType {
 
    definition: DefinitionId,
 
    variants: Vec<EnumVariant>,
 
pub struct UnionType {
 
    variants: Vec<UnionVariant>,
 
    tag_representation: PrimitiveType
 
}
 

	
 
struct StructMemberType {
 
pub struct StructField {
 
    identifier: Identifier,
 
    field_type: TypeAnnotationId,
 
}
 

	
 
pub struct StructType {
 
    fields: Vec<StructField>,
 
}
 

	
 
pub struct FunctionArgument {
 
    identifier: Identifier,
 
    argument_type: TypeAnnotationId,
 
}
 

	
 
struct StructType {
 
pub struct FunctionType {
 
    return_type: Type,
 
    arguments: Vec<FunctionArgument>
 
}
 

	
 
pub struct ComponentType {
 
    variant: ComponentVariant,
 
    arguments: Vec<FunctionArgument>
 
}
 

	
 
pub struct TypeTable {
 
    lookup: HashMap<DefinitionId, DefinedType>,
 
}
 

	
 
enum LookupResult {
 
    BuiltIn,
 
    Resolved((RootId, DefinitionId)),
 
    Unresolved((RootId, DefinitionId)),
 
    Error((InputPosition, String)),
 
}
 

	
 
struct FunctionType {
 
/// `TypeTable` is responsible for walking the entire lexed AST and laying out
 
/// the various user-defined types in terms of bytes and offsets. This process
 
/// may be pseudo-recursive (meaning: it is implemented in a recursive fashion,
 
/// but not in the recursive-function-call kind of way) in case a type depends
 
/// on another type to be resolved.
 
/// TODO: Distinction between resolved types and unresolved types (regarding the
 
///     mixed use of BuiltIns and resolved types) is a bit yucky at the moment,
 
///     will have to come up with something nice in the future.
 
/// TODO: Need to factor out the repeated lookup in some kind of state machine.
 
impl TypeTable {
 
    fn new(
 
        symbols: &SymbolTable, heap: &Heap, modules: &[LexedModule]
 
    ) -> Result<TypeTable, ParseError2> {
 
        if cfg!(debug_assertions) {
 
            for (index, module) in modules.iter().enumerate() {
 
                debug_assert_eq!(index, module.root_id.0.index as usize)
 
            }
 
        }
 

	
 
        // Estimate total number of definitions we will encounter
 
        let num_definitions = heap.definitions.len();
 
        let mut table = TypeTable{
 
            lookup: HashMap::with_capacity(num_definitions),
 
        };
 

	
 
        // Perform the breadcrumb-based type parsing. For now we do not allow
 
        // cyclic types. 
 
        // TODO: Allow cyclic types. However, we want to have an implementation
 
        //  that is somewhat efficient: if a type is cyclic, then we have to
 
        //  insert a pointer somewhere. However, we don't want to insert them
 
        //  everywhere, for each possible type. Without any further context the
 
        //  decision to place a pointer somewhere is "random", we need to know
 
        //  how the type is used to have an informed opinion on where to place
 
        //  the pointer.
 
        enum Breadcrumb {
 
            Linear((usize, usize)),
 
            Jumping((RootId, DefinitionId))
 
        }
 

	
 
        let mut module_index = 0;
 
        let mut definition_index = 0;
 
        let mut breadcrumbs = Vec::with_capacity(32); // if a user exceeds this, the user sucks at programming
 
        while module_index < modules.len() {
 
            // Go to next module if needed
 
            {
 
                let root = &heap[modules[module_index].root_id];
 
                if definition_index >= root.definitions.len() {
 
                    module_index += 1;
 
                    definition_index = 0;
 
                    continue;
 
                }
 
            }
 

	
 
            // Construct breadcrumbs in case we need to follow some types around
 
            debug_assert!(breadcrumbs.is_empty());
 
            breadcrumbs.push(Breadcrumb::Linear((module_index, definition_index)));
 
            'resolve_loop: while !breadcrumbs.is_empty() {
 
                // Retrieve module, the module's root and the definition
 
                let (module, root, definition_id) = match breadcrumbs.last().unwrap() {
 
                    Breadcrumb::Linear((module_index, definition_index)) => {
 
                        let module = &modules[*module_index];
 
                        let root = &heap[module.root_id];
 
                        let definition_id = root.definitions[*definition_index];
 
                        (module, root, definition_id)
 
                    },
 
                    Breadcrumb::Jumping((root_id, definition_id)) => {
 
                        let module = &modules[root_id.0.index as usize];
 
                        debug_assert_eq!(module.root_id, *root_id);
 
                        let root = &heap[*root_id];
 
                        (module, root, *definition_id)
 
                    }
 
                };
 

	
 
                let definition = &heap[definition_id];
 

	
 
                // Because we might have chased around to this particular 
 
                // definition before, we check if we haven't resolved the type
 
                // already.
 
                if table.lookup.contains_key(&definition_id) {
 
                    breadcrumbs.pop();
 
                    continue;
 
                }
 

	
 
                match definition {
 
                    Definition::Enum(definition) => {
 
                        // Check the definition to see if we're dealing with an
 
                        // enum or a union. If we find any union variants then
 
                        // we immediately check if the type is already resolved.
 
                        let mut has_tag_values = None;
 
                        let mut has_int_values = None;
 
                        for variant in &definition.variants {
 
                            match &variant.value {
 
                                EnumVariantValue::None => {},
 
                                EnumVariantValue::Integer(_) => {
 
                                    if has_int_values.is_none() { has_int_values = Some(variant.position); }
 
                                 },
 
                                EnumVariantValue::Type(variant_type) => { 
 
                                    if has_tag_values.is_none() { has_tag_values = Some(variant.position); }
 

	
 
                                    let variant_type = &heap[*variant_type];
 
                                    match lookup_type_definition(
 
                                        heap, &table, symbols, module.root_id,
 
                                        &variant_type.the_type.primitive
 
                                    ) {
 
                                        LookupResult::BuiltIn | LookupResult::Resolved(_) => {},
 
                                        LookupResult::Unresolved(root_and_definition_id) => {
 
                                            breadcrumbs.push(Breadcrumb::Jumping(root_and_definition_id));
 
                                            continue 'resolve_loop;
 
                                        },
 
                                        LookupResult::Error((position, message)) => {
 
                                            return Err(ParseError2::new_error(&module.source, position, &message));
 
                                        }
 
                                    }
 
                                },
 
                            }
 
                        }
 

	
 
                        if has_tag_values.is_some() && has_int_values.is_some() {
 
                            // Not entirely illegal, but probably not desired
 
                            let tag_pos = has_tag_values.unwrap();
 
                            let int_pos = has_int_values.unwrap();
 
                            return Err(
 
                                ParseError2::new_error(&module.source, definition.position, "Illegal combination of enum integer variant(s) and enum union variant(s)")
 
                                .with_postfixed_info(&module.source, int_pos, "Explicitly assigning an integer value here")
 
                                .with_postfixed_info(&module.source, tag_pos, "Explicitly declaring a union variant here")
 
                            )
 
                        }
 

	
 
                        // If here, then the definition is a valid discriminated
 
                        // union with all of its types resolved, or a valid
 
                        // enum.
 

	
 
                        // Decide whether to implement as enum or as union
 
                        let is_union = has_tag_values.is_some();
 
                        if is_union {
 
                            // Implement as discriminated union. Because we 
 
                            // checked the availability of types above, we are
 
                            // safe to lookup type definitions
 
                            let mut tag_value = -1;
 
                            let mut variants = Vec::with_capacity(definition.variants.len());
 
                            for variant in &definition.variants {
 
                                tag_value += 1;
 
                                let embedded_type = match &variant.value {
 
                                    EnumVariantValue::None => {
 
                                        None
 
                                    },
 
                                    EnumVariantValue::Type(type_annotation_id) => {
 
                                        // Type should be resolvable, we checked this above
 
                                        let type_annotation = &heap[*type_annotation_id];
 
                                        // TODO: Remove the assert once I'm clear on how to layout "the types" of types
 
                                        if cfg!(debug_assertions) {
 
                                            ensure_type_definition(heap, &table, symbols, module.root_id, &type_annotation.the_type.primitive);
 
                                        }
 

	
 
                                        Some(*type_annotation_id)
 
                                    },
 
                                    EnumVariantValue::Integer(_) => {
 
                                        debug_assert!(false, "Encountered `Integer` variant after asserting enum is a discriminated union");
 
                                        unreachable!();
 
                                    }
 
                                };
 

	
 
                                variants.push(UnionVariant{
 
                                    identifier: variant.identifier.clone(),
 
                                    embedded_type,
 
                                    tag_value,
 
                                })
 
                            }
 

	
 
                            table.add_definition(definition_id, DefinedType::Union(UnionType{
 
                                variants,
 
                                tag_representation: enum_representation(tag_value)
 
                            }));
 
                        } else {
 
                            // Implement as regular enum
 
                            let mut enum_value = -1; // TODO: allow u64 max size
 
                            let mut variants = Vec::with_capacity(definition.variants.len());
 
                            for variant in &definition.variants {
 
                                enum_value += 1;
 
                                match &variant.value {
 
                                    EnumVariantValue::None => {
 
                                        variants.push(EnumVariant{
 
                                            identifier: variant.identifier.clone(),
 
                                            value: enum_value,
 
                                        });
 
                                    },
 
                                    EnumVariantValue::Integer(override_value) => {
 
                                        enum_value = *override_value;
 
                                        variants.push(EnumVariant{
 
                                            identifier: variant.identifier.clone(),
 
                                            value: enum_value,
 
                                        });
 
                                    },
 
                                    EnumVariantValue::Type(_) => {
 
                                        debug_assert!(false, "Encountered `Type` variant after asserting enum is not a discriminated union");
 
                                        unreachable!();
 
                                    }
 
                                }
 
                            }
 

	
 
                            table.add_definition(definition_id, DefinedType::Enum(EnumType{
 
                                variants,
 
                                representation: enum_representation(enum_value),
 
                            }));
 
                        }
 
                    },
 
                    Definition::Struct(definition) => {
 
                        // Before we start allocating fields, make sure we can
 
                        // actually resolve all of the field types
 
                        for field_definition in &definition.fields {
 
                            let type_definition = &heap[field_definition.the_type];
 
                            match lookup_type_definition(
 
                                heap, &table, symbols, module.root_id,
 
                                &type_definition.the_type.primitive
 
                            ) {
 
                                LookupResult::BuiltIn | LookupResult::Resolved(_) => {},
 
                                LookupResult::Unresolved(root_and_definition_id) => {
 
                                    breadcrumbs.push(Breadcrumb::Jumping(root_and_definition_id));
 
                                    continue 'resolve_loop;
 
                                },
 
                                LookupResult::Error((position, message)) => {
 
                                    return Err(ParseError2::new_error(&module.source, position, &message));
 
                                }
 
                            }
 
                        }
 

	
 
                        // We can resolve everything
 
                        let mut fields = Vec::with_capacity(definition.fields.len());
 
                        for field_definition in &definition.fields {
 
                            let type_annotation = &heap[field_definition.the_type];
 
                            if cfg!(debug_assertions) {
 
                                ensure_type_definition(heap, &table, symbols, module.root_id, &type_annotation.the_type.primitive);
 
                            }
 

	
 
                            fields.push(StructField{
 
                                identifier: field_definition.field.clone(),
 
                                field_type: field_definition.the_type
 
                            });
 
                        }
 

	
 
                        table.add_definition(definition_id, DefinedType::Struct(StructType{
 
                            fields,
 
                        }));
 
                    },
 
                    Definition::Component(definition) => {
 
                        // As always, ensure all parameter types are resolved
 
                        for parameter_id in &definition.parameters {
 
                            let parameter = &heap[*parameter_id];
 
                            let type_definition = &heap[parameter.type_annotation];
 
                            match lookup_type_definition(
 
                                heap, &table, symbols, module.root_id,
 
                                &type_definition.the_type.primitive
 
                            ) {
 
                                LookupResult::BuiltIn | LookupResult::Resolved(_) => {},
 
                                LookupResult::Unresolved(root_and_definition_id) => {
 
                                    breadcrumbs.push(Breadcrumb::Jumping(root_and_definition_id));
 
                                    continue 'resolve_loop;
 
                                },
 
                                LookupResult::Error((position, message)) => {
 
                                    return Err(ParseError2::new_error(&module.source, position, &message));
 
                                }
 
                            }
 
                        }
 

	
 
                        // We can resolve everything
 
                        let mut parameters = Vec::with_capacity(definition.parameters.len());
 
                        for parameter_id in &definition.parameters {
 
                            let parameter = &heap[*parameter_id];
 
                            let type_definition = &heap[parameter.type_annotation];
 
                            if cfg!(debug_assertions) {
 
                                ensure_type_definition(heap, &table, symbols, module.root_id, &type_definition.the_type.primitive);
 
                            }
 

	
 
                            parameters.push(FunctionArgument{
 
                                identifier: parameter.identifier.clone(),
 
                                argument_type: parameter.type_annotation,
 
                            });
 
                        }
 

	
 
                        table.add_definition(definition_id, DefinedType::Component(ComponentType{
 
                            variant: definition.variant,
 
                            arguments: parameters, // Arguments, parameters, tomayto, tomahto
 
                        }));
 
                    },
 
                    Definition::Function(definition) => {
 
                        // TODO: Onto the last one!
 
                    },
 
                }
 

	
 
                // If here, then we layed out the current type definition under
 
                // investigation, so:
 
                debug_assert!(!breadcrumbs.is_empty());
 
                breadcrumbs.pop();
 
            }
 

	
 
            // Go to next definition
 
            definition_index += 1;
 
        }
 

	
 
        debug_assert_eq!(
 
            num_definitions, table.lookup.len(),
 
            "expected {} (reserved) definitions in table, got {}",
 
            num_definitions, table.lookup.len()
 
        );
 

	
 
        Ok(table)
 
    }
 

	
 
    pub(crate) fn get_definition(&self, definition_id: &DefinitionId) -> Option<&DefinedType> {
 
        self.lookup.get(definition_id)
 
    }
 

	
 
    fn add_definition(&mut self, definition_id: DefinitionId, definition: DefinedType) {
 
        debug_assert!(!self.lookup.contains_key(&definition_id), "already added definition");
 
        self.lookup.insert(definition_id, definition);
 
    }
 
}
 

	
 
struct ComponentType {
 
/// Attempts to lookup a type definition using a namespaced identifier. We have
 
/// three success cases: the first is simply that the type is a `BuiltIn` type.
 
/// In the two other cases both we find the definition of the type in the symbol
 
/// table, but in one case it is already `Resolved` in the type table, and in
 
/// the other case it is `Unresolved`. In this last case the type has to be
 
/// resolved before we're able to use it in the `TypeTable` construction
 
/// algorithm.
 
/// In the `Error` case something goes wrong with resolving the type. The error
 
/// message aims to be as helpful as possible to the user.
 
/// The caller should ensure that the `module_root` is where the `identifier`
 
/// lives.
 
fn lookup_type_definition(
 
    heap: &Heap, types: &TypeTable, symbols: &SymbolTable,
 
    module_root: RootId, type_to_resolve: &PrimitiveType
 
) -> LookupResult {
 
    if let PrimitiveType::Symbolic(type_to_resolve) = type_to_resolve {
 
        let identifier = &type_to_resolve.identifier;
 

	
 
        match symbols.resolve_namespaced_symbol(module_root, identifier) {
 
            None => {
 
                // Failed to find anything at all
 
                LookupResult::Error((identifier.position, String::from("Unknown type")))
 
            },
 
            Some((symbol, mut identifier_iter)) => {
 
                match symbol.symbol {
 
                    Symbol::Namespace(_root_id) => {
 
                        // Reference to a namespace, which is not a type. However,
 
                        // the error message depends on whether we have identifiers
 
                        // remaining or not
 
                        if identifier_iter.num_remaining() == 0 {
 
                            LookupResult::Error((
 
                                identifier.position,
 
                                String::from("Expected a type, got a module name")
 
                            ))
 
                        } else {
 
                            let next_identifier = identifier_iter.next().unwrap();
 
                            LookupResult::Error((
 
                                identifier.position,
 
                                format!("Cannot find symbol '{}' in this module", String::from_utf8_lossy(next_identifier))
 
                            ))
 
                        }
 
                    },
 
                    Symbol::Definition((definition_root_id, definition_id)) => {
 
                        // Got a definition, but we may also have more identifier's
 
                        // remaining in the identifier iterator
 
                        let definition = &heap[definition_id];
 
                        if identifier_iter.num_remaining() == 0 {
 
                            // See if the type is resolved, and make sure it is
 
                            // a non-function, non-component type. Ofcourse
 
                            // these are valid types, but we cannot (yet?) use
 
                            // them as function arguments, struct fields or enum
 
                            // variants
 
                            match definition {
 
                                Definition::Component(definition) => {
 
                                    return LookupResult::Error((
 
                                        identifier.position,
 
                                        format!(
 
                                            "Cannot use the component '{}' as an embedded type",
 
                                            String::from_utf8_lossy(&definition.identifier.value)
 
                                        )
 
                                    ));
 
                                },
 
                                Definition::Function(definition) => {
 
                                    return LookupResult::Error((
 
                                        identifier.position,
 
                                        format!(
 
                                            "Cannot use the function '{}' as an embedded type",
 
                                            String::from_utf8_lossy(&definition.identifier.value)
 
                                        )
 
                                    ));
 
                                },
 
                                Definition::Enum(_) | Definition::Struct(_) => {}
 
                            }
 

	
 
                            return if types.lookup.contains_key(&definition_id) {
 
                                LookupResult::Resolved((definition_root_id, definition_id))
 
                            } else {
 
                                LookupResult::Unresolved((definition_root_id, definition_id))
 
                            }
 
                        } else if identifier_iter.num_remaining() == 1 {
 
                            // This is always invalid, but if the type is an
 
                            // enumeration or a union then we want to return a
 
                            // different error message.
 
                            if definition.is_enum() {
 
                                let last_identifier = identifier_iter.next().unwrap();
 
                                return LookupResult::Error((
 
                                    identifier.position,
 
                                    format!(
 
                                        "Expected a type, but got a (possible) enum variant '{}'. Only the enum '{}' itself can be used as a type",
 
                                        String::from_utf8_lossy(last_identifier),
 
                                        String::from_utf8_lossy(&definition.identifier().value)
 
                                    )
 
                                ));
 
                            }
 
                        }
 

	
 
                        // Too much identifiers (>1) for an enumeration, or not an
 
                        // enumeration and we had more identifiers remaining
 
                        LookupResult::Error((
 
                            identifier.position,
 
                            format!(
 
                                "Unknown type '{}', did you mean to use '{}'?",
 
                                String::from_utf8_lossy(&identifier.value),
 
                                String::from_utf8_lossy(&definition.identifier().value)
 
                            )
 
                        ))
 
                    }
 
                }
 
            }
 
        }
 
    } else {
 
        LookupResult::BuiltIn
 
    }
 
}
 

	
 
struct TypeTable {
 
    lookup: HashMap<DefinitionId, DefinedType>,
 
/// Debugging function to ensure a type is resolved (calling
 
/// `lookup_type_definition` and ensuring its return value is `BuiltIn` or
 
/// `Resolved`
 
#[cfg(debug_assertions)]
 
fn ensure_type_definition(
 
    heap: &Heap, types: &TypeTable, symbols: &SymbolTable,
 
    module_root: RootId, type_to_resolve: &PrimitiveType
 
) {
 
    match lookup_type_definition(heap, types, symbols, module_root, type_to_resolve) {
 
        LookupResult::BuiltIn | LookupResult::Resolved(_) => {},
 
        LookupResult::Unresolved((_, definition_id)) => {
 
            assert!(
 
                false,
 
                "Expected that type definition for {} was resolved by the type table, but it wasn't",
 
                String::from_utf8_lossy(&heap[definition_id].identifier().value)
 
            )
 
        },
 
        LookupResult::Error((_, error)) => {
 
            let message = if let PrimitiveType::Symbolic(symbolic) = type_to_resolve {
 
                format!(
 
                    "Expected that type definition for {} was resolved by the type table, but it returned: {}",
 
                    String::from_utf8_lossy(&symbolic.identifier.value), &error
 
                )
 
            } else {
 
                format!(
 
                    "Expected (non-symbolic!?) type definition to be resolved, but it returned: {}",
 
                    &error
 
                )
 
            };
 
            assert!(false, "{}", message)
 
        }
 
    }
 
}
 

	
 
/// Determines an enumeration's integer representation type, or a union's tag
 
/// type, using the maximum value of the tag. The returned type is always a
 
/// builtin type.
 
/// TODO: Fix for maximum u64 value
 
fn enum_representation(max_tag_value: i64) -> PrimitiveType {
 
    if max_tag_value <= u8::max_value() as i64 {
 
        PrimitiveType::Byte
 
    } else if max_tag_value <= u16::max_value() as i64 {
 
        PrimitiveType::Short
 
    } else if max_tag_value <= u32::max_value() as i64 {
 
        PrimitiveType::Int
 
    } else {
 
        PrimitiveType::Long
 
    }
 
}
 
\ No newline at end of file
0 comments (0 inline, 0 general)