Check for function & binding duplication in the global scope

master
Araozu 2024-03-09 21:34:05 -05:00
parent ed9ccab5e1
commit ac2ab8d2dc
6 changed files with 61 additions and 23 deletions

View File

@ -2,6 +2,7 @@
## TODO
- Formally define the top level constructs
- Implement AST transformation before codegen:
Create a new AST to represent PHP source code
and a THP ast -> PHP ast process, so that the
@ -32,9 +33,9 @@
- [x] Minimal symbol table
- [x] Check duplicate function declarations
- [x] Improve REPL/File compilation code
- [ ] Typecheck bindings
- [x] Typecheck functions
- [ ] Transform simple THP expression into PHP statements
- [x] Check binding duplication in it's scope
- [x] Check function duplication in it's scope
- [x] Transform simple THP expression into PHP statements
## v0.0.9

View File

@ -6,22 +6,27 @@ impl Transpilable for Binding<'_> {
fn transpile(&self) -> String {
let expression_str = self.expression.transpile();
format!("${} = {}", self.identifier, expression_str)
format!("${} = {}", self.identifier.value, expression_str)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::syntax::ast::{var_binding::Binding, Expression};
use crate::{lexic::token::{Token, TokenType}, syntax::ast::{var_binding::Binding, Expression}};
#[test]
fn binding_should_transpile() {
let id = String::from("identifier");
let id_token = Token {
token_type: TokenType::Identifier,
value: id,
position: 0,
};
let value = String::from("322");
let binding = Binding {
datatype: None,
identifier: Box::new(id),
identifier: &id_token,
expression: Expression::Number(&value),
is_mutable: false,
};

View File

@ -18,15 +18,20 @@ impl Transpilable for ModuleAST<'_> {
#[cfg(test)]
mod tests {
use super::*;
use crate::syntax::ast::{var_binding::Binding, Expression, TopLevelDeclaration};
use crate::{lexic::token::{Token, TokenType}, syntax::ast::{var_binding::Binding, Expression, TopLevelDeclaration}};
#[test]
fn module_ast_should_transpile() {
let id = String::from("identifier");
let id_token = Token {
token_type: TokenType::Identifier,
value: id,
position: 0,
};
let value = String::from("322");
let binding = Binding {
datatype: None,
identifier: Box::new(id),
identifier: &id_token,
expression: Expression::Number(&value),
is_mutable: false,
};

View File

@ -4,7 +4,7 @@ use crate::{
syntax::ast::{ModuleAST, TopLevelDeclaration},
};
use super::symbol_table::SymbolTable;
use super::symbol_table::{SymbolEntry, SymbolTable};
pub trait SemanticCheck {
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError>;
@ -24,18 +24,46 @@ impl SemanticCheck for ModuleAST<'_> {
impl SemanticCheck for TopLevelDeclaration<'_> {
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
match self {
TopLevelDeclaration::Binding(_) => {
TopLevelDeclaration::Binding(binding) => {
let binding_name = &binding.identifier.value;
if scope.test(binding_name) {
let error = SemanticError {
error_start: 0,
error_end: 0,
reason: "Binding typechecking: Not implemented".into(),
error_start: binding.identifier.position,
error_end: binding.identifier.get_end_position(),
reason: format!(
"Duplicated function: A function with name {} was already defined",
binding_name
),
};
Err(MistiError::Semantic(error))
return Err(MistiError::Semantic(error));
}
let datatype = match binding.datatype {
Some(t) => t,
None => {
let error = SemanticError {
error_start: binding.identifier.position,
error_end: binding.identifier.get_end_position(),
reason: format!(
"The variable `{}` didn't define a datatype. Datatype inference is not implemented.",
binding_name
),
};
return Err(MistiError::Semantic(error));
}
};
scope.insert(binding_name.clone(), SymbolEntry::new_variable(datatype.value.clone()));
Ok(())
}
TopLevelDeclaration::FunctionDeclaration(function) => {
let function_name = function.identifier.value.clone();
// Check that the function is not already defined
if scope.test(&function_name) {
let error = SemanticError {
error_start: function.identifier.position,
@ -49,10 +77,7 @@ impl SemanticCheck for TopLevelDeclaration<'_> {
return Err(MistiError::Semantic(error));
}
scope.insert(
function_name,
super::symbol_table::SymbolEntry::Function(vec![], "Unit".into()),
);
scope.insert(function_name, SymbolEntry::new_function(vec![], "Unit".into()));
Ok(())
}

View File

@ -1,9 +1,11 @@
use crate::lexic::token::Token;
use super::Expression;
#[derive(Debug)]
pub struct Binding<'a> {
pub datatype: Option<String>,
pub identifier: Box<String>,
pub datatype: Option<&'a Token>,
pub identifier: &'a Token,
pub expression: Expression<'a>,
pub is_mutable: bool,
}

View File

@ -97,7 +97,7 @@ pub fn try_parse<'a>(tokens: &'a Vec<Token>, pos: usize) -> ParseResult<Binding,
let binding = Binding {
datatype: None,
identifier: Box::new(identifier.value.clone()),
identifier: &identifier,
expression,
is_mutable,
};
@ -117,7 +117,7 @@ mod tests {
panic!()
};
assert_eq!("identifier", format!("{}", binding.identifier));
assert_eq!("identifier", format!("{}", binding.identifier.value));
}
#[test]