1
0
Fork 0
mirror of synced 2025-09-23 12:18:44 +00:00

add semantic analysis

This commit is contained in:
schaeff 2017-12-10 00:03:39 +01:00
parent 76fb3a1eff
commit e27fdd1190
3 changed files with 159 additions and 2 deletions

View file

@ -9,7 +9,7 @@ use std::fmt;
use std::collections::HashMap;
use field::Field;
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct Prog<T: Field> {
/// Functions of the program
pub functions: Vec<Function<T>>,
@ -55,7 +55,7 @@ impl<T: Field> fmt::Debug for Prog<T> {
}
}
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone)]
pub struct Function<T: Field> {
/// Name of the program
pub id: String,

View file

@ -18,6 +18,7 @@ extern crate regex;
mod absy;
mod parser;
mod semantics;
mod flatten;
mod r1cs;
mod field;
@ -33,6 +34,7 @@ use std::io::prelude::*;
use field::{Field, FieldPrime};
use absy::Prog;
use parser::parse_program;
use semantics::Checker;
use flatten::Flattener;
use r1cs::r1cs_program;
use clap::{App, AppSettings, Arg, SubCommand};
@ -209,6 +211,10 @@ fn main() {
}
};
// check semantics
let semantics_ok = Checker::new().check_program(program_ast.clone());
println!("Semantics ok? {:?}", semantics_ok);
// flatten input program
let program_flattened =
Flattener::new(FieldPrime::get_required_bits()).flatten_program(program_ast);

151
src/semantics.rs Normal file
View file

@ -0,0 +1,151 @@
//! Module containing semantic analysis tools to run at compile time
//!
//! @file flatten.rs
//! @author Dennis Kuhnert <dennis.kuhnert@campus.tu-berlin.de>
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
//! @date 2017
use std::collections::{HashMap, HashSet};
use absy::*;
use field::Field;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Symbol {
id: String,
level: usize
}
// Checker, checks the semantics of a program.
pub struct Checker {
scope: HashSet<Symbol>,
level: usize
}
impl Checker {
pub fn new() -> Checker {
Checker {
scope: HashSet::new(),
level: 0
}
}
pub fn new_with_args(scope: HashSet<Symbol>, level: usize) -> Checker {
Checker {
scope: scope,
level: level
}
}
pub fn check_program<T: Field>(&mut self, prog: Prog<T>) -> bool {
let mut res = true;
for func in prog.functions {
let function_checked = self.check_function(func);
res = res && function_checked;
}
res
}
fn check_function<T: Field>(&mut self, funct: Function<T>) -> bool {
self.level += 1;
for arg in funct.arguments {
self.scope.insert(Symbol {
id: arg.id.to_string(),
level: 0
});
}
let mut res = true;
for stat in funct.statements {
let statement_checked = self.check_statement(
stat
);
res = res && statement_checked;
}
self.level -= 1;
// TODO: cleanup scope of all symbols of level i
res
}
fn check_statement<T: Field>(&mut self, stat: Statement<T>) -> bool {
match stat {
Statement::Return(expr) => {
self.check_expression(expr)
}
Statement::Definition(id, expr) => {
let expr_checked = self.check_expression(expr);
self.scope.insert(Symbol {
id: id.to_string(),
level: 0
});
expr_checked
}
Statement::Condition(lhs, rhs) => {
self.check_expression(lhs) && self.check_expression(rhs)
}
_ => true,
}
}
fn check_expression<T: Field>(&mut self, expr: Expression<T>) -> bool {
match expr {
Expression::Identifier(id) => {
self.scope.contains(&Symbol {id: id.to_string(), level: 0})
}
Expression::Add(box e1, box e2) | Expression::Sub(box e1, box e2) | Expression::Mult(box e1, box e2) |
Expression::Div(box e1, box e2) | Expression::Pow(box e1, box e2) => {
self.check_expression(e1) && self.check_expression(e2)
}
Expression::IfElse(box condition, box consequent, box alternative) => {
self.check_condition(condition) && self.check_expression(consequent) && self.check_expression(alternative)
}
_ => true,
}
}
fn check_condition<T: Field>(&mut self, cond: Condition<T>) -> bool {
match cond {
Condition::Lt(e1, e2) |
Condition::Le(e1, e2) |
Condition::Eq(e1, e2) |
Condition::Ge(e1, e2) |
Condition::Gt(e1, e2) => {
self.check_expression(e1) && self.check_expression(e2)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use field::FieldPrime;
#[test]
fn undefined_variable_in_statement() {
// a = b
// b undefined
let statement: Statement<FieldPrime> = Statement::Definition(
String::from("a"),
Expression::Identifier(String::from("b"))
);
let mut checker = Checker::new();
assert_eq!(checker.check_statement(statement), false);
}
#[test]
fn defined_variable_in_statement() {
// a = b
// b undefined
let statement: Statement<FieldPrime> = Statement::Definition(
String::from("a"),
Expression::Identifier(String::from("b"))
);
let mut scope = HashSet::new();
scope.insert(Symbol {
id: String::from("b"),
level: 0
});
let mut checker = Checker::new_with_args(scope, 1);
assert_eq!(checker.check_statement(statement), true);
}
}