diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e56fa5..d56cd2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ codegen section can focus only in codegen, not in translation of thp->php. - Parse __more__ binary operators +- Store tokens for the semantic analysis phase, to have actual error reporting - Parse more complex bindings - Watch mode - Improve error messages @@ -24,8 +25,12 @@ ## v0.0.12 +- [x] Infer datatype of an identifier +- [ ] Infer datatype of a binary operatior +- [ ] Infer datatype of unary operator - [ ] Infer datatype of a function call expression - [ ] Infer datatype of binary operators +- [ ] Infer Int & Float as different types - [ ] Execute semantic analysis on the function's block - [ ] Write tests - [ ] Abstract the parsing of datatypes, such that in the future generics can be implemented in a single place diff --git a/src/semantic/checks/binding.rs b/src/semantic/checks/binding.rs index c242e52..79da9f6 100644 --- a/src/semantic/checks/binding.rs +++ b/src/semantic/checks/binding.rs @@ -28,7 +28,7 @@ impl SemanticCheck for Binding<'_> { // This gets the datatype of the assigned expression, // to compare it later with the declared datatype. - let expression_datatype = self.expression.get_type(); + let expression_datatype = self.expression.get_type(scope)?; let datatype = match self.datatype { Some(t) => t.value.clone(), diff --git a/src/semantic/symbol_table.rs b/src/semantic/symbol_table.rs index de7a0f7..5e2724a 100644 --- a/src/semantic/symbol_table.rs +++ b/src/semantic/symbol_table.rs @@ -45,6 +45,11 @@ impl SymbolTable { pub fn test(&self, key: &String) -> bool { self.node.borrow_mut().test(key) } + + /// Gets the datatype of a symbol, if it exists + pub fn get_type(&self, key: &String) -> Option { + self.node.borrow_mut().get_type(key) + } } impl SymbolTableNode { @@ -83,6 +88,27 @@ impl SymbolTableNode { None => false, } } + + /// Returns the symbol's datatype + pub fn get_type(&mut self, key: &String) -> Option { + // Try to get the type in the current scope + if let Some(entry) = self.scope.get(key) { + // TODO: Change to allow other types of datatypes: functions, classes, maps + return match entry { + SymbolEntry::Variable(t) => Some(t.clone()), + SymbolEntry::Function(_, _) => None, + } + } + + // Try to get the type in the parent scope + match &self.parent { + Some(parent) => { + let mut parent = parent.as_ref().borrow_mut(); + parent.get_type(key) + } + None => None, + } + } } impl SymbolEntry { diff --git a/src/semantic/types/expression.rs b/src/semantic/types/expression.rs index 8042173..1427ce1 100644 --- a/src/semantic/types/expression.rs +++ b/src/semantic/types/expression.rs @@ -1,15 +1,34 @@ -use crate::syntax::ast::Expression; +use crate::{ + error_handling::{semantic_error::SemanticError, MistiError}, + semantic::symbol_table::SymbolTable, + syntax::ast::Expression, +}; use super::Typed; impl Typed for Expression<'_> { - fn get_type(&self) -> String { + /// Attempts to get the datatype for an expression. + fn get_type(&self, scope: &SymbolTable) -> Result { match self { // TODO: Distinguish between Int & Float - Expression::Number(_) => "Int".into(), - Expression::String(_) => "String".into(), - Expression::Boolean(_) => "Bool".into(), - Expression::Identifier(_) => todo!(), + Expression::Number(_) => Ok("Int".into()), + Expression::String(_) => Ok("String".into()), + Expression::Boolean(_) => Ok("Bool".into()), + Expression::Identifier(identifier) => { + // Attempt to get the datatype of the identifier in the current scope + let datatype = match scope.get_type(identifier) { + Some(x) => x, + None => { + return Err(MistiError::Semantic(SemanticError { + error_start: 0, + error_end: 1, + reason: format!("The identifier {} does not exist.", identifier), + })) + } + }; + + Ok(datatype) + } Expression::FunctionCall(_) => todo!(), Expression::UnaryOperator(_, _) => todo!(), Expression::BinaryOperator(_, _, _) => todo!(), diff --git a/src/semantic/types/mod.rs b/src/semantic/types/mod.rs index 7ce9580..d08c62e 100644 --- a/src/semantic/types/mod.rs +++ b/src/semantic/types/mod.rs @@ -1,8 +1,12 @@ // This crate provides an interface and implementations // for determining the datatypes of the language constructs. +use crate::error_handling::MistiError; + +use super::symbol_table::SymbolTable; + mod expression; pub trait Typed { - fn get_type(&self) -> String; + fn get_type(&self, scope: &SymbolTable) -> Result; }