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
 
@@ -9,5 +9,10 @@ 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
 
@@ -1246,14 +1246,36 @@ impl SyntaxElement for Root {
 
}
 

	
 
#[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
 
    }
 
@@ -1481,7 +1503,7 @@ impl SyntaxElement for TypeAnnotation {
 
}
 

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

	
 
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 
pub enum Constant {
src/protocol/eval.rs
Show inline comments
 
@@ -68,10 +68,9 @@ impl Value {
 
            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 {
src/protocol/lexer.rs
Show inline comments
 
@@ -58,6 +58,7 @@ fn is_integer_rest(x: Option<u8>) -> bool {
 
            || c >= b'A' && c <= b'F'
 
            || c == b'x'
 
            || c == b'X'
 
            || c == b'o'
 
    } else {
 
        false
 
    }
 
@@ -219,6 +220,48 @@ impl Lexer<'_> {
 
        }
 
        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
 

	
 
@@ -1025,17 +1068,11 @@ impl Lexer<'_> {
 
            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 }))
 
    }
 
@@ -1574,8 +1611,38 @@ impl Lexer<'_> {
 
        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")
 
@@ -1635,10 +1702,37 @@ impl Lexer<'_> {
 
    }
 
}
 

	
 
// #[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() {
 
@@ -1755,4 +1849,4 @@ impl Lexer<'_> {
 
//             }
 
//         }
 
//     }
 
// }
 
}
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.
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)