Changeset - 814be01095d9
[Not reviewed]
0 5 3
mh - 4 years ago 2021-01-07 19:12:05
contact@maxhenger.nl
implement module/version pragma, WIP on visitor rewrite
8 files changed with 158 insertions and 24 deletions:
0 comments (0 inline, 0 general)
src/lib.rs
Show inline comments
 
#[macro_use]
 
mod macros;
 

	
 
mod common;
 
mod protocol;
 
mod runtime;
 

	
 
pub use common::{ConnectorId, EndpointPolarity, Payload, Polarity, PortId};
 
pub use protocol::{ProtocolDescription, TRIVIAL_PD};
 
pub use runtime::{error, Connector, DummyLogger, FileLogger, VecLogger};
 

	
 
// TODO: Remove when not benchmarking
 
pub use protocol::inputsource::InputSource;
 
pub use protocol::ast::Heap;
 
pub use protocol::lexer::Lexer;
 

	
 
#[cfg(feature = "ffi")]
 
pub mod ffi;
src/protocol/ast.rs
Show inline comments
 
@@ -1057,620 +1057,642 @@ impl Index<ReturnStatementId> for Heap {
 
}
 

	
 
impl Index<AssertStatementId> for Heap {
 
    type Output = AssertStatement;
 
    fn index(&self, index: AssertStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_assert()
 
    }
 
}
 

	
 
impl Index<GotoStatementId> for Heap {
 
    type Output = GotoStatement;
 
    fn index(&self, index: GotoStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_goto()
 
    }
 
}
 

	
 
impl IndexMut<GotoStatementId> for Heap {
 
    fn index_mut(&mut self, index: GotoStatementId) -> &mut Self::Output {
 
        (&mut self.statements[(index.0).0]).as_goto_mut()
 
    }
 
}
 

	
 
impl Index<NewStatementId> for Heap {
 
    type Output = NewStatement;
 
    fn index(&self, index: NewStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_new()
 
    }
 
}
 

	
 
impl Index<PutStatementId> for Heap {
 
    type Output = PutStatement;
 
    fn index(&self, index: PutStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_put()
 
    }
 
}
 

	
 
impl Index<ExpressionStatementId> for Heap {
 
    type Output = ExpressionStatement;
 
    fn index(&self, index: ExpressionStatementId) -> &Self::Output {
 
        &self.statements[(index.0).0].as_expression()
 
    }
 
}
 

	
 
impl Index<ExpressionId> for Heap {
 
    type Output = Expression;
 
    fn index(&self, index: ExpressionId) -> &Self::Output {
 
        &self.expressions[index.0]
 
    }
 
}
 

	
 
impl Index<AssignmentExpressionId> for Heap {
 
    type Output = AssignmentExpression;
 
    fn index(&self, index: AssignmentExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_assignment()
 
    }
 
}
 

	
 
impl Index<ConditionalExpressionId> for Heap {
 
    type Output = ConditionalExpression;
 
    fn index(&self, index: ConditionalExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_conditional()
 
    }
 
}
 

	
 
impl Index<BinaryExpressionId> for Heap {
 
    type Output = BinaryExpression;
 
    fn index(&self, index: BinaryExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_binary()
 
    }
 
}
 

	
 
impl Index<UnaryExpressionId> for Heap {
 
    type Output = UnaryExpression;
 
    fn index(&self, index: UnaryExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_unary()
 
    }
 
}
 

	
 
impl Index<IndexingExpressionId> for Heap {
 
    type Output = IndexingExpression;
 
    fn index(&self, index: IndexingExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_indexing()
 
    }
 
}
 

	
 
impl Index<SlicingExpressionId> for Heap {
 
    type Output = SlicingExpression;
 
    fn index(&self, index: SlicingExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_slicing()
 
    }
 
}
 

	
 
impl Index<SelectExpressionId> for Heap {
 
    type Output = SelectExpression;
 
    fn index(&self, index: SelectExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_select()
 
    }
 
}
 

	
 
impl Index<ArrayExpressionId> for Heap {
 
    type Output = ArrayExpression;
 
    fn index(&self, index: ArrayExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_array()
 
    }
 
}
 

	
 
impl Index<ConstantExpressionId> for Heap {
 
    type Output = ConstantExpression;
 
    fn index(&self, index: ConstantExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_constant()
 
    }
 
}
 

	
 
impl Index<CallExpressionId> for Heap {
 
    type Output = CallExpression;
 
    fn index(&self, index: CallExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_call()
 
    }
 
}
 

	
 
impl IndexMut<CallExpressionId> for Heap {
 
    fn index_mut(&mut self, index: CallExpressionId) -> &mut Self::Output {
 
        (&mut self.expressions[(index.0).0]).as_call_mut()
 
    }
 
}
 

	
 
impl Index<VariableExpressionId> for Heap {
 
    type Output = VariableExpression;
 
    fn index(&self, index: VariableExpressionId) -> &Self::Output {
 
        &self.expressions[(index.0).0].as_variable()
 
    }
 
}
 

	
 
impl IndexMut<VariableExpressionId> for Heap {
 
    fn index_mut(&mut self, index: VariableExpressionId) -> &mut Self::Output {
 
        (&mut self.expressions[(index.0).0]).as_variable_mut()
 
    }
 
}
 

	
 
impl Index<DeclarationId> for Heap {
 
    type Output = Declaration;
 
    fn index(&self, index: DeclarationId) -> &Self::Output {
 
        &self.declarations[index.0]
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct Root {
 
    pub this: RootId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub pragmas: Vec<PragmaId>,
 
    pub imports: Vec<ImportId>,
 
    pub definitions: Vec<DefinitionId>,
 
    // Pase 2: linker
 
    pub declarations: Vec<DeclarationId>,
 
}
 

	
 
impl Root {
 
    pub fn get_definition(&self, h: &Heap, id: IdentifierId) -> Option<DefinitionId> {
 
        for &def in self.definitions.iter() {
 
            if h[h[def].identifier()] == h[id] {
 
                return Some(def);
 
            }
 
        }
 
        None
 
    }
 
    pub fn get_definition_ident(&self, h: &Heap, id: &[u8]) -> Option<DefinitionId> {
 
        for &def in self.definitions.iter() {
 
            if h[h[def].identifier()].ident() == id {
 
                return Some(def);
 
            }
 
        }
 
        None
 
    }
 
    pub fn get_declaration(&self, h: &Heap, id: IdentifierId) -> Option<DeclarationId> {
 
        for &decl in self.declarations.iter() {
 
            if h[h[decl].identifier()] == h[id] {
 
                return Some(decl);
 
            }
 
        }
 
        None
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct Pragma {
 
pub enum Pragma {
 
    Version(PragmaVersion),
 
    Module(PragmaModule)
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct PragmaVersion {
 
    pub this: PragmaId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub version: u64,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct PragmaModule {
 
    pub this: PragmaId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub value: Vec<u8>,
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct PragmaOld {
 
    pub this: PragmaId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub value: Vec<u8>,
 
}
 

	
 
impl SyntaxElement for Pragma {
 
impl SyntaxElement for PragmaOld {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct Import {
 
    pub this: ImportId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub value: Vec<u8>,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum Identifier {
 
    External(ExternalIdentifier),
 
    Source(SourceIdentifier),
 
}
 

	
 
impl Identifier {
 
    pub fn as_source(&self) -> &SourceIdentifier {
 
        match self {
 
            Identifier::Source(result) => result,
 
            _ => panic!("Unable to cast `Identifier` to `SourceIdentifier`"),
 
        }
 
    }
 
    pub fn is_external(&self) -> bool {
 
        match self {
 
            Identifier::External(_) => true,
 
            _ => false,
 
        }
 
    }
 
    pub fn as_external(&self) -> &ExternalIdentifier {
 
        match self {
 
            Identifier::External(result) => result,
 
            _ => panic!("Unable to cast `Identifier` to `ExternalIdentifier`"),
 
        }
 
    }
 
    fn ident(&self) -> &[u8] {
 
        match self {
 
            Identifier::External(eid) => eid.ident(),
 
            Identifier::Source(sid) => sid.ident(),
 
        }
 
    }
 
}
 

	
 
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.ident()))
 
    }
 
}
 

	
 
impl PartialEq<Identifier> for Identifier {
 
    fn eq(&self, rhs: &Identifier) -> bool {
 
        self.ident() == rhs.ident()
 
    }
 
}
 

	
 
impl PartialEq<SourceIdentifier> for Identifier {
 
    fn eq(&self, rhs: &SourceIdentifier) -> bool {
 
        self.ident() == rhs.ident()
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct ExternalIdentifier {
 
    pub this: ExternalIdentifierId,
 
    // Phase 1: parser
 
    pub value: Vec<u8>,
 
}
 

	
 
impl ExternalIdentifier {
 
    fn ident(&self) -> &[u8] {
 
        &self.value
 
    }
 
}
 

	
 
impl Display for ExternalIdentifier {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        // A source identifier is in ASCII range.
 
        write!(f, "{}", String::from_utf8_lossy(&self.value))
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct SourceIdentifier {
 
    pub this: SourceIdentifierId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub value: Vec<u8>,
 
}
 

	
 
impl SourceIdentifier {
 
    pub fn ident(&self) -> &[u8] {
 
        &self.value
 
    }
 
}
 

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

	
 
impl Display for SourceIdentifier {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        // A source identifier is in ASCII range.
 
        write!(f, "{}", String::from_utf8_lossy(&self.value))
 
    }
 
}
 

	
 
impl PartialEq<Identifier> for SourceIdentifier {
 
    fn eq(&self, rhs: &Identifier) -> bool {
 
        self.ident() == rhs.ident()
 
    }
 
}
 

	
 
impl PartialEq<SourceIdentifier> for SourceIdentifier {
 
    fn eq(&self, rhs: &SourceIdentifier) -> bool {
 
        self.ident() == rhs.ident()
 
    }
 
}
 

	
 
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),
 
}
 

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

	
 
#[allow(dead_code)]
 
impl Type {
 
    pub const INPUT: Type = Type { primitive: PrimitiveType::Input, array: false };
 
    pub const OUTPUT: Type = Type { primitive: PrimitiveType::Output, array: false };
 
    pub const MESSAGE: Type = Type { primitive: PrimitiveType::Message, array: false };
 
    pub const BOOLEAN: Type = Type { primitive: PrimitiveType::Boolean, array: false };
 
    pub const BYTE: Type = Type { primitive: PrimitiveType::Byte, array: false };
 
    pub const SHORT: Type = Type { primitive: PrimitiveType::Short, array: false };
 
    pub const INT: Type = Type { primitive: PrimitiveType::Int, array: false };
 
    pub const LONG: Type = Type { primitive: PrimitiveType::Long, array: false };
 

	
 
    pub const INPUT_ARRAY: Type = Type { primitive: PrimitiveType::Input, array: true };
 
    pub const OUTPUT_ARRAY: Type = Type { primitive: PrimitiveType::Output, array: true };
 
    pub const MESSAGE_ARRAY: Type = Type { primitive: PrimitiveType::Message, array: true };
 
    pub const BOOLEAN_ARRAY: Type = Type { primitive: PrimitiveType::Boolean, array: true };
 
    pub const BYTE_ARRAY: Type = Type { primitive: PrimitiveType::Byte, array: true };
 
    pub const SHORT_ARRAY: Type = Type { primitive: PrimitiveType::Short, array: true };
 
    pub const INT_ARRAY: Type = Type { primitive: PrimitiveType::Int, array: true };
 
    pub const LONG_ARRAY: Type = Type { primitive: PrimitiveType::Long, array: true };
 
}
 

	
 
impl Display for Type {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        match &self.primitive {
 
            PrimitiveType::Input => {
 
                write!(f, "in")?;
 
            }
 
            PrimitiveType::Output => {
 
                write!(f, "out")?;
 
            }
 
            PrimitiveType::Message => {
 
                write!(f, "msg")?;
 
            }
 
            PrimitiveType::Boolean => {
 
                write!(f, "boolean")?;
 
            }
 
            PrimitiveType::Byte => {
 
                write!(f, "byte")?;
 
            }
 
            PrimitiveType::Short => {
 
                write!(f, "short")?;
 
            }
 
            PrimitiveType::Int => {
 
                write!(f, "int")?;
 
            }
 
            PrimitiveType::Long => {
 
                write!(f, "long")?;
 
            }
 
            PrimitiveType::Symbolic(data) => {
 
                // Type data is in ASCII range.
 
                write!(f, "{}", String::from_utf8_lossy(&data))?;
 
            }
 
        }
 
        if self.array {
 
            write!(f, "[]")
 
        } else {
 
            Ok(())
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct TypeAnnotation {
 
    pub this: TypeAnnotationId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub the_type: Type,
 
}
 

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

	
 
type CharacterData = Vec<u8>;
 
type IntegerData = Vec<u8>;
 
type IntegerData = i64;
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum Constant {
 
    Null, // message
 
    True,
 
    False,
 
    Character(CharacterData),
 
    Integer(IntegerData),
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum Field {
 
    Length,
 
    Symbolic(SourceIdentifierId),
 
}
 
impl Field {
 
    pub fn is_length(&self) -> bool {
 
        match self {
 
            Field::Length => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
 
pub enum Scope {
 
    Definition(DefinitionId),
 
    Block(BlockStatementId),
 
    Synchronous(SynchronousStatementId),
 
}
 

	
 
impl Scope {
 
    pub fn to_block(&self) -> BlockStatementId {
 
        match &self {
 
            Scope::Block(id) => *id,
 
            _ => panic!("Unable to cast `Scope` to `BlockStatement`"),
 
        }
 
    }
 
}
 

	
 
pub trait VariableScope {
 
    fn parent_scope(&self, h: &Heap) -> Option<Scope>;
 
    fn get_variable(&self, h: &Heap, id: SourceIdentifierId) -> Option<VariableId>;
 
}
 

	
 
impl VariableScope for Scope {
 
    fn parent_scope(&self, h: &Heap) -> Option<Scope> {
 
        match self {
 
            Scope::Definition(def) => h[*def].parent_scope(h),
 
            Scope::Block(stmt) => h[*stmt].parent_scope(h),
 
            Scope::Synchronous(stmt) => h[*stmt].parent_scope(h),
 
        }
 
    }
 
    fn get_variable(&self, h: &Heap, id: SourceIdentifierId) -> Option<VariableId> {
 
        match self {
 
            Scope::Definition(def) => h[*def].get_variable(h, id),
 
            Scope::Block(stmt) => h[*stmt].get_variable(h, id),
 
            Scope::Synchronous(stmt) => h[*stmt].get_variable(h, id),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum Variable {
 
    Parameter(Parameter),
 
    Local(Local),
 
}
 

	
 
impl Variable {
 
    pub fn identifier(&self) -> SourceIdentifierId {
 
        match self {
 
            Variable::Parameter(var) => var.identifier,
 
            Variable::Local(var) => var.identifier,
 
        }
 
    }
 
    pub fn is_parameter(&self) -> bool {
 
        match self {
 
            Variable::Parameter(_) => true,
 
            _ => false,
 
        }
 
    }
 
    pub fn as_parameter(&self) -> &Parameter {
 
        match self {
 
            Variable::Parameter(result) => result,
 
            _ => panic!("Unable to cast `Variable` to `Parameter`"),
 
        }
 
    }
 
    pub fn as_local(&self) -> &Local {
 
        match self {
 
            Variable::Local(result) => result,
 
            _ => panic!("Unable to cast `Variable` to `Local`"),
 
        }
 
    }
 
    pub fn the_type<'b>(&self, h: &'b Heap) -> &'b Type {
 
        match self {
 
            Variable::Parameter(param) => &h[param.type_annotation].the_type,
 
            Variable::Local(local) => &h[local.type_annotation].the_type,
 
        }
 
    }
 
}
 

	
 
impl SyntaxElement for Variable {
 
    fn position(&self) -> InputPosition {
 
        match self {
 
            Variable::Parameter(decl) => decl.position(),
 
            Variable::Local(decl) => decl.position(),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct Parameter {
 
    pub this: ParameterId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub type_annotation: TypeAnnotationId,
 
    pub identifier: SourceIdentifierId,
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub struct Local {
 
    pub this: LocalId,
 
    // Phase 1: parser
 
    pub position: InputPosition,
 
    pub type_annotation: TypeAnnotationId,
 
    pub identifier: SourceIdentifierId,
 
}
 
impl SyntaxElement for Local {
 
    fn position(&self) -> InputPosition {
 
        self.position
 
    }
 
}
 

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

	
 
impl Definition {
 
    pub fn is_component(&self) -> bool {
 
        match self {
 
            Definition::Component(_) => true,
 
            _ => false,
 
        }
 
    }
 
    pub fn as_component(&self) -> &Component {
 
        match self {
 
            Definition::Component(result) => result,
 
            _ => panic!("Unable to cast `Definition` to `Component`"),
 
        }
 
    }
 
    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) -> SourceIdentifierId {
 
        match self {
 
            Definition::Component(com) => com.identifier(),
 
            Definition::Function(fun) => fun.identifier,
 
        }
 
    }
 
    pub fn parameters(&self) -> &Vec<ParameterId> {
 
        match self {
 
            Definition::Component(com) => com.parameters(),
 
            Definition::Function(fun) => &fun.parameters,
 
        }
 
    }
 
    pub fn body(&self) -> StatementId {
 
        match self {
src/protocol/eval.rs
Show inline comments
 
use std::collections::HashMap;
 
use std::fmt;
 
use std::fmt::{Debug, Display, Formatter};
 
use std::{i16, i32, i64, i8};
 

	
 
use crate::common::*;
 

	
 
use crate::protocol::ast::*;
 
use crate::protocol::EvalContext;
 

	
 
// const MAX_RECURSION: usize = 1024;
 

	
 
const BYTE_MIN: i64 = i8::MIN as i64;
 
const BYTE_MAX: i64 = i8::MAX as i64;
 
const SHORT_MIN: i64 = i16::MIN as i64;
 
const SHORT_MAX: i64 = i16::MAX as i64;
 
const INT_MIN: i64 = i32::MIN as i64;
 
const INT_MAX: i64 = i32::MAX as i64;
 

	
 
const MESSAGE_MAX_LENGTH: i64 = SHORT_MAX;
 

	
 
const ONE: Value = Value::Byte(ByteValue(1));
 

	
 
trait ValueImpl {
 
    fn exact_type(&self) -> Type;
 
    fn is_type_compatible(&self, t: &Type) -> bool;
 
}
 

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum Value {
 
    Input(InputValue),
 
    Output(OutputValue),
 
    Message(MessageValue),
 
    Boolean(BooleanValue),
 
    Byte(ByteValue),
 
    Short(ShortValue),
 
    Int(IntValue),
 
    Long(LongValue),
 
    InputArray(InputArrayValue),
 
    OutputArray(OutputArrayValue),
 
    MessageArray(MessageArrayValue),
 
    BooleanArray(BooleanArrayValue),
 
    ByteArray(ByteArrayValue),
 
    ShortArray(ShortArrayValue),
 
    IntArray(IntArrayValue),
 
    LongArray(LongArrayValue),
 
}
 
impl Value {
 
    pub fn receive_message(buffer: &Payload) -> Value {
 
        Value::Message(MessageValue(Some(buffer.clone())))
 
    }
 
    fn create_message(length: Value) -> Value {
 
        match length {
 
            Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => {
 
                let length: i64 = i64::from(length);
 
                if length < 0 || length > MESSAGE_MAX_LENGTH {
 
                    // Only messages within the expected length are allowed
 
                    Value::Message(MessageValue(None))
 
                } else {
 
                    Value::Message(MessageValue(Some(Payload::new(length as usize))))
 
                }
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn from_constant(constant: &Constant) -> Value {
 
        match constant {
 
            Constant::Null => Value::Message(MessageValue(None)),
 
            Constant::True => Value::Boolean(BooleanValue(true)),
 
            Constant::False => Value::Boolean(BooleanValue(false)),
 
            Constant::Integer(data) => {
 
            Constant::Integer(val) => {
 
                // Convert raw ASCII data to UTF-8 string
 
                let raw = String::from_utf8_lossy(data);
 
                let val = raw.parse::<i64>().unwrap();
 
                let val = *val;
 
                if val >= BYTE_MIN && val <= BYTE_MAX {
 
                    Value::Byte(ByteValue(val as i8))
 
                } else if val >= SHORT_MIN && val <= SHORT_MAX {
 
                    Value::Short(ShortValue(val as i16))
 
                } else if val >= INT_MIN && val <= INT_MAX {
 
                    Value::Int(IntValue(val as i32))
 
                } else {
 
                    Value::Long(LongValue(val))
 
                }
 
            }
 
            Constant::Character(_data) => unimplemented!(),
 
        }
 
    }
 
    fn set(&mut self, index: &Value, value: &Value) -> Option<Value> {
 
        // The index must be of integer type, and non-negative
 
        let the_index: usize;
 
        match index {
 
            Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => {
 
                let index = i64::from(index);
 
                if index < 0 || index >= MESSAGE_MAX_LENGTH {
 
                    // It is inconsistent to update out of bounds
 
                    return None;
 
                }
 
                the_index = index.try_into().unwrap();
 
            }
 
            _ => unreachable!(),
 
        }
 
        // The subject must be either a message or an array
 
        // And the value and the subject must be compatible
 
        match (self, value) {
 
            (Value::Message(MessageValue(None)), _) => {
 
                // It is inconsistent to update the null message
 
                None
 
            }
 
            (Value::Message(MessageValue(Some(payload))), Value::Byte(ByteValue(b))) => {
 
                if *b < 0 {
 
                    // It is inconsistent to update with a negative value
 
                    return None;
 
                }
 
                if let Some(slot) = payload.as_mut_vec().get_mut(the_index) {
 
                    *slot = (*b).try_into().unwrap();
 
                    Some(value.clone())
 
                } else {
 
                    // It is inconsistent to update out of bounds
 
                    None
 
                }
 
            }
 
            (Value::Message(MessageValue(Some(payload))), Value::Short(ShortValue(b))) => {
 
                if *b < 0 || *b > BYTE_MAX as i16 {
 
                    // It is inconsistent to update with a negative value or a too large value
 
                    return None;
 
                }
 
                if let Some(slot) = payload.as_mut_vec().get_mut(the_index) {
 
                    *slot = (*b).try_into().unwrap();
 
                    Some(value.clone())
 
                } else {
 
                    // It is inconsistent to update out of bounds
 
                    None
 
                }
 
            }
 
            (Value::InputArray(_), Value::Input(_)) => todo!(),
 
            (Value::OutputArray(_), Value::Output(_)) => todo!(),
 
            (Value::MessageArray(_), Value::Message(_)) => todo!(),
 
            (Value::BooleanArray(_), Value::Boolean(_)) => todo!(),
 
            (Value::ByteArray(_), Value::Byte(_)) => todo!(),
 
            (Value::ShortArray(_), Value::Short(_)) => todo!(),
 
            (Value::IntArray(_), Value::Int(_)) => todo!(),
 
            (Value::LongArray(_), Value::Long(_)) => todo!(),
 
            _ => unreachable!(),
 
        }
 
    }
 
    fn get(&self, index: &Value) -> Option<Value> {
 
        // The index must be of integer type, and non-negative
 
        let the_index: usize;
 
        match index {
 
            Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => {
 
                let index = i64::from(index);
 
                if index < 0 || index >= MESSAGE_MAX_LENGTH {
 
                    // It is inconsistent to update out of bounds
 
                    return None;
 
                }
 
                the_index = index.try_into().unwrap();
 
            }
 
            _ => unreachable!(),
 
        }
 
        // The subject must be either a message or an array
 
        match self {
 
            Value::Message(MessageValue(None)) => {
 
                // It is inconsistent to read from the null message
 
                None
 
            }
 
            Value::Message(MessageValue(Some(payload))) => {
 
                if let Some(slot) = payload.as_slice().get(the_index) {
 
                    Some(Value::Short(ShortValue((*slot).try_into().unwrap())))
 
                } else {
 
                    // It is inconsistent to update out of bounds
 
                    None
 
                }
 
            }
 
            _ => panic!("Can only get from port value"),
 
        }
 
    }
 
    fn length(&self) -> Option<Value> {
 
        // The subject must be either a message or an array
 
        match self {
 
            Value::Message(MessageValue(None)) => {
 
                // It is inconsistent to get length from the null message
 
                None
 
            }
 
            Value::Message(MessageValue(Some(buffer))) => {
 
                Some(Value::Int(IntValue((buffer.len()).try_into().unwrap())))
 
            }
 
            Value::InputArray(InputArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::OutputArray(OutputArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::MessageArray(MessageArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::BooleanArray(BooleanArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::ByteArray(ByteArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::ShortArray(ShortArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::IntArray(IntArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::LongArray(LongArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            _ => unreachable!(),
 
        }
 
    }
 
    fn plus(&self, other: &Value) -> Value {
 
        match (self, other) {
 
            (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Byte(ByteValue(*s + *o))
 
            }
 
            (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Short(ShortValue(*s as i16 + *o))
 
            }
 
            (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s as i32 + *o))
 
            }
 
            (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 + *o))
 
            }
 
            (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Short(ShortValue(*s + *o as i16))
 
            }
 
            (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Short(ShortValue(*s + *o))
 
            }
 
            (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s as i32 + *o))
 
            }
 
            (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 + *o))
 
            }
 
            (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Int(IntValue(*s + *o as i32))
 
            }
 
            (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Int(IntValue(*s + *o as i32))
 
            }
 
            (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => Value::Int(IntValue(*s + *o)),
 
            (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 + *o))
 
            }
 
            (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Long(LongValue(*s + *o as i64))
 
            }
 
            (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Long(LongValue(*s + *o as i64))
 
            }
 
            (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Long(LongValue(*s + *o as i64))
 
            }
 
            (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s + *o))
 
            }
 

	
 
            (Value::Message(MessageValue(s)), Value::Message(MessageValue(o))) => {
 
                let payload = if let [Some(s), Some(o)] = [s, o] {
 
                    let mut payload = s.clone();
 
                    payload.concatenate_with(o);
src/protocol/lexer.rs
Show inline comments
 
use crate::protocol::ast::*;
 
use crate::protocol::inputsource::*;
 

	
 
const MAX_LEVEL: usize = 128;
 

	
 
fn is_vchar(x: Option<u8>) -> bool {
 
    if let Some(c) = x {
 
        c >= 0x21 && c <= 0x7E
 
    } else {
 
        false
 
    }
 
}
 

	
 
fn is_wsp(x: Option<u8>) -> bool {
 
    if let Some(c) = x {
 
        c == b' ' || c == b'\t'
 
    } else {
 
        false
 
    }
 
}
 

	
 
fn is_ident_start(x: Option<u8>) -> bool {
 
    if let Some(c) = x {
 
        c >= b'A' && c <= b'Z' || c >= b'a' && c <= b'z'
 
    } else {
 
        false
 
    }
 
}
 

	
 
fn is_ident_rest(x: Option<u8>) -> bool {
 
    if let Some(c) = x {
 
        c >= b'A' && c <= b'Z' || c >= b'a' && c <= b'z' || c >= b'0' && c <= b'9' || c == b'_'
 
    } else {
 
        false
 
    }
 
}
 

	
 
fn is_constant(x: Option<u8>) -> bool {
 
    if let Some(c) = x {
 
        c >= b'0' && c <= b'9' || c == b'\''
 
    } else {
 
        false
 
    }
 
}
 

	
 
fn is_integer_start(x: Option<u8>) -> bool {
 
    if let Some(c) = x {
 
        c >= b'0' && c <= b'9'
 
    } else {
 
        false
 
    }
 
}
 

	
 
fn is_integer_rest(x: Option<u8>) -> bool {
 
    if let Some(c) = x {
 
        c >= b'0' && c <= b'9'
 
            || c >= b'a' && c <= b'f'
 
            || c >= b'A' && c <= b'F'
 
            || c == b'x'
 
            || c == b'X'
 
            || c == b'o'
 
    } else {
 
        false
 
    }
 
}
 

	
 
fn lowercase(x: u8) -> u8 {
 
    if x >= b'A' && x <= b'Z' {
 
        x - b'A' + b'a'
 
    } else {
 
        x
 
    }
 
}
 

	
 
pub struct Lexer<'a> {
 
    source: &'a mut InputSource,
 
    level: usize,
 
}
 

	
 
impl Lexer<'_> {
 
    pub fn new(source: &mut InputSource) -> Lexer {
 
        Lexer { source, level: 0 }
 
    }
 
    fn consume_line(&mut self) -> Result<Vec<u8>, ParseError> {
 
        let mut result: Vec<u8> = Vec::new();
 
        let mut next = self.source.next();
 
        while next.is_some() && next != Some(b'\n') && next != Some(b'\r') {
 
            if !(is_vchar(next) || is_wsp(next)) {
 
                return Err(self.source.error("Expected visible character or whitespace"));
 
            }
 
            result.push(next.unwrap());
 
            self.source.consume();
 
            next = self.source.next();
 
        }
 
        if next.is_some() {
 
            self.source.consume();
 
        }
 
        if next == Some(b'\r') && self.source.next() == Some(b'\n') {
 
            self.source.consume();
 
        }
 
        Ok(result)
 
    }
 
    fn consume_whitespace(&mut self, expected: bool) -> Result<(), ParseError> {
 
        let mut found = false;
 
        let mut next = self.source.next();
 
        while next.is_some() {
 
            if next == Some(b' ')
 
                || next == Some(b'\t')
 
                || next == Some(b'\r')
 
                || next == Some(b'\n')
 
            {
 
                self.source.consume();
 
                next = self.source.next();
 
                found = true;
 
                continue;
 
            }
 
            if next == Some(b'/') {
 
                next = self.source.lookahead(1);
 
                if next == Some(b'/') {
 
                    self.source.consume(); // slash
 
                    self.source.consume(); // slash
 
                    self.consume_line()?;
 
                    next = self.source.next();
 
                    found = true;
 
                    continue;
 
                }
 
                if next == Some(b'*') {
 
                    self.source.consume(); // slash
 
                    self.source.consume(); // star
 
                    next = self.source.next();
 
                    while next.is_some() {
 
                        if next == Some(b'*') {
 
                            next = self.source.lookahead(1);
 
                            if next == Some(b'/') {
 
                                self.source.consume(); // star
 
                                self.source.consume(); // slash
 
                                break;
 
                            }
 
                        }
 
                        self.source.consume();
 
                        next = self.source.next();
 
                    }
 
                    next = self.source.next();
 
                    found = true;
 
                    continue;
 
                }
 
            }
 
            break;
 
        }
 
        if expected && !found {
 
            Err(self.source.error("Expected whitespace"))
 
        } else {
 
            Ok(())
 
        }
 
    }
 
    fn has_keyword(&self, keyword: &[u8]) -> bool {
 
        if !self.source.has(keyword) {
 
            return false;
 
        }
 

	
 
        // Word boundary
 
        if let Some(next) = self.source.lookahead(keyword.len()) {
 
            !(next >= b'A' && next <= b'Z' || next >= b'a' && next <= b'z')
 
        } else {
 
            true
 
        }
 
    }
 
    fn consume_keyword(&mut self, keyword: &[u8]) -> Result<(), ParseError> {
 
        let len = keyword.len();
 
        for i in 0..len {
 
            let expected = Some(lowercase(keyword[i]));
 
            let next = self.source.next();
 
            if next != expected {
 
                return Err(self
 
                    .source
 
                    .error(format!("Expected keyword: {}", String::from_utf8_lossy(keyword))));
 
            }
 
            self.source.consume();
 
        }
 
        if let Some(next) = self.source.next() {
 
            if next >= b'A' && next <= b'Z' || next >= b'a' && next <= b'z' {
 
                return Err(self.source.error(format!(
 
                    "Expected word boundary after keyword: {}",
 
                    String::from_utf8_lossy(keyword)
 
                )));
 
            }
 
        }
 
        Ok(())
 
    }
 
    fn has_string(&self, string: &[u8]) -> bool {
 
        self.source.has(string)
 
    }
 
    fn consume_string(&mut self, string: &[u8]) -> Result<(), ParseError> {
 
        let len = string.len();
 
        for i in 0..len {
 
            let expected = Some(string[i]);
 
            let next = self.source.next();
 
            if next != expected {
 
                return Err(self
 
                    .source
 
                    .error(format!("Expected {}", String::from_utf8_lossy(string))));
 
            }
 
            self.source.consume();
 
        }
 
        Ok(())
 
    }
 
    fn consume_ident(&mut self) -> Result<Vec<u8>, ParseError> {
 
        if !self.has_identifier() {
 
            return Err(self.source.error("Expected identifier"));
 
        }
 
        let mut result = Vec::new();
 
        let mut next = self.source.next();
 
        result.push(next.unwrap());
 
        self.source.consume();
 
        next = self.source.next();
 
        while is_ident_rest(next) {
 
            result.push(next.unwrap());
 
            self.source.consume();
 
            next = self.source.next();
 
        }
 
        Ok(result)
 
    }
 
    fn has_integer(&mut self) -> bool {
 
        is_integer_start(self.source.next())
 
    }
 
    fn consume_integer(&mut self) -> Result<i64, ParseError> {
 
        let position = self.source.pos();
 
        let mut data = Vec::new();
 
        let mut next = self.source.next();
 
        while is_integer_rest(next) {
 
            data.push(next.unwrap());
 
            self.source.consume();
 
            next = self.source.next();
 
        }
 

	
 
        let data_len = data.len();
 
        debug_assert_ne!(data_len, 0);
 
        if data_len == 1 {
 
            debug_assert!(data[0] >= b'0' && data[0] <= b'9');
 
            return Ok((data[0] - b'0') as i64);
 
        } else {
 
            // TODO: Fix, u64 should be supported as well
 
            let parsed = if data[1] == b'b' {
 
                let data = String::from_utf8_lossy(&data[2..]);
 
                i64::from_str_radix(&data, 2)
 
            } else if data[1] == b'o' {
 
                let data = String::from_utf8_lossy(&data[2..]);
 
                i64::from_str_radix(&data, 8)
 
            } else if data[1] == b'x' {
 
                let data = String::from_utf8_lossy(&data[2..]);
 
                i64::from_str_radix(&data, 16)
 
            } else {
 
                // Assume decimal
 
                let data = String::from_utf8_lossy(&data);
 
                i64::from_str_radix(&data, 10)
 
            };
 

	
 
            if let Err(_err) = parsed {
 
                return Err(ParseError::new(position, "Invalid integer constant"));
 
            }
 

	
 
            Ok(parsed.unwrap())
 
        }
 
    }
 

	
 
    // Statement keywords
 

	
 
    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")
 
    }
 
    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")
 
            || self.has_keyword(b"byte")
 
            || self.has_keyword(b"short")
 
            || self.has_keyword(b"int")
 
            || self.has_keyword(b"long")
 
    }
 
    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")
 
    }
 

	
 
    // 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<SourceIdentifierId, ParseError> {
 
        if self.has_statement_keyword() || self.has_type_keyword() || self.has_builtin_keyword() {
 
            return Err(self.source.error("Expected identifier"));
 
        }
 
        let position = self.source.pos();
 
        let value = self.consume_ident()?;
 
        let id = h.alloc_source_identifier(|this| SourceIdentifier { this, position, value });
 
        Ok(id)
 
    }
 
    fn consume_identifier_spilled(&mut self) -> Result<(), ParseError> {
 
        if self.has_statement_keyword() || self.has_type_keyword() || self.has_builtin_keyword() {
 
            return Err(self.source.error("Expected identifier"));
 
        }
 
        self.consume_ident()?;
 
        Ok(())
 
    }
 

	
 
    // Types and type annotations
 

	
 
    fn consume_primitive_type(&mut self) -> Result<PrimitiveType, ParseError> {
 
        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")?;
 
            Ok(PrimitiveType::Output)
 
        } else if self.has_keyword(b"msg") {
 
            self.consume_keyword(b"msg")?;
 
            Ok(PrimitiveType::Message)
 
        } else if self.has_keyword(b"boolean") {
 
            self.consume_keyword(b"boolean")?;
 
            Ok(PrimitiveType::Boolean)
 
        } else if self.has_keyword(b"byte") {
 
            self.consume_keyword(b"byte")?;
 
            Ok(PrimitiveType::Byte)
 
        } else if self.has_keyword(b"short") {
 
            self.consume_keyword(b"short")?;
 
            Ok(PrimitiveType::Short)
 
        } 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 {
 
            let data = self.consume_ident()?;
 
            Ok(PrimitiveType::Symbolic(data))
 
        }
 
    }
 
    fn has_array(&mut self) -> bool {
 
        let backup_pos = self.source.pos();
 
        let mut result = false;
 
        match self.consume_whitespace(false) {
 
            Ok(_) => result = self.has_string(b"["),
 
            Err(_) => {}
 
        }
 
        self.source.seek(backup_pos);
 
        return result;
 
    }
 
    fn consume_type(&mut self) -> Result<Type, ParseError> {
 
        let primitive = self.consume_primitive_type()?;
 
        let array;
 
        if self.has_array() {
 
            self.consume_string(b"[]")?;
 
            array = true;
 
        } else {
 
            array = false;
 
        }
 
        Ok(Type { primitive, array })
 
    }
 
    fn create_type_annotation_input(&self, h: &mut Heap) -> Result<TypeAnnotationId, ParseError> {
 
        let position = self.source.pos();
 
        let the_type = Type::INPUT;
 
        let id = h.alloc_type_annotation(|this| TypeAnnotation { this, position, the_type });
 
        Ok(id)
 
    }
 
    fn create_type_annotation_output(&self, h: &mut Heap) -> Result<TypeAnnotationId, ParseError> {
 
        let position = self.source.pos();
 
        let the_type = Type::OUTPUT;
 
        let id = h.alloc_type_annotation(|this| TypeAnnotation { this, position, the_type });
 
        Ok(id)
 
    }
 
    fn consume_type_annotation(&mut self, h: &mut Heap) -> Result<TypeAnnotationId, ParseError> {
 
        let position = self.source.pos();
 
        let the_type = self.consume_type()?;
 
        let id = h.alloc_type_annotation(|this| TypeAnnotation { this, position, the_type });
 
        Ok(id)
 
    }
 
    fn consume_type_annotation_spilled(&mut self) -> Result<(), ParseError> {
 
        self.consume_type()?;
 
        Ok(())
 
    }
 

	
 
    // Parameters
 

	
 
    fn consume_parameter(&mut self, h: &mut Heap) -> Result<ParameterId, ParseError> {
 
        let position = self.source.pos();
 
        let type_annotation = self.consume_type_annotation(h)?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        let id =
 
            h.alloc_parameter(|this| Parameter { this, position, type_annotation, identifier });
 
        Ok(id)
 
    }
 
    fn consume_parameters(
 
        &mut self,
 
        h: &mut Heap,
 
        params: &mut Vec<ParameterId>,
 
    ) -> Result<(), ParseError> {
 
        self.consume_string(b"(")?;
 
        self.consume_whitespace(false)?;
 
        if !self.has_string(b")") {
 
            while self.source.next().is_some() {
 
                params.push(self.consume_parameter(h)?);
 
                self.consume_whitespace(false)?;
 
                if self.has_string(b")") {
 
                    break;
 
                }
 
                self.consume_string(b",")?;
 
                self.consume_whitespace(false)?;
 
            }
 
        }
 
        self.consume_string(b")")
 
    }
 

	
 
    // ====================
 
    // Expressions
 
    // ====================
 

	
 
    fn consume_paren_expression(&mut self, h: &mut Heap) -> Result<ExpressionId, ParseError> {
 
        self.consume_string(b"(")?;
 
        self.consume_whitespace(false)?;
 
        let result = self.consume_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b")")?;
 
        Ok(result)
 
    }
 
    fn consume_expression(&mut self, h: &mut Heap) -> Result<ExpressionId, ParseError> {
 
        if self.level >= MAX_LEVEL {
 
            return Err(self.source.error("Too deeply nested expression"));
 
        }
 
        self.level += 1;
 
        let result = self.consume_assignment_expression(h);
 
        self.level -= 1;
 
        result
 
    }
 
    fn consume_assignment_expression(&mut self, h: &mut Heap) -> Result<ExpressionId, ParseError> {
 
        let result = self.consume_conditional_expression(h)?;
 
        self.consume_whitespace(false)?;
 
@@ -836,395 +879,389 @@ impl Lexer<'_> {
 
                self.consume_string(b"~")?;
 
                operation = UnaryOperation::BitwiseNot;
 
            } else {
 
                self.consume_string(b"!")?;
 
                operation = UnaryOperation::LogicalNot;
 
            }
 
            self.consume_whitespace(false)?;
 
            if self.level >= MAX_LEVEL {
 
                return Err(self.source.error("Too deeply nested expression"));
 
            }
 
            self.level += 1;
 
            let result = self.consume_prefix_expression(h);
 
            self.level -= 1;
 
            let expression = result?;
 
            return Ok(h
 
                .alloc_unary_expression(|this| UnaryExpression {
 
                    this,
 
                    position,
 
                    operation,
 
                    expression,
 
                })
 
                .upcast());
 
        }
 
        self.consume_postfix_expression(h)
 
    }
 
    fn consume_postfix_expression(&mut self, h: &mut Heap) -> Result<ExpressionId, ParseError> {
 
        let mut result = self.consume_primary_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        while self.has_string(b"++")
 
            || self.has_string(b"--")
 
            || self.has_string(b"[")
 
            || (self.has_string(b".") && !self.has_string(b".."))
 
        {
 
            let mut position = self.source.pos();
 
            if self.has_string(b"++") {
 
                self.consume_string(b"++")?;
 
                let operation = UnaryOperation::PostIncrement;
 
                let expression = result;
 
                self.consume_whitespace(false)?;
 
                result = h
 
                    .alloc_unary_expression(|this| UnaryExpression {
 
                        this,
 
                        position,
 
                        operation,
 
                        expression,
 
                    })
 
                    .upcast();
 
            } else if self.has_string(b"--") {
 
                self.consume_string(b"--")?;
 
                let operation = UnaryOperation::PostDecrement;
 
                let expression = result;
 
                self.consume_whitespace(false)?;
 
                result = h
 
                    .alloc_unary_expression(|this| UnaryExpression {
 
                        this,
 
                        position,
 
                        operation,
 
                        expression,
 
                    })
 
                    .upcast();
 
            } else if self.has_string(b"[") {
 
                self.consume_string(b"[")?;
 
                self.consume_whitespace(false)?;
 
                let subject = result;
 
                let index = self.consume_expression(h)?;
 
                self.consume_whitespace(false)?;
 
                if self.has_string(b"..") || self.has_string(b":") {
 
                    position = self.source.pos();
 
                    if self.has_string(b"..") {
 
                        self.consume_string(b"..")?;
 
                    } else {
 
                        self.consume_string(b":")?;
 
                    }
 
                    self.consume_whitespace(false)?;
 
                    let to_index = self.consume_expression(h)?;
 
                    self.consume_whitespace(false)?;
 
                    result = h
 
                        .alloc_slicing_expression(|this| SlicingExpression {
 
                            this,
 
                            position,
 
                            subject,
 
                            from_index: index,
 
                            to_index,
 
                        })
 
                        .upcast();
 
                } else {
 
                    result = h
 
                        .alloc_indexing_expression(|this| IndexingExpression {
 
                            this,
 
                            position,
 
                            subject,
 
                            index,
 
                        })
 
                        .upcast();
 
                }
 
                self.consume_string(b"]")?;
 
                self.consume_whitespace(false)?;
 
            } else {
 
                assert!(self.has_string(b"."));
 
                self.consume_string(b".")?;
 
                self.consume_whitespace(false)?;
 
                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)?);
 
                }
 
                result = h
 
                    .alloc_select_expression(|this| SelectExpression {
 
                        this,
 
                        position,
 
                        subject,
 
                        field,
 
                    })
 
                    .upcast();
 
            }
 
        }
 
        Ok(result)
 
    }
 
    fn consume_primary_expression(&mut self, h: &mut Heap) -> Result<ExpressionId, ParseError> {
 
        if self.has_string(b"(") {
 
            return self.consume_paren_expression(h);
 
        }
 
        if self.has_string(b"{") {
 
            return Ok(self.consume_array_expression(h)?.upcast());
 
        }
 
        if self.has_constant()
 
            || self.has_keyword(b"null")
 
            || self.has_keyword(b"true")
 
            || self.has_keyword(b"false")
 
        {
 
            return Ok(self.consume_constant_expression(h)?.upcast());
 
        }
 
        if self.has_call_expression() {
 
            return Ok(self.consume_call_expression(h)?.upcast());
 
        }
 
        Ok(self.consume_variable_expression(h)?.upcast())
 
    }
 
    fn consume_array_expression(&mut self, h: &mut Heap) -> Result<ArrayExpressionId, ParseError> {
 
        let position = self.source.pos();
 
        let mut elements = Vec::new();
 
        self.consume_string(b"{")?;
 
        self.consume_whitespace(false)?;
 
        if !self.has_string(b"}") {
 
            while self.source.next().is_some() {
 
                elements.push(self.consume_expression(h)?);
 
                self.consume_whitespace(false)?;
 
                if self.has_string(b"}") {
 
                    break;
 
                }
 
                self.consume_string(b",")?;
 
                self.consume_whitespace(false)?;
 
            }
 
        }
 
        self.consume_string(b"}")?;
 
        Ok(h.alloc_array_expression(|this| ArrayExpression { this, position, elements }))
 
    }
 
    fn has_constant(&self) -> bool {
 
        is_constant(self.source.next())
 
    }
 
    fn consume_constant_expression(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<ConstantExpressionId, ParseError> {
 
        let position = self.source.pos();
 
        let value;
 
        if self.has_keyword(b"null") {
 
            self.consume_keyword(b"null")?;
 
            value = Constant::Null;
 
        } else if self.has_keyword(b"true") {
 
            self.consume_keyword(b"true")?;
 
            value = Constant::True;
 
        } else if self.has_keyword(b"false") {
 
            self.consume_keyword(b"false")?;
 
            value = Constant::False;
 
        } else if self.source.next() == Some(b'\'') {
 
            self.source.consume();
 
            let mut data = Vec::new();
 
            let mut next = self.source.next();
 
            while next != Some(b'\'') && (is_vchar(next) || next == Some(b' ')) {
 
                data.push(next.unwrap());
 
                self.source.consume();
 
                next = self.source.next();
 
            }
 
            if next != Some(b'\'') || data.is_empty() {
 
                return Err(self.source.error("Expected character constant"));
 
            }
 
            self.source.consume();
 
            value = Constant::Character(data);
 
        } else {
 
            let mut data = Vec::new();
 
            let mut next = self.source.next();
 
            if !is_integer_start(next) {
 
            if !self.has_integer() {
 
                return Err(self.source.error("Expected integer constant"));
 
            }
 
            while is_integer_rest(next) {
 
                data.push(next.unwrap());
 
                self.source.consume();
 
                next = self.source.next();
 
            }
 
            value = Constant::Integer(data);
 

	
 
            value = Constant::Integer(self.consume_integer()?);
 
        }
 
        Ok(h.alloc_constant_expression(|this| ConstantExpression { this, position, value }))
 
    }
 
    fn has_call_expression(&mut self) -> bool {
 
        /* We prevent ambiguity with variables, by looking ahead
 
        the identifier to see if we can find an opening
 
        parenthesis: this signals a call expression. */
 
        if self.has_builtin_keyword() {
 
            return true;
 
        }
 
        let backup_pos = self.source.pos();
 
        let mut result = false;
 
        match self.consume_identifier_spilled() {
 
            Ok(_) => match self.consume_whitespace(false) {
 
                Ok(_) => {
 
                    result = self.has_string(b"(");
 
                }
 
                Err(_) => {}
 
            },
 
            Err(_) => {}
 
        }
 
        self.source.seek(backup_pos);
 
        return result;
 
    }
 
    fn consume_call_expression(&mut self, h: &mut Heap) -> Result<CallExpressionId, ParseError> {
 
        let position = self.source.pos();
 
        let method;
 
        if self.has_keyword(b"get") {
 
            self.consume_keyword(b"get")?;
 
            method = Method::Get;
 
        } else if self.has_keyword(b"fires") {
 
            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)
 
        }
 
        self.consume_whitespace(false)?;
 
        let mut arguments = Vec::new();
 
        self.consume_string(b"(")?;
 
        self.consume_whitespace(false)?;
 
        if !self.has_string(b")") {
 
            while self.source.next().is_some() {
 
                arguments.push(self.consume_expression(h)?);
 
                self.consume_whitespace(false)?;
 
                if self.has_string(b")") {
 
                    break;
 
                }
 
                self.consume_string(b",")?;
 
                self.consume_whitespace(false)?
 
            }
 
        }
 
        self.consume_string(b")")?;
 
        Ok(h.alloc_call_expression(|this| CallExpression {
 
            this,
 
            position,
 
            method,
 
            arguments,
 
            declaration: None,
 
        }))
 
    }
 
    fn consume_variable_expression(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<VariableExpressionId, ParseError> {
 
        let position = self.source.pos();
 
        let identifier = self.consume_identifier(h)?;
 
        Ok(h.alloc_variable_expression(|this| VariableExpression {
 
            this,
 
            position,
 
            identifier,
 
            declaration: None,
 
        }))
 
    }
 

	
 
    // ====================
 
    // Statements
 
    // ====================
 

	
 
    fn consume_statement(&mut self, h: &mut Heap) -> Result<StatementId, ParseError> {
 
        if self.level >= MAX_LEVEL {
 
            return Err(self.source.error("Too deeply nested statement"));
 
        }
 
        self.level += 1;
 
        let result = self.consume_statement_impl(h);
 
        self.level -= 1;
 
        result
 
    }
 
    fn has_label(&mut self) -> bool {
 
        /* To prevent ambiguity with expression statements consisting
 
        only of an identifier, we look ahead and match the colon
 
        that signals a labeled statement. */
 
        let backup_pos = self.source.pos();
 
        let mut result = false;
 
        match self.consume_identifier_spilled() {
 
            Ok(_) => match self.consume_whitespace(false) {
 
                Ok(_) => {
 
                    result = self.has_string(b":");
 
                }
 
                Err(_) => {}
 
            },
 
            Err(_) => {}
 
        }
 
        self.source.seek(backup_pos);
 
        return result;
 
    }
 
    fn consume_statement_impl(&mut self, h: &mut Heap) -> Result<StatementId, ParseError> {
 
        if self.has_string(b"{") {
 
            Ok(self.consume_block_statement(h)?)
 
        } else if self.has_keyword(b"skip") {
 
            Ok(self.consume_skip_statement(h)?.upcast())
 
        } else if self.has_keyword(b"if") {
 
            Ok(self.consume_if_statement(h)?.upcast())
 
        } else if self.has_keyword(b"while") {
 
            Ok(self.consume_while_statement(h)?.upcast())
 
        } else if self.has_keyword(b"break") {
 
            Ok(self.consume_break_statement(h)?.upcast())
 
        } else if self.has_keyword(b"continue") {
 
            Ok(self.consume_continue_statement(h)?.upcast())
 
        } else if self.has_keyword(b"synchronous") {
 
            Ok(self.consume_synchronous_statement(h)?.upcast())
 
        } else if self.has_keyword(b"return") {
 
            Ok(self.consume_return_statement(h)?.upcast())
 
        } else if self.has_keyword(b"assert") {
 
            Ok(self.consume_assert_statement(h)?.upcast())
 
        } else if self.has_keyword(b"goto") {
 
            Ok(self.consume_goto_statement(h)?.upcast())
 
        } else if self.has_keyword(b"new") {
 
            Ok(self.consume_new_statement(h)?.upcast())
 
        } else if self.has_keyword(b"put") {
 
            Ok(self.consume_put_statement(h)?.upcast())
 
        } else if self.has_label() {
 
            Ok(self.consume_labeled_statement(h)?.upcast())
 
        } else {
 
            Ok(self.consume_expression_statement(h)?.upcast())
 
        }
 
    }
 
    fn has_local_statement(&mut self) -> bool {
 
        /* To avoid ambiguity, we look ahead to find either the
 
        channel keyword that signals a variable declaration, or
 
        a type annotation followed by another identifier.
 
        Example:
 
          my_type[] x = {5}; // memory statement
 
          my_var[5] = x; // assignment expression, expression statement
 
        Note how both the local and the assignment
 
        start with arbitrary identifier followed by [. */
 
        if self.has_keyword(b"channel") {
 
            return true;
 
        }
 
        if self.has_statement_keyword() {
 
            return false;
 
        }
 
        let backup_pos = self.source.pos();
 
        let mut result = false;
 
        if let Ok(_) = self.consume_type_annotation_spilled() {
 
            if let Ok(_) = self.consume_whitespace(false) {
 
                result = self.has_identifier();
 
            }
 
        }
 
        self.source.seek(backup_pos);
 
        return result;
 
    }
 
    fn consume_block_statement(&mut self, h: &mut Heap) -> Result<StatementId, ParseError> {
 
        let position = self.source.pos();
 
        let mut statements = Vec::new();
 
        self.consume_string(b"{")?;
 
        self.consume_whitespace(false)?;
 
        while self.has_local_statement() {
 
            statements.push(self.consume_local_statement(h)?.upcast());
 
            self.consume_whitespace(false)?;
 
        }
 
        while !self.has_string(b"}") {
 
            statements.push(self.consume_statement(h)?);
 
            self.consume_whitespace(false)?;
 
        }
 
        self.consume_string(b"}")?;
 
        if statements.is_empty() {
 
            Ok(h.alloc_skip_statement(|this| SkipStatement { this, position, next: None }).upcast())
 
        } else {
 
            Ok(h.alloc_block_statement(|this| BlockStatement {
 
                this,
 
                position,
 
                statements,
 
                parent_scope: None,
 
                locals: Vec::new(),
 
                labels: Vec::new(),
 
            })
 
            .upcast())
 
        }
 
@@ -1385,374 +1422,431 @@ impl Lexer<'_> {
 
            label,
 
            target: None,
 
        }))
 
    }
 
    fn consume_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<SynchronousStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"synchronous")?;
 
        self.consume_whitespace(false)?;
 
        let mut parameters = Vec::new();
 
        if self.has_string(b"(") {
 
            self.consume_parameters(h, &mut parameters)?;
 
            self.consume_whitespace(false)?;
 
        } else if !self.has_keyword(b"skip") && !self.has_string(b"{") {
 
            return Err(self.source.error("Expected block statement"));
 
        }
 
        let body = self.consume_statement(h)?;
 
        Ok(h.alloc_synchronous_statement(|this| SynchronousStatement {
 
            this,
 
            position,
 
            parameters,
 
            body,
 
            parent_scope: None,
 
        }))
 
    }
 
    fn consume_return_statement(&mut self, h: &mut Heap) -> Result<ReturnStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"return")?;
 
        self.consume_whitespace(false)?;
 
        let expression = if self.has_string(b"(") {
 
            self.consume_paren_expression(h)
 
        } else {
 
            self.consume_expression(h)
 
        }?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_return_statement(|this| ReturnStatement { this, position, expression }))
 
    }
 
    fn consume_assert_statement(&mut self, h: &mut Heap) -> Result<AssertStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"assert")?;
 
        self.consume_whitespace(false)?;
 
        let expression = if self.has_string(b"(") {
 
            self.consume_paren_expression(h)
 
        } else {
 
            self.consume_expression(h)
 
        }?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_assert_statement(|this| AssertStatement {
 
            this,
 
            position,
 
            expression,
 
            next: None,
 
        }))
 
    }
 
    fn consume_goto_statement(&mut self, h: &mut Heap) -> Result<GotoStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"goto")?;
 
        self.consume_whitespace(false)?;
 
        let label = self.consume_identifier(h)?;
 
        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, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"new")?;
 
        self.consume_whitespace(false)?;
 
        let expression = self.consume_call_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_new_statement(|this| NewStatement { this, position, expression, next: None }))
 
    }
 
    fn consume_put_statement(&mut self, h: &mut Heap) -> Result<PutStatementId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"put")?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b"(")?;
 
        let port = self.consume_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b",")?;
 
        self.consume_whitespace(false)?;
 
        let message = self.consume_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b")")?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_put_statement(|this| PutStatement { this, position, port, message, next: None }))
 
    }
 
    fn consume_expression_statement(
 
        &mut self,
 
        h: &mut Heap,
 
    ) -> Result<ExpressionStatementId, ParseError> {
 
        let position = self.source.pos();
 
        let expression = self.consume_expression(h)?;
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_expression_statement(|this| ExpressionStatement {
 
            this,
 
            position,
 
            expression,
 
            next: None,
 
        }))
 
    }
 

	
 
    // ====================
 
    // Symbol definitions
 
    // ====================
 

	
 
    fn has_symbol_definition(&self) -> bool {
 
        self.has_keyword(b"composite")
 
            || self.has_keyword(b"primitive")
 
            || self.has_type_keyword()
 
            || self.has_identifier()
 
    }
 
    fn consume_symbol_definition(&mut self, h: &mut Heap) -> Result<DefinitionId, ParseError> {
 
        if self.has_keyword(b"composite") || self.has_keyword(b"primitive") {
 
            Ok(self.consume_component_definition(h)?.upcast())
 
        } else {
 
            Ok(self.consume_function_definition(h)?.upcast())
 
        }
 
    }
 
    fn consume_component_definition(&mut self, h: &mut Heap) -> Result<ComponentId, ParseError> {
 
        if self.has_keyword(b"composite") {
 
            Ok(self.consume_composite_definition(h)?.upcast())
 
        } else {
 
            Ok(self.consume_primitive_definition(h)?.upcast())
 
        }
 
    }
 
    fn consume_composite_definition(&mut self, h: &mut Heap) -> Result<CompositeId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"composite")?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        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 }))
 
    }
 
    fn consume_primitive_definition(&mut self, h: &mut Heap) -> Result<PrimitiveId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"primitive")?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        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 }))
 
    }
 
    fn consume_function_definition(&mut self, h: &mut Heap) -> Result<FunctionId, ParseError> {
 
        let position = self.source.pos();
 
        let return_type = self.consume_type_annotation(h)?;
 
        self.consume_whitespace(true)?;
 
        let identifier = self.consume_identifier(h)?;
 
        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 {
 
            this,
 
            position,
 
            return_type,
 
            identifier,
 
            parameters,
 
            body,
 
        }))
 
    }
 
    fn has_pragma(&self) -> bool {
 
        if let Some(c) = self.source.next() {
 
            c == b'#'
 
        } else {
 
            false
 
        }
 
    }
 
    fn consume_pragma(&mut self, h: &mut Heap) -> Result<PragmaId, ParseError> {
 
        let position = self.source.pos();
 
        let next = self.source.next();
 
        if next != Some(b'#') {
 
            return Err(self.source.error("Expected pragma"));
 
        }
 
        self.source.consume();
 
        if !is_vchar(self.source.next()) {
 
            return Err(self.source.error("Expected pragma"));
 
        }
 
        let value = self.consume_line()?;
 
        Ok(h.alloc_pragma(|this| Pragma { this, position, value }))
 
        if self.has_string(b"version") {
 
            self.consume_string(b"version")?;
 
            self.consume_whitespace(true)?;
 
            if !self.has_integer() {
 
                return Err(self.source.error("Expected integer constant"));
 
            }
 
            let version = self.consume_integer()?;
 
            debug_assert!(version >= 0);
 
            return Ok(h.alloc_pragma(|this| Pragma::Version(PragmaVersion{
 
                this, position, version: version as u64
 
            })))
 
        } else if self.has_string(b"module") {
 
            self.consume_string(b"module")?;
 
            self.consume_whitespace(true)?;
 
            if !self.has_identifier() {
 
                return Err(self.source.error("Expected identifier"));
 
            }
 
            let mut value = Vec::new();
 
            let mut ident = self.consume_ident()?;
 
            value.append(&mut ident);
 
            while self.has_string(b".") {
 
                self.consume_string(b".")?;
 
                value.push(b'.');
 
                ident = self.consume_ident()?;
 
                value.append(&mut ident);
 
            }
 
            return Ok(h.alloc_pragma(|this| Pragma::Module(PragmaModule{
 
                this, position, value
 
            })));
 
        } else {
 
            return Err(self.source.error("Unknown pragma"));
 
        }
 
    }
 
    fn has_import(&self) -> bool {
 
        self.has_keyword(b"import")
 
    }
 
    fn consume_import(&mut self, h: &mut Heap) -> Result<ImportId, ParseError> {
 
        let position = self.source.pos();
 
        self.consume_keyword(b"import")?;
 
        self.consume_whitespace(true)?;
 
        let mut value = Vec::new();
 
        let mut ident = self.consume_ident()?;
 
        value.append(&mut ident);
 
        while self.has_string(b".") {
 
            self.consume_string(b".")?;
 
            value.push(b'.');
 
            ident = self.consume_ident()?;
 
            value.append(&mut ident);
 
        }
 
        self.consume_whitespace(false)?;
 
        self.consume_string(b";")?;
 
        Ok(h.alloc_import(|this| Import { this, position, value }))
 
    }
 
    pub fn consume_protocol_description(&mut self, h: &mut Heap) -> Result<RootId, ParseError> {
 
        let position = self.source.pos();
 
        let mut pragmas = Vec::new();
 
        let mut imports = Vec::new();
 
        let mut definitions = Vec::new();
 
        self.consume_whitespace(false)?;
 
        while self.has_pragma() {
 
            let pragma = self.consume_pragma(h)?;
 
            pragmas.push(pragma);
 
            self.consume_whitespace(false)?;
 
        }
 
        while self.has_import() {
 
            let import = self.consume_import(h)?;
 
            imports.push(import);
 
            self.consume_whitespace(false)?;
 
        }
 
        // do-while block
 
        while {
 
            let def = self.consume_symbol_definition(h)?;
 
            definitions.push(def);
 
            self.consume_whitespace(false)?;
 
            self.has_symbol_definition()
 
        } {}
 
        // end of file
 
        if !self.source.is_eof() {
 
            return Err(self.source.error("Expected end of file"));
 
        }
 
        Ok(h.alloc_protocol_description(|this| Root {
 
            this,
 
            position,
 
            pragmas,
 
            imports,
 
            definitions,
 
            declarations: Vec::new(),
 
        }))
 
    }
 
}
 

	
 
// #[cfg(test)]
 
// mod tests {
 
//     use crate::protocol::ast::Expression::*;
 
//     use crate::protocol::{ast, lexer::*};
 
#[cfg(test)]
 
mod tests {
 
    use crate::protocol::ast::Expression::*;
 
    use crate::protocol::{ast, lexer::*};
 

	
 
    #[test]
 
    fn test_pragmas() {
 
        let mut h = Heap::new();
 
        let mut input = InputSource::from_string("
 
        #version 0o7777
 
        #module something.dot.separated
 
        ").expect("new InputSource");
 
        let mut lex = Lexer::new(&mut input);
 
        let lexed = lex.consume_protocol_description(&mut h)
 
            .expect("lex input source");
 
        let root = &h[lexed];
 
        assert_eq!(root.pragmas.len(), 2);
 
        let pv = &h[root.pragmas[0]];
 
        let pm = &h[root.pragmas[1]];
 

	
 
        if let Pragma::Version(v) = pv {
 
            assert_eq!(v.version, 0o7777)
 
        } else {
 
            assert!(false, "first pragma not version");
 
        }
 
        if let Pragma::Module(m) = pm {
 
            assert_eq!(m.value, b"something.dot.separated");
 
        } else {
 
            assert!(false, "second pragma not version");
 
        }
 
    }
 

	
 
//     #[test]
 
//     fn test_lowercase() {
 
//         assert_eq!(lowercase(b'a'), b'a');
 
//         assert_eq!(lowercase(b'A'), b'a');
 
//         assert_eq!(lowercase(b'z'), b'z');
 
//         assert_eq!(lowercase(b'Z'), b'z');
 
//     }
 

	
 
//     #[test]
 
//     fn test_basic_expression() {
 
//         let mut h = Heap::new();
 
//         let mut is = InputSource::from_string("a+b;").unwrap();
 
//         let mut lex = Lexer::new(&mut is);
 
//         match lex.consume_expression(&mut h) {
 
//             Ok(expr) => {
 
//                 println!("{:?}", expr);
 
//                 if let Binary(bin) = &h[expr] {
 
//                     if let Variable(left) = &h[bin.left] {
 
//                         if let Variable(right) = &h[bin.right] {
 
//                             assert_eq!("a", format!("{}", h[left.identifier]));
 
//                             assert_eq!("b", format!("{}", h[right.identifier]));
 
//                             assert_eq!(Some(b';'), is.next());
 
//                             return;
 
//                         }
 
//                     }
 
//                 }
 
//                 assert!(false);
 
//             }
 
//             Err(err) => {
 
//                 err.print(&is);
 
//                 assert!(false);
 
//             }
 
//         }
 
//     }
 

	
 
//     #[test]
 
//     fn test_paren_expression() {
 
//         let mut h = Heap::new();
 
//         let mut is = InputSource::from_string("(true)").unwrap();
 
//         let mut lex = Lexer::new(&mut is);
 
//         match lex.consume_paren_expression(&mut h) {
 
//             Ok(expr) => {
 
//                 println!("{:#?}", expr);
 
//                 if let Constant(con) = &h[expr] {
 
//                     if let ast::Constant::True = con.value {
 
//                         return;
 
//                     }
 
//                 }
 
//                 assert!(false);
 
//             }
 
//             Err(err) => {
 
//                 err.print(&is);
 
//                 assert!(false);
 
//             }
 
//         }
 
//     }
 

	
 
//     #[test]
 
//     fn test_expression() {
 
//         let mut h = Heap::new();
 
//         let mut is = InputSource::from_string("(x(1+5,get(y))-w[5])+z++\n").unwrap();
 
//         let mut lex = Lexer::new(&mut is);
 
//         match lex.consume_expression(&mut h) {
 
//             Ok(expr) => {
 
//                 println!("{:#?}", expr);
 
//             }
 
//             Err(err) => {
 
//                 err.print(&is);
 
//                 assert!(false);
 
//             }
 
//         }
 
//     }
 

	
 
//     #[test]
 
//     fn test_basic_statement() {
 
//         let mut h = Heap::new();
 
//         let mut is = InputSource::from_string("while (true) { skip; }").unwrap();
 
//         let mut lex = Lexer::new(&mut is);
 
//         match lex.consume_statement(&mut h) {
 
//             Ok(stmt) => {
 
//                 println!("{:#?}", stmt);
 
//                 if let Statement::While(w) = &h[stmt] {
 
//                     if let Expression::Constant(_) = h[w.test] {
 
//                         if let Statement::Block(_) = h[w.body] {
 
//                             return;
 
//                         }
 
//                     }
 
//                 }
 
//                 assert!(false);
 
//             }
 
//             Err(err) => {
 
//                 err.print(&is);
 
//                 assert!(false);
 
//             }
 
//         }
 
//     }
 

	
 
//     #[test]
 
//     fn test_statement() {
 
//         let mut h = Heap::new();
 
//         let mut is = InputSource::from_string(
 
//             "label: while (true) { if (x++ > y[0]) break label; else continue; }\n",
 
//         )
 
//         .unwrap();
 
//         let mut lex = Lexer::new(&mut is);
 
//         match lex.consume_statement(&mut h) {
 
//             Ok(stmt) => {
 
//                 println!("{:#?}", stmt);
 
//             }
 
//             Err(err) => {
 
//                 err.print(&is);
 
//                 assert!(false);
 
//             }
 
//         }
 
//     }
 
// }
 
}
src/protocol/mod.rs
Show inline comments
 
mod arena;
 
mod ast;
 
// mod ast;
 
mod eval;
 
pub(crate) mod inputsource;
 
mod lexer;
 
// mod lexer;
 
mod library;
 
mod parser;
 

	
 
// TODO: Remove when not benchmarking
 
pub(crate) mod ast;
 
pub(crate) mod lexer;
 

	
 
lazy_static::lazy_static! {
 
    /// Conveniently-provided protocol description initialized with a zero-length PDL string.
 
    /// Exposed to minimize repeated initializations of this common protocol description.
 
    pub static ref TRIVIAL_PD: std::sync::Arc<ProtocolDescription> = {
 
        std::sync::Arc::new(ProtocolDescription::parse(b"").unwrap())
 
    };
 
}
 

	
 
use crate::common::*;
 
use crate::protocol::ast::*;
 
use crate::protocol::eval::*;
 
use crate::protocol::inputsource::*;
 
use crate::protocol::parser::*;
 

	
 
/// Description of a protocol object, used to configure new connectors.
 
/// (De)serializable.
 
#[derive(serde::Serialize, serde::Deserialize)]
 
#[repr(C)]
 
pub struct ProtocolDescription {
 
    heap: Heap,
 
    source: InputSource,
 
    root: RootId,
 
}
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub(crate) struct ComponentState {
 
    prompt: Prompt,
 
}
 
pub(crate) enum EvalContext<'a> {
 
    Nonsync(&'a mut NonsyncProtoContext<'a>),
 
    Sync(&'a mut SyncProtoContext<'a>),
 
    // None,
 
}
 
//////////////////////////////////////////////
 

	
 
impl std::fmt::Debug for ProtocolDescription {
 
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 
        write!(f, "(An opaque protocol description)")
 
    }
 
}
 
impl ProtocolDescription {
 
    pub fn parse(buffer: &[u8]) -> Result<Self, String> {
 
        let mut heap = Heap::new();
 
        let mut source = InputSource::from_buffer(buffer).unwrap();
 
        let mut parser = Parser::new(&mut source);
 
        match parser.parse(&mut heap) {
 
            Ok(root) => {
 
                return Ok(ProtocolDescription { heap, source, root });
 
            }
 
            Err(err) => {
 
                let mut vec: Vec<u8> = Vec::new();
 
                err.write(&source, &mut vec).unwrap();
 
                Err(String::from_utf8_lossy(&vec).to_string())
 
            }
 
        }
 
    }
 
    pub(crate) fn component_polarities(
 
        &self,
 
        identifier: &[u8],
 
    ) -> Result<Vec<Polarity>, AddComponentError> {
 
        use AddComponentError::*;
 
        let h = &self.heap;
 
        let root = &h[self.root];
 
        let def = root.get_definition_ident(h, identifier);
 
        if def.is_none() {
 
            return Err(NoSuchComponent);
 
        }
 
        let def = &h[def.unwrap()];
 
        if !def.is_component() {
 
            return Err(NoSuchComponent);
 
        }
 
        for &param in def.parameters().iter() {
 
            let param = &h[param];
 
            let type_annot = &h[param.type_annotation];
 
            if type_annot.the_type.array {
 
                return Err(NonPortTypeParameters);
 
            }
 
            match type_annot.the_type.primitive {
 
                PrimitiveType::Input | PrimitiveType::Output => continue,
 
                _ => {
 
                    return Err(NonPortTypeParameters);
 
                }
 
            }
 
        }
 
        let mut result = Vec::new();
 
        for &param in def.parameters().iter() {
 
            let param = &h[param];
 
            let type_annot = &h[param.type_annotation];
 
            let ptype = &type_annot.the_type.primitive;
 
            if ptype == &PrimitiveType::Input {
 
                result.push(Polarity::Getter)
 
            } else if ptype == &PrimitiveType::Output {
 
                result.push(Polarity::Putter)
 
            } else {
 
                unreachable!()
 
            }
 
        }
 
        Ok(result)
 
    }
 
    // expects port polarities to be correct
 
    pub(crate) fn new_component(&self, identifier: &[u8], ports: &[PortId]) -> ComponentState {
 
        let mut args = Vec::new();
 
        for (&x, y) in ports.iter().zip(self.component_polarities(identifier).unwrap()) {
 
            match y {
 
                Polarity::Getter => args.push(Value::Input(InputValue(x))),
 
                Polarity::Putter => args.push(Value::Output(OutputValue(x))),
 
            }
 
        }
 
        let h = &self.heap;
 
        let root = &h[self.root];
 
        let def = root.get_definition_ident(h, identifier).unwrap();
 
        ComponentState { prompt: Prompt::new(h, def, &args) }
 
    }
 
}
 
impl ComponentState {
 
    pub(crate) fn nonsync_run<'a: 'b, 'b>(
 
        &'a mut self,
 
        context: &'b mut NonsyncProtoContext<'b>,
 
        pd: &'a ProtocolDescription,
 
    ) -> NonsyncBlocker {
 
        let mut context = EvalContext::Nonsync(context);
 
        loop {
 
            let result = self.prompt.step(&pd.heap, &mut context);
 
            match result {
 
                // In component definitions, there are no return statements
 
                Ok(_) => unreachable!(),
 
                Err(cont) => match cont {
 
                    EvalContinuation::Stepping => continue,
 
                    EvalContinuation::Inconsistent => return NonsyncBlocker::Inconsistent,
 
                    EvalContinuation::Terminal => return NonsyncBlocker::ComponentExit,
 
                    EvalContinuation::SyncBlockStart => return NonsyncBlocker::SyncBlockStart,
 
                    // Not possible to end sync block if never entered one
 
                    EvalContinuation::SyncBlockEnd => unreachable!(),
 
                    EvalContinuation::NewComponent(decl, args) => {
 
                        // Look up definition (TODO for now, assume it is a definition)
 
                        let h = &pd.heap;
 
                        let def = h[decl].as_defined().definition;
 
                        let init_state = ComponentState { prompt: Prompt::new(h, def, &args) };
 
                        context.new_component(&args, init_state);
 
                        // Continue stepping
 
                        continue;
 
                    }
 
                    // Outside synchronous blocks, no fires/get/put happens
 
                    EvalContinuation::BlockFires(_) => unreachable!(),
 
                    EvalContinuation::BlockGet(_) => unreachable!(),
 
                    EvalContinuation::Put(_, _) => unreachable!(),
 
                },
 
            }
 
        }
 
    }
 

	
 
    pub(crate) fn sync_run<'a: 'b, 'b>(
 
        &'a mut self,
 
        context: &'b mut SyncProtoContext<'b>,
 
        pd: &'a ProtocolDescription,
 
    ) -> SyncBlocker {
 
        let mut context = EvalContext::Sync(context);
 
        loop {
 
            let result = self.prompt.step(&pd.heap, &mut context);
 
            match result {
 
                // Inside synchronous blocks, there are no return statements
 
                Ok(_) => unreachable!(),
 
                Err(cont) => match cont {
 
                    EvalContinuation::Stepping => continue,
 
                    EvalContinuation::Inconsistent => return SyncBlocker::Inconsistent,
 
                    // First need to exit synchronous block before definition may end
 
                    EvalContinuation::Terminal => unreachable!(),
 
                    // No nested synchronous blocks
 
                    EvalContinuation::SyncBlockStart => unreachable!(),
 
                    EvalContinuation::SyncBlockEnd => return SyncBlocker::SyncBlockEnd,
 
                    // Not possible to create component in sync block
 
                    EvalContinuation::NewComponent(_, _) => unreachable!(),
 
                    EvalContinuation::BlockFires(port) => match port {
 
                        Value::Output(OutputValue(port)) => {
 
                            return SyncBlocker::CouldntCheckFiring(port);
 
                        }
 
                        Value::Input(InputValue(port)) => {
 
                            return SyncBlocker::CouldntCheckFiring(port);
 
                        }
 
                        _ => unreachable!(),
 
                    },
 
                    EvalContinuation::BlockGet(port) => match port {
 
                        Value::Output(OutputValue(port)) => {
 
                            return SyncBlocker::CouldntReadMsg(port);
 
                        }
 
                        Value::Input(InputValue(port)) => {
 
                            return SyncBlocker::CouldntReadMsg(port);
 
                        }
 
                        _ => unreachable!(),
 
                    },
 
                    EvalContinuation::Put(port, message) => {
 
                        let value;
 
                        match port {
src/protocol/parser/depth_visitor.rs
Show inline comments
 
new file 100644
src/protocol/parser/shallow_visitor.rs
Show inline comments
 
new file 100644
 
use crate::protocol::ast::*;
 
use crate::protocol::input_source::*;
 
use crate::protocol::lexer::*;
 

	
 
type Unit = ();
 
type VisitorResult = Result<Unit, ParseError>;
 

	
 
trait ShallowVisitor: Sized {
 
    fn visit_protocol_description(&mut self, h: &mut Heap, pd: RootId) -> 
 
}
 
\ No newline at end of file
src/protocol/parser/visitor.rs
Show inline comments
 
new file 100644
0 comments (0 inline, 0 general)