...
 
Commits (2)
use crate::ast::Expr;
use crate::ast::Expr_;
use crate::ast::Program;
use crate::lexer::Span;
use std::collections::HashMap;
fn check_main(program: &Program) -> bool {
for expression in &program.stmts {
......@@ -21,52 +23,69 @@ fn check_main(program: &Program) -> bool {
false
}
fn detect_collision(scope: &mut Vec<String>, identifier: &String) {
println!("identifier: {:?}", identifier);
match scope.iter().find(|&x| x == identifier) {
Some(_) => panic!(
"Error: identifier \"{}\" already declared. Aborting compilation.",
identifier
),
None => {}
fn detect_collision(scope: &mut HashMap<String, Span>, identifier: &String, span: &Span) {
if scope.contains_key(identifier) {
panic!(
"Error: \"{}\" at {:?} already declared at {:?}. Aborting compilation...",
identifier,
span,
scope.get(identifier).unwrap()
);
}
scope.push(identifier.to_string());
scope.insert(identifier.clone(), span.clone());
}
fn identifiers_collision(program: &Vec<Expr>, mut scope: Vec<String>) {
for expression in program {
match &expression.node {
// if we encounter a function declaration /////////////////////////
fn identifiers_collision(program: &Vec<Expr>, mut scope: HashMap<String, Span>) {
// Checks all the statements, and if they declare an identifier, add it to
// the scope. If a declaration is a declaration of a function, add it to a
// queue to process it then separately. Its arguments will be added to its
// scope before processing it.
use std::collections::VecDeque;
// first body, second arguments
let mut subscopes = VecDeque::<(&Vec<Expr>, &Vec<Expr>)>::new();
for statement in program {
match &statement.node {
Expr_::Func {
ident: identifier,
t: _,
args: _,
expr: func_expr,
args: arguments,
expr: func_body,
} => {
detect_collision(&mut scope, &identifier);
let new_scope = scope.clone();
identifiers_collision(&func_expr, new_scope);
detect_collision(&mut scope, &identifier, &statement.span);
subscopes.push_back((func_body, arguments));
}
// if we encounter a variable declaration /////////////////////////
Expr_::Assign {
ident: identifier,
t: _,
expr: _,
} => {
detect_collision(&mut scope, &identifier);
detect_collision(&mut scope, &identifier, &statement.span);
}
_ => {}
}
}
eprintln!("available identifiers in current scope: {:?}", scope);
while subscopes.len() != 0 {
let (new_program, arguments) = subscopes.pop_front().unwrap();
let mut new_scope = scope.clone();
for arg in arguments {
match &arg.node {
Expr_::Arg {
ident: identifier,
t: _,
} => {
detect_collision(&mut new_scope, identifier, &arg.span);
}
_ => {}
}
}
identifiers_collision(&new_program, new_scope);
}
}
pub fn check_grammar(program: &Program) {
if !check_main(&program) {
panic!("No main function detected. Compilation aborted.");
}
let identifiers_scopes: Vec<String> = Vec::new();
let identifiers_scopes: HashMap<String, Span> = HashMap::new();
identifiers_collision(&program.stmts, identifiers_scopes); // check for identifier collision
}
#![feature(proc_macro_hygiene)]
extern crate plex;
use std::io::Read;
mod ast;
mod lexer;
mod parser;
mod grammar;
fn main() {
fn get_file_content() -> String {
use std::env;
use std::fs::File;
use std::io::prelude::*;
let mut file = File::open(env::args().nth(1).unwrap()).unwrap();
let mut s = String::new();
std::io::stdin().read_to_string(&mut s).unwrap();
file.read_to_string(&mut s).unwrap();
s
}
fn main() {
let s = get_file_content();
let lexer = lexer::Lexer::new(&s);
let program = parser::parse(lexer).unwrap();
for expression in &program.stmts {
eprintln!("{:?}\n", expression);
}
grammar::check_grammar(&program);
}