Merge pull request #22 from Schaeff/move-to-semantics
Move checks to semantics
This commit is contained in:
commit
f17bb4f140
2 changed files with 145 additions and 47 deletions
|
@ -1376,23 +1376,6 @@ pub fn parse_program<T: Field>(file: File) -> Result<Prog<T>, Error<T>> {
|
||||||
) {
|
) {
|
||||||
(Token::Def, ref s1, ref p1) => match parse_function(&mut lines, s1, p1) {
|
(Token::Def, ref s1, ref p1) => match parse_function(&mut lines, s1, p1) {
|
||||||
Ok((function, p2)) => {
|
Ok((function, p2)) => {
|
||||||
// panic if signature is not unique
|
|
||||||
match functions.iter().find(|x: &&Function<T>| {
|
|
||||||
x.id == function.id && x.arguments.len() == function.arguments.len()
|
|
||||||
}) {
|
|
||||||
Some(_) => panic!(
|
|
||||||
"Error while reading function: {}({}). Duplicate function signatures.",
|
|
||||||
function.id,
|
|
||||||
function
|
|
||||||
.arguments
|
|
||||||
.iter()
|
|
||||||
.map(|x| format!("{}", x))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(",")
|
|
||||||
),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
functions.push(function);
|
functions.push(function);
|
||||||
current_line = p2.line; // this is the line of the return statement
|
current_line = p2.line; // this is the line of the return statement
|
||||||
current_line += 1;
|
current_line += 1;
|
||||||
|
@ -1412,22 +1395,6 @@ pub fn parse_program<T: Field>(file: File) -> Result<Prog<T>, Error<T>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if exactly one main function exists
|
|
||||||
let mut has_main = false;
|
|
||||||
for func in &functions {
|
|
||||||
if func.id == "main".to_string() {
|
|
||||||
if !has_main {
|
|
||||||
has_main = true;
|
|
||||||
} else {
|
|
||||||
panic!("Error while parsing program: Multiple main functions!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has_main {
|
|
||||||
panic!("Error while parsing program: No main function found.")
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Prog { functions })
|
Ok(Prog { functions })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
159
src/semantics.rs
159
src/semantics.rs
|
@ -50,25 +50,42 @@ impl Checker {
|
||||||
|
|
||||||
pub fn check_program<T: Field>(&mut self, prog: Prog<T>) -> Result<(), String> {
|
pub fn check_program<T: Field>(&mut self, prog: Prog<T>) -> Result<(), String> {
|
||||||
for func in prog.functions {
|
for func in prog.functions {
|
||||||
|
self.check_function(&func)?;
|
||||||
self.functions.insert(FunctionDeclaration {
|
self.functions.insert(FunctionDeclaration {
|
||||||
id: func.clone().id,
|
id: func.id,
|
||||||
return_count: func.clone().return_count,
|
return_count: func.return_count,
|
||||||
arg_count: func.clone().arguments.len()
|
arg_count: func.arguments.len()
|
||||||
});
|
});
|
||||||
self.check_function(func)?;
|
|
||||||
}
|
}
|
||||||
|
self.check_single_main()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_function<T: Field>(&mut self, funct: Function<T>) -> Result<(), String> {
|
fn check_single_main(&mut self) -> Result<(), String> {
|
||||||
|
match self.functions.clone().into_iter().filter(|fun| fun.id == "main").count() {
|
||||||
|
1 => Ok(()),
|
||||||
|
0 => Err((format!("No main function found"))),
|
||||||
|
n => Err((format!("Only one main function allowed, found {}", n)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_function<T: Field>(&mut self, funct: &Function<T>) -> Result<(), String> {
|
||||||
|
match self.find_function(&funct.id, funct.arguments.len()) {
|
||||||
|
Some(_) => {
|
||||||
|
return Err(format!("Duplicate definition for function {} with {} arguments", funct.id, funct.arguments.len()))
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
self.level += 1;
|
self.level += 1;
|
||||||
for arg in funct.arguments {
|
for arg in funct.arguments.clone() {
|
||||||
self.scope.insert(Symbol {
|
self.scope.insert(Symbol {
|
||||||
id: arg.id.to_string(),
|
id: arg.id.to_string(),
|
||||||
level: self.level
|
level: self.level
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for stat in funct.statements {
|
for stat in funct.statements.clone() {
|
||||||
self.check_statement(stat)?;
|
self.check_statement(stat)?;
|
||||||
}
|
}
|
||||||
let current_level = self.level.clone();
|
let current_level = self.level.clone();
|
||||||
|
@ -120,7 +137,7 @@ impl Checker {
|
||||||
match rhs {
|
match rhs {
|
||||||
// Right side has to be a function call
|
// Right side has to be a function call
|
||||||
Expression::FunctionCall(ref fun_id, ref arguments) => {
|
Expression::FunctionCall(ref fun_id, ref arguments) => {
|
||||||
match self.find_function(fun_id, arguments) {
|
match self.find_function(fun_id, arguments.len()) {
|
||||||
// the function has to be defined
|
// the function has to be defined
|
||||||
Some(f) => {
|
Some(f) => {
|
||||||
if f.return_count == ids.len() {
|
if f.return_count == ids.len() {
|
||||||
|
@ -166,7 +183,7 @@ impl Checker {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Expression::FunctionCall(ref fun_id, ref arguments) => {
|
Expression::FunctionCall(ref fun_id, ref arguments) => {
|
||||||
match self.find_function(fun_id, arguments) {
|
match self.find_function(fun_id, arguments.len()) {
|
||||||
// the function has to be defined
|
// the function has to be defined
|
||||||
Some(f) => {
|
Some(f) => {
|
||||||
if f.return_count == 1 { // Functions must return a single value when not in a MultipleDefinition
|
if f.return_count == 1 { // Functions must return a single value when not in a MultipleDefinition
|
||||||
|
@ -205,8 +222,8 @@ impl Checker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_function<T: Field>(&mut self, id: &str, args: &Vec<Expression<T>>) -> Option<FunctionDeclaration> {
|
fn find_function(&mut self, id: &str, arg_count: usize) -> Option<FunctionDeclaration> {
|
||||||
self.functions.clone().into_iter().find(|fun| fun.id == id && fun.arg_count == args.len())
|
self.functions.clone().into_iter().find(|fun| fun.id == id && fun.arg_count == arg_count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,6 +313,8 @@ mod tests {
|
||||||
// def bar():
|
// def bar():
|
||||||
// a = 2
|
// a = 2
|
||||||
// return a
|
// return a
|
||||||
|
// def main():
|
||||||
|
// return 1
|
||||||
// should pass
|
// should pass
|
||||||
let foo_args = Vec::<Parameter>::new();
|
let foo_args = Vec::<Parameter>::new();
|
||||||
let mut foo_statements = Vec::<Statement<FieldPrime>>::new();
|
let mut foo_statements = Vec::<Statement<FieldPrime>>::new();
|
||||||
|
@ -328,9 +347,24 @@ mod tests {
|
||||||
return_count: 1,
|
return_count: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let main_args = Vec::<Parameter>::new();
|
||||||
|
let mut main_statements = Vec::<Statement<FieldPrime>>::new();
|
||||||
|
main_statements.push(Statement::Return(
|
||||||
|
ExpressionList {
|
||||||
|
expressions: vec![Expression::Number(FieldPrime::from(1))]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
let main = Function {
|
||||||
|
id: "main".to_string(),
|
||||||
|
arguments: main_args,
|
||||||
|
statements: main_statements,
|
||||||
|
return_count: 1,
|
||||||
|
};
|
||||||
|
|
||||||
let mut funcs = Vec::<Function<FieldPrime>>::new();
|
let mut funcs = Vec::<Function<FieldPrime>>::new();
|
||||||
funcs.push(foo);
|
funcs.push(foo);
|
||||||
funcs.push(bar);
|
funcs.push(bar);
|
||||||
|
funcs.push(main);
|
||||||
let prog = Prog {
|
let prog = Prog {
|
||||||
functions: funcs
|
functions: funcs
|
||||||
};
|
};
|
||||||
|
@ -366,7 +400,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut checker = Checker::new();
|
let mut checker = Checker::new();
|
||||||
assert_eq!(checker.check_function(foo), Err("i is undefined".to_string()));
|
assert_eq!(checker.check_function(&foo), Err("i is undefined".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -396,7 +430,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut checker = Checker::new();
|
let mut checker = Checker::new();
|
||||||
assert_eq!(checker.check_function(foo), Ok(()));
|
assert_eq!(checker.check_function(&foo), Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -569,6 +603,103 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut checker = Checker::new_with_args(HashSet::new(), 0, functions);
|
let mut checker = Checker::new_with_args(HashSet::new(), 0, functions);
|
||||||
assert_eq!(checker.check_function(bar), Ok(()));
|
assert_eq!(checker.check_function(&bar), Ok(()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn duplicate_function_declaration() {
|
||||||
|
// def foo(a, b):
|
||||||
|
// return 1
|
||||||
|
// def foo(c, d):
|
||||||
|
// return 2
|
||||||
|
//
|
||||||
|
// should fail
|
||||||
|
let foo2_statements: Vec<Statement<FieldPrime>> = vec![
|
||||||
|
Statement::Return(
|
||||||
|
ExpressionList {
|
||||||
|
expressions: vec![
|
||||||
|
Expression::Number(FieldPrime::from(1))
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
let foo2_arguments = vec![
|
||||||
|
Parameter { id: 'c'.to_string(), private: true },
|
||||||
|
Parameter { id: 'd'.to_string(), private: true }
|
||||||
|
];
|
||||||
|
|
||||||
|
let foo1 = FunctionDeclaration {
|
||||||
|
id: "foo".to_string(),
|
||||||
|
arg_count: 2,
|
||||||
|
return_count: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut functions = HashSet::new();
|
||||||
|
functions.insert(foo1);
|
||||||
|
|
||||||
|
let foo2 = Function {
|
||||||
|
id: "foo".to_string(),
|
||||||
|
arguments: foo2_arguments,
|
||||||
|
statements: foo2_statements,
|
||||||
|
return_count: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut checker = Checker::new_with_args(HashSet::new(), 0, functions);
|
||||||
|
assert_eq!(checker.check_function(&foo2), Err(("Duplicate definition for function foo with 2 arguments".to_string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn duplicate_main_function() {
|
||||||
|
// def main(a):
|
||||||
|
// return 1
|
||||||
|
// def main():
|
||||||
|
// return 1
|
||||||
|
//
|
||||||
|
// should fail
|
||||||
|
let main1_statements: Vec<Statement<FieldPrime>> = vec![
|
||||||
|
Statement::Return(
|
||||||
|
ExpressionList {
|
||||||
|
expressions: vec![
|
||||||
|
Expression::Number(FieldPrime::from(1))
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
let main1_arguments = vec![Parameter { id: 'a'.to_string(), private: false }];
|
||||||
|
|
||||||
|
let main2_statements: Vec<Statement<FieldPrime>> = vec![
|
||||||
|
Statement::Return(
|
||||||
|
ExpressionList {
|
||||||
|
expressions: vec![
|
||||||
|
Expression::Number(FieldPrime::from(1))
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
let main2_arguments = vec![];
|
||||||
|
|
||||||
|
let main1 = Function {
|
||||||
|
id: "main".to_string(),
|
||||||
|
arguments: main1_arguments,
|
||||||
|
statements: main1_statements,
|
||||||
|
return_count: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let main2 = Function {
|
||||||
|
id: "main".to_string(),
|
||||||
|
arguments: main2_arguments,
|
||||||
|
statements: main2_statements,
|
||||||
|
return_count: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let prog = Prog {
|
||||||
|
functions: vec![main1, main2]
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut checker = Checker::new();
|
||||||
|
assert_eq!(checker.check_program(prog), Err(("Only one main function allowed, found 2".to_string())));
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue