Changeset - 5e11ebce9bc0
[Not reviewed]
0 5 0
Hans-Dieter Hiep - 5 years ago 2020-02-10 11:57:19
hdh@cwi.nl
Evaluator new_component and new_channel implemented
5 files changed with 103 insertions and 23 deletions:
0 comments (0 inline, 0 general)
src/protocol/ast.rs
Show inline comments
 
@@ -1344,25 +1344,25 @@ impl Display for ExternalIdentifier {
 
    }
 
}
 

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

	
 
impl SourceIdentifier {
 
    fn ident(&self) -> &[u8] {
 
    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 {
 
@@ -1818,24 +1818,30 @@ impl Declaration {
 
            Declaration::Imported(decl) => &decl.signature,
 
        }
 
    }
 
    pub fn identifier(&self) -> IdentifierId {
 
        self.signature().identifier()
 
    }
 
    pub fn is_component(&self) -> bool {
 
        self.signature().is_component()
 
    }
 
    pub fn is_function(&self) -> bool {
 
        self.signature().is_function()
 
    }
 
    pub fn as_defined(&self) -> &DefinedDeclaration {
 
        match self {
 
            Declaration::Defined(result) => result,
 
            _ => panic!("Unable to cast `Declaration` to `DefinedDeclaration`"),
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct DefinedDeclaration {
 
    pub this: DefinedDeclarationId,
 
    // Phase 2: linker
 
    pub definition: DefinitionId,
 
    pub signature: Signature,
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ImportedDeclaration {
 
@@ -2169,24 +2175,25 @@ impl BlockStatement {
 
                // nested synchronous statements are flagged illegal,
 
                // and that happens before resolving variables that
 
                // creates the parent_scope references in the first place.
 
                Some(h[parent].parent_scope(h).unwrap().to_block())
 
            }
 
            Scope::Block(parent) => {
 
                // A variable scope is either a definition, sync, or block.
 
                Some(parent)
 
            }
 
        }
 
    }
 
    pub fn first(&self) -> StatementId {
 
        // It is an invariant (guaranteed by the lexer) that block statements have at least one stmt
 
        *self.statements.first().unwrap()
 
    }
 
}
 

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

	
 
impl VariableScope for BlockStatement {
 
    fn parent_scope(&self, _h: &Heap) -> Option<Scope> {
src/protocol/eval.rs
Show inline comments
 
@@ -1366,25 +1366,25 @@ impl Store {
 
                match subject.set(&index, &value) {
 
                    Some(value) => Ok(value),
 
                    None => Err(EvalContinuation::Inconsistent),
 
                }
 
            }
 
            _ => unimplemented!("{:?}", h[lexpr]),
 
        }
 
    }
 
    fn get(&mut self, h: &Heap, rexpr: ExpressionId) -> EvalResult {
 
        match &h[rexpr] {
 
            Expression::Variable(var) => {
 
                let var = var.declaration.unwrap();
 
                let value = self.map.get(&var).unwrap();
 
                let value = self.map.get(&var).expect(&format!("Uninitialized variable {:?}", h[h[var].identifier()]));
 
                Ok(value.clone())
 
            }
 
            _ => unimplemented!("{:?}", h[rexpr]),
 
        }
 
    }
 
    fn eval(&mut self, h: &Heap, ctx: &mut EvalContext, expr: ExpressionId) -> EvalResult {
 
        match &h[expr] {
 
            Expression::Assignment(expr) => {
 
                let value = self.eval(h, ctx, expr.right)?;
 
                match expr.operation {
 
                    AssignmentOperator::Set => {
 
                        self.update(h, ctx, expr.left, value.clone());
 
@@ -1476,25 +1476,25 @@ impl Store {
 
            Expression::Variable(expr) => self.get(h, expr.this.upcast()),
 
        }
 
    }
 
}
 

	
 
type EvalResult = Result<Value, EvalContinuation>;
 
pub enum EvalContinuation {
 
    Stepping,
 
    Inconsistent,
 
    Terminal,
 
    SyncBlockStart,
 
    SyncBlockEnd,
 
    NewComponent(Vec<Value>),
 
    NewComponent(DeclarationId, Vec<Value>),
 
    BlockFires(Value),
 
    BlockGet(Value),
 
    Put(Value, Value),
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Prompt {
 
    definition: DefinitionId,
 
    store: Store,
 
    position: Option<StatementId>,
 
}
 

	
 
@@ -1524,25 +1524,30 @@ impl Prompt {
 
                    // Continue to first statement
 
                    self.position = Some(stmt.first());
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::Local(stmt) => {
 
                    match stmt {
 
                        LocalStatement::Memory(stmt) => {
 
                            // Evaluate initial expression
 
                            let value = self.store.eval(h, ctx, stmt.initial)?;
 
                            // Update store
 
                            self.store.initialize(h, stmt.variable.upcast(), value);
 
                        }
 
                        LocalStatement::Channel(stmt) => unimplemented!(),
 
                        LocalStatement::Channel(stmt) => {
 
                            let [from, to] = ctx.new_channel();
 
                            // Store the values in the declared variables
 
                            self.store.initialize(h, stmt.from.upcast(), from);
 
                            self.store.initialize(h, stmt.to.upcast(), to);
 
                        },
 
                    }
 
                    // Continue to next statement
 
                    self.position = stmt.next();
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::Skip(stmt) => {
 
                    // Continue to next statement
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::Labeled(stmt) => {
 
                    // Continue to next statement
 
@@ -1582,74 +1587,104 @@ impl Prompt {
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::Synchronous(stmt) => {
 
                    // Continue to next statement, and signal upward
 
                    self.position = Some(stmt.body);
 
                    Err(EvalContinuation::SyncBlockStart)
 
                }
 
                Statement::EndSynchronous(stmt) => {
 
                    // Continue to next statement, and signal upward
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::SyncBlockEnd)
 
                }
 
                Statement::Break(stmt) => {
 
                    // Continue to end of while
 
                    self.position = stmt.target.map(EndWhileStatementId::upcast);
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::Continue(stmt) => {
 
                    // Continue to beginning of while
 
                    self.position = stmt.target.map(WhileStatementId::upcast);
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::Assert(stmt) => {
 
                    // Evaluate expression
 
                    let value = self.store.eval(h, ctx, stmt.expression)?;
 
                    if value.as_boolean().0 {
 
                        // Continue to next statement
 
                        self.position = stmt.next;
 
                        Err(EvalContinuation::Stepping)
 
                    } else {
 
                        // Assertion failed: inconsistent
 
                        Err(EvalContinuation::Inconsistent)
 
                    }
 
                }
 
                Statement::Return(stmt) => {
 
                    // Evaluate expression
 
                    let value = self.store.eval(h, ctx, stmt.expression)?;
 
                    // Done with evaluation
 
                    Ok(value)
 
                }
 
                Statement::Goto(stmt) => {
 
                    // Continue to target
 
                    self.position = stmt.target.map(|x| x.upcast());
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                Statement::New(stmt) => todo!(),
 
                Statement::New(stmt) => {
 
                    let expr = &h[stmt.expression];
 
                    let mut args = Vec::new();
 
                    for &arg in expr.arguments.iter() {
 
                        let value = self.store.eval(h, ctx, arg)?;
 
                        args.push(value);
 
                    }
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::NewComponent(expr.declaration.unwrap(), args))
 
                }
 
                Statement::Put(stmt) => {
 
                    // Evaluate port and message
 
                    let port = self.store.eval(h, ctx, stmt.port)?;
 
                    let message = self.store.eval(h, ctx, stmt.message)?;
 
                    // Continue to next statement
 
                    self.position = stmt.next;
 
                    // Signal the put upwards
 
                    Err(EvalContinuation::Put(port, message))
 
                }
 
                Statement::Expression(stmt) => {
 
                    // Evaluate expression
 
                    let value = self.store.eval(h, ctx, stmt.expression)?;
 
                    // Continue to next statement
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::Stepping)
 
                }
 
                _ => unimplemented!("{:?}", stmt),
 
            }
 
        } else {
 
            Err(EvalContinuation::Terminal)
 
        }
 
    }
 
    fn compute_function(h: &Heap, fun: FunctionId, args: &Vec<Value>) -> Option<Value> {
 
        let mut prompt = Self::new(h, fun.upcast(), args);
 
        let mut context = EvalContext::None;
 
        loop {
 
            let result = prompt.step(h, &mut context);
 
            match result {
 
                Ok(val) => return Some(val),
 
                Err(cont) => match cont {
 
                    EvalContinuation::Stepping => continue,
 
                    EvalContinuation::Inconsistent => return None,
 
                    // Functions never terminate without returning
 
                    EvalContinuation::Terminal => unreachable!(),
 
                    // Functions never encounter any blocking behavior
 
                    EvalContinuation::SyncBlockStart => unreachable!(),
 
                    EvalContinuation::SyncBlockEnd => unreachable!(),
 
                    EvalContinuation::NewComponent(args) => unreachable!(),
 
                    EvalContinuation::NewComponent(_, _) => unreachable!(),
 
                    EvalContinuation::BlockFires(val) => unreachable!(),
 
                    EvalContinuation::BlockGet(val) => unreachable!(),
 
                    EvalContinuation::Put(port, msg) => unreachable!(),
 
                },
 
            }
 
        }
 
    }
 
}
 

	
 
#[cfg(test)]
 
mod tests {
 
    extern crate test_generator;
 
@@ -1660,26 +1695,25 @@ mod tests {
 
    use test_generator::test_resources;
 

	
 
    use super::*;
 

	
 
    #[test_resources("testdata/eval/positive/*.pdl")]
 
    fn batch1(resource: &str) {
 
        let path = Path::new(resource);
 
        let expect = path.with_extension("txt");
 
        let mut heap = Heap::new();
 
        let mut source = InputSource::from_file(&path).unwrap();
 
        let mut parser = Parser::new(&mut source);
 
        let pd = parser.parse(&mut heap).unwrap();
 
        let test = heap.get_external_identifier(b"test");
 
        let def = heap[pd].get_definition(&heap, test.upcast()).unwrap();
 
        let def = heap[pd].get_definition_ident(&heap, b"test").unwrap();
 
        let fun = heap[def].as_function().this;
 
        let args = Vec::new();
 
        let result = Prompt::compute_function(&heap, fun, &args).unwrap();
 
        let valstr: String = format!("{}", result);
 
        println!("{}", valstr);
 

	
 
        let mut cev: Vec<u8> = Vec::new();
 
        let mut f = File::open(expect).unwrap();
 
        f.read_to_end(&mut cev).unwrap();
 
        let lavstr = String::from_utf8_lossy(&cev);
 
        println!("{}", lavstr);
 

	
src/protocol/mod.rs
Show inline comments
 
@@ -112,26 +112,32 @@ impl ComponentState for ComponentStateImpl {
 
        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 MonoBlocker::Inconsistent,
 
                    EvalContinuation::Terminal => return MonoBlocker::ComponentExit,
 
                    EvalContinuation::SyncBlockStart => return MonoBlocker::SyncBlockStart,
 
                    // Not possible to end sync block if never entered one
 
                    EvalContinuation::SyncBlockEnd => unreachable!(),
 
                    EvalContinuation::NewComponent(args) => {
 
                        todo!();
 
                    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;
 
                        println!("Create component: {}",  String::from_utf8_lossy(h[h[def].identifier()].ident()));
 
                        let init_state = ComponentStateImpl { 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(val) => unreachable!(),
 
                    EvalContinuation::BlockGet(val) => unreachable!(),
 
                    EvalContinuation::Put(port, msg) => unreachable!(),
 
                },
 
            }
 
        }
 
    }
 

	
 
    fn sync_run<C: PolyContext<D = ProtocolDescriptionImpl>>(
 
@@ -145,25 +151,25 @@ impl ComponentState for ComponentStateImpl {
 
            match result {
 
                // Inside synchronous blocks, there are no return statements
 
                Ok(_) => unreachable!(),
 
                Err(cont) => match cont {
 
                    EvalContinuation::Stepping => continue,
 
                    EvalContinuation::Inconsistent => return PolyBlocker::Inconsistent,
 
                    // First need to exit synchronous block before definition may end
 
                    EvalContinuation::Terminal => unreachable!(),
 
                    // No nested synchronous blocks
 
                    EvalContinuation::SyncBlockStart => unreachable!(),
 
                    EvalContinuation::SyncBlockEnd => return PolyBlocker::SyncBlockEnd,
 
                    // Not possible to create component in sync block
 
                    EvalContinuation::NewComponent(args) => unreachable!(),
 
                    EvalContinuation::NewComponent(_, _) => unreachable!(),
 
                    EvalContinuation::BlockFires(port) => match port {
 
                        Value::Output(OutputValue(key)) => {
 
                            return PolyBlocker::CouldntCheckFiring(key);
 
                        }
 
                        Value::Input(InputValue(key)) => {
 
                            return PolyBlocker::CouldntCheckFiring(key);
 
                        }
 
                        _ => unreachable!(),
 
                    },
 
                    EvalContinuation::BlockGet(port) => match port {
 
                        Value::Output(OutputValue(key)) => {
 
                            return PolyBlocker::CouldntReadMsg(key);
 
@@ -205,47 +211,69 @@ impl ComponentState for ComponentStateImpl {
 
}
 

	
 
pub enum EvalContext<'a> {
 
    Mono(&'a mut dyn MonoContext<D = ProtocolDescriptionImpl, S = ComponentStateImpl>),
 
    Poly(&'a mut dyn PolyContext<D = ProtocolDescriptionImpl>),
 
    None,
 
}
 
impl EvalContext<'_> {
 
    fn random(&mut self) -> LongValue {
 
        match self {
 
            EvalContext::None => unreachable!(),
 
            EvalContext::Mono(context) => todo!(),
 
            EvalContext::Poly(context) => unreachable!(),
 
            EvalContext::Poly(_) => unreachable!(),
 
        }
 
    }
 
    fn channel(&mut self) -> (Value, Value) {
 
    fn new_component(&mut self, args: &[Value], init_state: ComponentStateImpl) -> () {
 
        match self {
 
            EvalContext::None => unreachable!(),
 
            EvalContext::Mono(context) => unreachable!(),
 
            EvalContext::Poly(context) => todo!(),
 
            EvalContext::Mono(context) => {
 
                let mut moved_keys = HashSet::new();
 
                for arg in args.iter() {
 
                    match arg {
 
                        Value::Output(OutputValue(key)) => { moved_keys.insert(*key); }
 
                        Value::Input(InputValue(key)) => { moved_keys.insert(*key); }
 
                        _ => {}
 
                    }
 
                }
 
                context.new_component(moved_keys, init_state)
 
            }
 
            EvalContext::Poly(_) => unreachable!(),
 
        }
 
    }
 
    fn new_channel(&mut self) -> [Value; 2] {
 
        match self {
 
            EvalContext::None => unreachable!(),
 
            EvalContext::Mono(context) => {
 
                let [from, to] = context.new_channel();
 
                let from = Value::Output(OutputValue(from));
 
                let to = Value::Input(InputValue(to));
 
                return [from, to];
 
            }
 
            EvalContext::Poly(_) => unreachable!()
 
        }
 
    }
 
    fn fires(&mut self, port: Value) -> Option<Value> {
 
        match self {
 
            EvalContext::None => unreachable!(),
 
            EvalContext::Mono(context) => unreachable!(),
 
            EvalContext::Mono(_) => unreachable!(),
 
            EvalContext::Poly(context) => match port {
 
                Value::Output(OutputValue(key)) => context.is_firing(key).map(Value::from),
 
                Value::Input(InputValue(key)) => context.is_firing(key).map(Value::from),
 
                _ => unreachable!(),
 
            },
 
        }
 
    }
 
    fn get(&mut self, port: Value) -> Option<Value> {
 
        match self {
 
            EvalContext::None => unreachable!(),
 
            EvalContext::Mono(context) => unreachable!(),
 
            EvalContext::Mono(_) => unreachable!(),
 
            EvalContext::Poly(context) => match port {
 
                Value::Output(OutputValue(key)) => {
 
                    context.read_msg(key).map(Value::receive_message)
 
                }
 
                Value::Input(InputValue(key)) => context.read_msg(key).map(Value::receive_message),
 
                _ => unreachable!(),
 
            },
 
        }
 
    }
 
}
src/protocol/parser.rs
Show inline comments
 
@@ -1073,53 +1073,53 @@ struct UniqueStatementId(StatementId);
 
struct LinkStatements {
 
    prev: Option<UniqueStatementId>,
 
}
 

	
 
impl LinkStatements {
 
    fn new() -> Self {
 
        LinkStatements { prev: None }
 
    }
 
}
 

	
 
impl Visitor for LinkStatements {
 
    fn visit_statement(&mut self, h: &mut Heap, stmt: StatementId) -> VisitorResult {
 
        if let Some(UniqueStatementId(prev)) = std::mem::replace(&mut self.prev, None) {
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(stmt);
 
        }
 
        recursive_statement(self, h, stmt)
 
    }
 
    fn visit_local_statement(&mut self, _h: &mut Heap, stmt: LocalStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_labeled_statement(&mut self, h: &mut Heap, stmt: LabeledStatementId) -> VisitorResult {
 
        recursive_labeled_statement(self, h, stmt)
 
    }
 
    fn visit_skip_statement(&mut self, _h: &mut Heap, stmt: SkipStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_if_statement(&mut self, h: &mut Heap, stmt: IfStatementId) -> VisitorResult {
 
        // We allocate a pseudo-statement, which combines both branches into one next statement
 
        let position = h[stmt].position;
 
        let pseudo =
 
            h.alloc_end_if_statement(|this| EndIfStatement { this, position, next: None }).upcast();
 
        assert!(self.prev.is_none());
 
        self.visit_statement(h, h[stmt].true_body)?;
 
        if let Some(UniqueStatementId(prev)) = std::mem::replace(&mut self.prev, None) {
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(pseudo);
 
        }
 
        assert!(self.prev.is_none());
 
        self.visit_statement(h, h[stmt].false_body)?;
 
        if let Some(UniqueStatementId(prev)) = std::mem::replace(&mut self.prev, None) {
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(pseudo);
 
        }
 
        // Use the pseudo-statement as the statement where to update the next pointer
 
        self.prev = Some(UniqueStatementId(pseudo));
 
        Ok(())
 
    }
 
    fn visit_while_statement(&mut self, h: &mut Heap, stmt: WhileStatementId) -> VisitorResult {
 
        // We allocate a pseudo-statement, to which the break statement finds its target
 
        let position = h[stmt].position;
 
        let pseudo =
 
            h.alloc_end_while_statement(|this| EndWhileStatement { this, position, next: None });
 
        // Update the while's next statement to point to the pseudo-statement
src/test/connector.rs
Show inline comments
 
@@ -515,44 +515,55 @@ fn alternator_2() {
 
            }
 
        },
 
    ]));
 
}
 

	
 
#[test]
 
// PANIC TODO: eval::1536
 
fn composite_chain() {
 
    // Check if composition works. Forward messages through long chains
 
    /*
 
    Alice -->sync-->sync-->A|P-->sync-->sync--> Bob
 
    */
 
    static PDL : &[u8] =
 
b"primitive sync(in i, out o) {
 
    while(true) synchronous {
 
        if (fires(i)) put(o, get(i));
 
    }
 
}
 
composite sync_2(in i, out o) {
 
    channel x -> y;
 
    new sync(i, x);
 
    new sync(y, o);
 
}";
 
    let timeout = Duration::from_millis(1_500);
 
    let addrs = [next_addr(), next_addr()];
 
    const N: usize = 1;
 
    static MSG: &[u8] = b"Hippity Hoppity";
 
    static MSG: &[u8] = b"SSS";
 
    assert!(run_connector_set(&[
 
        //
 
        &|x| {
 
            // Alice
 
            x.configure(PDL, b"sync_2").unwrap();
 
            x.bind_port(0, Native).unwrap();
 
            x.bind_port(1, Active(addrs[0])).unwrap();
 
            x.connect(timeout).unwrap();
 
            for _ in 0..N {
 
                x.put(0, MSG.to_vec()).unwrap();
 
                assert_eq!(0, x.sync(timeout).unwrap());
 
            }
 
        },
 
        &|x| {
 
            // Bob
 
            x.configure(PDL, b"sync_2").unwrap();
 
            x.configure(PDL, b"sync").unwrap();
 
            x.bind_port(0, Passive(addrs[0])).unwrap();
 
            x.bind_port(1, Native).unwrap();
 
            x.connect(timeout).unwrap();
 
            for _ in 0..N {
 
                // get msg round
 
                x.get(0).unwrap();
 
                assert_eq!(Ok(0), x.sync(timeout));
 
                assert_eq!(Ok(MSG), x.read_gotten(0));
 
            }
 
        },
 
    ]));
 
}
0 comments (0 inline, 0 general)