refactor: migrate all errors to new struct
This commit is contained in:
parent
1a7dd72783
commit
15030635fb
@ -30,6 +30,8 @@
|
|||||||
- [x] Typecheck while loops
|
- [x] Typecheck while loops
|
||||||
- [x] Include Ariadne for error reporting
|
- [x] Include Ariadne for error reporting
|
||||||
- [x] Migrate lexic errors to new error interface
|
- [x] Migrate lexic errors to new error interface
|
||||||
|
- [x] Migrate syntax errors to new error interface
|
||||||
|
- [x] Migrate semantic errors to new error interface
|
||||||
|
|
||||||
|
|
||||||
## v0.1.1
|
## v0.1.1
|
||||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -152,7 +152,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thp"
|
name = "thp"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ariadne",
|
"ariadne",
|
||||||
"colored",
|
"colored",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "thp"
|
name = "thp"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,4 +17,10 @@
|
|||||||
0x000015: Invalid for loop
|
0x000015: Invalid for loop
|
||||||
0x000016: Invalid if condition
|
0x000016: Invalid if condition
|
||||||
0x000017: Incomplete block
|
0x000017: Incomplete block
|
||||||
|
0x000018: Missing reference
|
||||||
|
0x000019: Invalid reference
|
||||||
|
0x000020: Unknown error (compiler todo)
|
||||||
|
0x000021: Mismatched types
|
||||||
|
0x000022: Duplicated reference
|
||||||
|
0x000023: Mismatched argument count
|
||||||
|
|
||||||
|
@ -18,6 +18,12 @@ pub const SYNTAX_INVALID_FUNCTION_DECLARATION: u32 = 14;
|
|||||||
pub const SYNTAX_INVALID_FOR_LOOP: u32 = 15;
|
pub const SYNTAX_INVALID_FOR_LOOP: u32 = 15;
|
||||||
pub const SYNTAX_INVALID_IF_CONDITION: u32 = 16;
|
pub const SYNTAX_INVALID_IF_CONDITION: u32 = 16;
|
||||||
pub const SYNTAX_INCOMPLETE_BLOCK: u32 = 17;
|
pub const SYNTAX_INCOMPLETE_BLOCK: u32 = 17;
|
||||||
|
pub const SEMANTIC_MISSING_REFERENCE: u32 = 18;
|
||||||
|
pub const SEMANTIC_INVALID_REFERENCE: u32 = 19;
|
||||||
|
pub const COMPILER_TODO: u32 = 20;
|
||||||
|
pub const SEMANTIC_MISMATCHED_TYPES: u32 = 21;
|
||||||
|
pub const SEMANTIC_DUPLICATED_REFERENCE: u32 = 22;
|
||||||
|
pub const SEMANTIC_MISMATCHED_ARGUMENT_COUNT: u32 = 23;
|
||||||
|
|
||||||
/// Reads the error codes from the error code list
|
/// Reads the error codes from the error code list
|
||||||
pub fn error_code_to_string() -> String {
|
pub fn error_code_to_string() -> String {
|
||||||
|
@ -1,170 +0,0 @@
|
|||||||
use ariadne::{Color, Label, Report, ReportKind, Source};
|
|
||||||
|
|
||||||
use super::{LexError, PrintableError};
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
|
|
||||||
impl PrintableError for LexError {
|
|
||||||
fn get_error_str(&self, chars: &Vec<char>) -> String {
|
|
||||||
let line_number = get_line_number(chars, self.position);
|
|
||||||
let (erroneous_code, column_number_zero) = get_line(chars, self.position);
|
|
||||||
let column_number = column_number_zero + 1;
|
|
||||||
|
|
||||||
let line_number_whitespace = " ".repeat(line_number.to_string().len());
|
|
||||||
let whitespace = " ".repeat(column_number_zero);
|
|
||||||
let reason = &self.reason;
|
|
||||||
|
|
||||||
format!(
|
|
||||||
r#"
|
|
||||||
{line_number_whitespace} |
|
|
||||||
{line_number } | {erroneous_code}
|
|
||||||
{line_number_whitespace} | {whitespace}^
|
|
||||||
|
|
||||||
{reason} at line {line_number}:{column_number}"#,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_ariadne(&self, source: &String) {
|
|
||||||
let report = Report::build(ReportKind::Error, "sample.thp", self.position)
|
|
||||||
.with_label(
|
|
||||||
Label::new(("sample.thp", self.position..self.end_position))
|
|
||||||
.with_message(self.reason.clone())
|
|
||||||
.with_color(Color::Red),
|
|
||||||
)
|
|
||||||
.finish();
|
|
||||||
report.eprint(("sample.thp", Source::from(source))).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts a line of code from `chars` and the number of characters in the back.
|
|
||||||
/// `pos` indicates a position, from where to extract the line.
|
|
||||||
///
|
|
||||||
/// Ex. Given:
|
|
||||||
/// - `input = "first line\nsecond line\nthird line"`
|
|
||||||
/// - `pos = 15`
|
|
||||||
///
|
|
||||||
/// this function should return `("second line", 4)`
|
|
||||||
fn get_line(chars: &Vec<char>, pos: usize) -> (String, usize) {
|
|
||||||
let mut result_chars = VecDeque::<char>::new();
|
|
||||||
|
|
||||||
// Push chars to the front until a new line is found
|
|
||||||
// TODO: refactor
|
|
||||||
let mut before_pos = pos;
|
|
||||||
loop {
|
|
||||||
let current_char = chars[before_pos];
|
|
||||||
|
|
||||||
if current_char == '\n' {
|
|
||||||
// This is important because before_pos will be used to calculate
|
|
||||||
// the number of chars before pos
|
|
||||||
before_pos += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
result_chars.push_front(current_char);
|
|
||||||
|
|
||||||
if before_pos == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
before_pos -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push chars to the end until a new line is found
|
|
||||||
let mut after_pos = pos + 1;
|
|
||||||
let char_count = chars.len();
|
|
||||||
while after_pos < char_count {
|
|
||||||
let current_char = chars[after_pos];
|
|
||||||
|
|
||||||
if current_char == '\n' {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
result_chars.push_back(current_char);
|
|
||||||
after_pos += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
(result_chars.iter().collect::<String>(), pos - before_pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_line_number(chars: &Vec<char>, target_pos: usize) -> usize {
|
|
||||||
let mut count = 1;
|
|
||||||
|
|
||||||
for (pos, char) in chars.iter().enumerate() {
|
|
||||||
if pos >= target_pos {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if *char == '\n' {
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::lexic;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_error_msg() {
|
|
||||||
let input = String::from("val name' = 20");
|
|
||||||
let result = lexic::get_tokens(&input);
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(_) => assert!(false),
|
|
||||||
Err(err_data) => {
|
|
||||||
let chars: Vec<char> = input.chars().into_iter().collect();
|
|
||||||
let err_str = err_data.get_error_str(&chars);
|
|
||||||
|
|
||||||
let expected_str = format!(
|
|
||||||
r#"
|
|
||||||
|
|
|
||||||
1 | val name' = 20
|
|
||||||
| ^
|
|
||||||
|
|
||||||
Illegal character `'` (escaped: \') at line 1:9"#,
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(expected_str, err_str,);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_extract_line() {
|
|
||||||
let input = String::from("first line\nsecond line\nthird line");
|
|
||||||
let chars: Vec<char> = input.chars().into_iter().collect();
|
|
||||||
|
|
||||||
let (result, back_count) = get_line(&chars, 15);
|
|
||||||
|
|
||||||
assert_eq!("second line", result);
|
|
||||||
assert_eq!(4, back_count);
|
|
||||||
|
|
||||||
let input = String::from("val binding = 322");
|
|
||||||
let chars: Vec<char> = input.chars().into_iter().collect();
|
|
||||||
|
|
||||||
let (result, back_count) = get_line(&chars, 6);
|
|
||||||
|
|
||||||
assert_eq!("val binding = 322", result);
|
|
||||||
assert_eq!(6, back_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_get_line_number() {
|
|
||||||
let input = String::from("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten");
|
|
||||||
let chars: Vec<char> = input.chars().into_iter().collect();
|
|
||||||
|
|
||||||
let line_number = get_line_number(&chars, 11);
|
|
||||||
assert_eq!(3, line_number);
|
|
||||||
|
|
||||||
let line_number = get_line_number(&chars, 0);
|
|
||||||
assert_eq!(1, line_number);
|
|
||||||
|
|
||||||
let line_number = get_line_number(&chars, 3);
|
|
||||||
assert_eq!(1, line_number);
|
|
||||||
|
|
||||||
let line_number = get_line_number(&chars, 15);
|
|
||||||
assert_eq!(4, line_number);
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,9 +5,7 @@ use serde::Serialize;
|
|||||||
|
|
||||||
use self::semantic_error::SemanticError;
|
use self::semantic_error::SemanticError;
|
||||||
|
|
||||||
mod lex_error;
|
|
||||||
pub mod semantic_error;
|
pub mod semantic_error;
|
||||||
mod syntax_error;
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub mod error_messages;
|
pub mod error_messages;
|
||||||
@ -38,22 +36,7 @@ pub struct ErrorLabel {
|
|||||||
pub enum MistiError {
|
pub enum MistiError {
|
||||||
Lex(ErrorContainer),
|
Lex(ErrorContainer),
|
||||||
Syntax(ErrorContainer),
|
Syntax(ErrorContainer),
|
||||||
Semantic(SemanticError),
|
Semantic(ErrorContainer),
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
|
||||||
pub struct LexError {
|
|
||||||
pub position: usize,
|
|
||||||
// TODO: Add and end position
|
|
||||||
pub end_position: usize,
|
|
||||||
pub reason: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
|
||||||
pub struct SyntaxError {
|
|
||||||
pub error_start: usize,
|
|
||||||
pub error_end: usize,
|
|
||||||
pub reason: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrintableError for MistiError {
|
impl PrintableError for MistiError {
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
use ariadne::{Color, Label, Report, ReportKind, Source};
|
|
||||||
|
|
||||||
use super::utils::{get_line, get_line_number};
|
|
||||||
use super::{PrintableError, SyntaxError};
|
|
||||||
|
|
||||||
impl PrintableError for SyntaxError {
|
|
||||||
fn get_error_str(&self, chars: &Vec<char>) -> String {
|
|
||||||
let (line, before, length) = get_line(chars, self.error_start, self.error_end);
|
|
||||||
|
|
||||||
let line_number = get_line_number(chars, self.error_start);
|
|
||||||
let line_number_whitespace = " ".repeat(line_number.to_string().len());
|
|
||||||
|
|
||||||
let whitespace = vec![' '; before].iter().collect::<String>();
|
|
||||||
let indicator = vec!['^'; length].iter().collect::<String>();
|
|
||||||
let reason = &self.reason;
|
|
||||||
|
|
||||||
format!(
|
|
||||||
r#"
|
|
||||||
{line_number_whitespace} |
|
|
||||||
{line_number } | {line}
|
|
||||||
{line_number_whitespace} | {whitespace}{indicator}
|
|
||||||
|
|
||||||
{reason} at line {line_number}:{before}"#,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_ariadne(&self, source: &String) {
|
|
||||||
let report = Report::build(ReportKind::Error, "sample.thp", self.error_start)
|
|
||||||
.with_label(
|
|
||||||
Label::new(("sample.thp", self.error_start..self.error_end))
|
|
||||||
.with_message(self.reason.clone())
|
|
||||||
.with_color(Color::Red),
|
|
||||||
)
|
|
||||||
.finish();
|
|
||||||
|
|
||||||
report.eprint(("sample.thp", Source::from(source))).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::{error_handling::MistiError, lexic::get_tokens, syntax::build_ast};
|
|
||||||
|
|
||||||
fn _get_error_data(input: String) -> (Vec<char>, MistiError) {
|
|
||||||
let tokens = get_tokens(&input).unwrap();
|
|
||||||
let error_holder = build_ast(&tokens);
|
|
||||||
|
|
||||||
match error_holder {
|
|
||||||
Ok(_) => panic!(
|
|
||||||
"syntax_error test: Input expected to throw error didn't:\n\n{}",
|
|
||||||
input
|
|
||||||
),
|
|
||||||
Err(error) => {
|
|
||||||
let chars: Vec<char> = input.chars().into_iter().collect();
|
|
||||||
|
|
||||||
(chars, error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_get_line() {
|
|
||||||
let input: Vec<char> = String::from("\n\nval number == 50\n\n")
|
|
||||||
.chars()
|
|
||||||
.into_iter()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let start_position = 13;
|
|
||||||
let end_position = 15;
|
|
||||||
|
|
||||||
let (line, before, length) = get_line(&input, start_position, end_position);
|
|
||||||
|
|
||||||
assert_eq!("val number == 50", line);
|
|
||||||
assert_eq!(11, before);
|
|
||||||
assert_eq!(2, length);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{semantic_error::SemanticError, MistiError},
|
error_handling::{
|
||||||
|
error_messages::SEMANTIC_DUPLICATED_REFERENCE, semantic_error::SemanticError,
|
||||||
|
ErrorContainer, ErrorLabel, MistiError,
|
||||||
|
},
|
||||||
semantic::{
|
semantic::{
|
||||||
impls::SemanticCheck,
|
impls::SemanticCheck,
|
||||||
types::{Type, Typed},
|
types::{Type, Typed},
|
||||||
@ -17,16 +20,19 @@ impl SemanticCheck for VariableBinding<'_> {
|
|||||||
// TODO: Define if variables can be redeclared.
|
// TODO: Define if variables can be redeclared.
|
||||||
// If so, it is irrelevant to check if the variable is already defined
|
// If so, it is irrelevant to check if the variable is already defined
|
||||||
if scope.test(binding_name) {
|
if scope.test(binding_name) {
|
||||||
let error = SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start: self.identifier.position,
|
message: String::from("A reference with this name was already defined"),
|
||||||
error_end: self.identifier.get_end_position(),
|
start: self.identifier.position,
|
||||||
reason: format!(
|
end: self.identifier.get_end_position(),
|
||||||
"Duplicated: A symbol with name {} was already defined",
|
|
||||||
binding_name
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
return Err(MistiError::Semantic(error));
|
error_code: SEMANTIC_DUPLICATED_REFERENCE,
|
||||||
|
error_offset: self.identifier.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This gets the datatype of the assigned expression,
|
// This gets the datatype of the assigned expression,
|
||||||
@ -41,16 +47,22 @@ impl SemanticCheck for VariableBinding<'_> {
|
|||||||
|
|
||||||
// Both the declared & actual datatypes must be the same
|
// Both the declared & actual datatypes must be the same
|
||||||
if datatype != expression_datatype {
|
if datatype != expression_datatype {
|
||||||
let error = SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start: self.identifier.position,
|
message: format!(
|
||||||
error_end: self.identifier.get_end_position(),
|
|
||||||
reason: format!(
|
|
||||||
"The variable `{}` was declared as `{:?}` but its expression has type `{:?}`",
|
"The variable `{}` was declared as `{:?}` but its expression has type `{:?}`",
|
||||||
binding_name, datatype, expression_datatype
|
binding_name, datatype, expression_datatype
|
||||||
),
|
),
|
||||||
|
start: self.identifier.position,
|
||||||
|
end: self.identifier.get_end_position(),
|
||||||
};
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
return Err(MistiError::Semantic(error));
|
error_code: SEMANTIC_DUPLICATED_REFERENCE,
|
||||||
|
error_offset: self.identifier.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.insert(binding_name.clone(), datatype);
|
scope.insert(binding_name.clone(), datatype);
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{semantic_error::SemanticError, MistiError},
|
error_handling::{
|
||||||
|
error_messages::SEMANTIC_MISMATCHED_TYPES, semantic_error::SemanticError, ErrorContainer,
|
||||||
|
ErrorLabel, MistiError,
|
||||||
|
},
|
||||||
semantic::{
|
semantic::{
|
||||||
impls::SemanticCheck,
|
impls::SemanticCheck,
|
||||||
symbol_table::SymbolTable,
|
symbol_table::SymbolTable,
|
||||||
@ -17,14 +20,22 @@ impl SemanticCheck for Conditional<'_> {
|
|||||||
let if_condition_type = if_condition.get_type(scope)?;
|
let if_condition_type = if_condition.get_type(scope)?;
|
||||||
if !if_condition_type.equals(&bool_type) {
|
if !if_condition_type.equals(&bool_type) {
|
||||||
let (error_start, error_end) = if_condition.get_position();
|
let (error_start, error_end) = if_condition.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!(
|
||||||
error_end,
|
|
||||||
reason: format!(
|
|
||||||
"Expected a condition of type Bool, found {:?}",
|
"Expected a condition of type Bool, found {:?}",
|
||||||
if_condition_type
|
if_condition_type
|
||||||
),
|
),
|
||||||
}));
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if block
|
// Check if block
|
||||||
@ -37,14 +48,22 @@ impl SemanticCheck for Conditional<'_> {
|
|||||||
let condition_type = condition.get_type(scope)?;
|
let condition_type = condition.get_type(scope)?;
|
||||||
if !condition_type.equals(&bool_type) {
|
if !condition_type.equals(&bool_type) {
|
||||||
let (error_start, error_end) = condition.get_position();
|
let (error_start, error_end) = condition.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!(
|
||||||
error_end,
|
|
||||||
reason: format!(
|
|
||||||
"Expected a condition of type Bool, found {:?}",
|
"Expected a condition of type Bool, found {:?}",
|
||||||
condition_type
|
condition_type
|
||||||
),
|
),
|
||||||
}));
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
else_if_member.body.check_semantics(scope)?;
|
else_if_member.body.check_semantics(scope)?;
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{semantic_error::SemanticError, MistiError},
|
error_handling::{
|
||||||
|
error_messages::{
|
||||||
|
COMPILER_TODO, SEMANTIC_INVALID_REFERENCE, SEMANTIC_MISMATCHED_ARGUMENT_COUNT,
|
||||||
|
SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
},
|
||||||
|
ErrorContainer, ErrorLabel, MistiError,
|
||||||
|
},
|
||||||
semantic::{
|
semantic::{
|
||||||
impls::SemanticCheck,
|
impls::SemanticCheck,
|
||||||
symbol_table::SymbolTable,
|
symbol_table::SymbolTable,
|
||||||
@ -22,15 +28,23 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
if parameters.len() != arguments.len() {
|
if parameters.len() != arguments.len() {
|
||||||
let (error_start, error_end) = f.arguments.get_position();
|
let (error_start, error_end) = f.arguments.get_position();
|
||||||
|
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!(
|
||||||
error_end,
|
|
||||||
reason: format!(
|
|
||||||
"Expected {} arguments, got {}",
|
"Expected {} arguments, got {}",
|
||||||
parameters.len(),
|
parameters.len(),
|
||||||
arguments.len(),
|
arguments.len(),
|
||||||
),
|
),
|
||||||
}));
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_ARGUMENT_COUNT,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that each argument matches the required datatype
|
// Check that each argument matches the required datatype
|
||||||
@ -42,14 +56,22 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
if !argument_datatype.is_value(parameter) {
|
if !argument_datatype.is_value(parameter) {
|
||||||
// The argument and the parameter have diferent types
|
// The argument and the parameter have diferent types
|
||||||
let (error_start, error_end) = argument.get_position();
|
let (error_start, error_end) = argument.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!(
|
||||||
error_end,
|
|
||||||
reason: format!(
|
|
||||||
"Expected a {}, got {:?}",
|
"Expected a {}, got {:?}",
|
||||||
parameter, argument_datatype
|
parameter, argument_datatype
|
||||||
),
|
),
|
||||||
}));
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,14 +79,22 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let (error_start, error_end) = fun.get_position();
|
let (error_start, error_end) = fun.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!(
|
||||||
error_end,
|
|
||||||
reason: format!(
|
|
||||||
"Expected a function type, got {:?}",
|
"Expected a function type, got {:?}",
|
||||||
function_datatype
|
function_datatype
|
||||||
),
|
),
|
||||||
}));
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,21 +117,37 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
} else {
|
} else {
|
||||||
// Error: unary negation can only be applied to a Bool
|
// Error: unary negation can only be applied to a Bool
|
||||||
let (error_start, error_end) = expression.get_position();
|
let (error_start, error_end) = expression.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!("Expected a Bool, got {}", t),
|
||||||
error_end,
|
start: error_start,
|
||||||
reason: format!("Expected a Bool, got a {}", t),
|
end: error_end,
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("!", Type::Function(_, _)) => {
|
("!", Type::Function(_, _)) => {
|
||||||
// Error: unary negation can only be applied to a Bool
|
// Error: unary negation can only be applied to a Bool
|
||||||
let (error_start, error_end) = expression.get_position();
|
let (error_start, error_end) = expression.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!("Expected a Bool, got a function"),
|
||||||
error_end,
|
start: error_start,
|
||||||
reason: format!("Expected a Bool, got a function",),
|
end: error_end,
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
("-", Type::Value(t)) => {
|
("-", Type::Value(t)) => {
|
||||||
if t == "Int" || t == "Float" {
|
if t == "Int" || t == "Float" {
|
||||||
@ -110,21 +156,37 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
} else {
|
} else {
|
||||||
// Error: unary negation can only be applied to a Number
|
// Error: unary negation can only be applied to a Number
|
||||||
let (error_start, error_end) = expression.get_position();
|
let (error_start, error_end) = expression.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!("Expected a Float or Int, got a {}", t),
|
||||||
error_end,
|
start: error_start,
|
||||||
reason: format!("Expected a Float or Int, got a {}", t),
|
end: error_end,
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("-", Type::Function(_, _)) => {
|
("-", Type::Function(_, _)) => {
|
||||||
// Error: unary negation can only be applied to a Bool
|
// Error: unary negation can only be applied to a Bool
|
||||||
let (error_start, error_end) = expression.get_position();
|
let (error_start, error_end) = expression.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!("Expected a Float or Int, got a function"),
|
||||||
error_end,
|
start: error_start,
|
||||||
reason: format!("Expected a Float or Int, got a function",),
|
end: error_end,
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
(op, _) => {
|
(op, _) => {
|
||||||
// Compiler error: something that shouldn't be
|
// Compiler error: something that shouldn't be
|
||||||
@ -146,11 +208,19 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
// If the operator is not found its a user error,
|
// If the operator is not found its a user error,
|
||||||
// because we allow arbitrary operators
|
// because we allow arbitrary operators
|
||||||
let (error_start, error_end) = (op.position, op.get_end_position());
|
let (error_start, error_end) = (op.position, op.get_end_position());
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!("The binary operator {} does not exist", op.value),
|
||||||
error_end,
|
start: error_start,
|
||||||
reason: format!("The binary operator {} does not exist", op.value),
|
end: error_end,
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_INVALID_REFERENCE,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -168,26 +238,42 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
|
|
||||||
if !left_expr_type.is_value(&op_params[0]) {
|
if !left_expr_type.is_value(&op_params[0]) {
|
||||||
let (error_start, error_end) = left_expr.get_position();
|
let (error_start, error_end) = left_expr.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!(
|
||||||
error_end,
|
|
||||||
reason: format!(
|
|
||||||
"Expected a {}, got a {:?} on the left side of the {} operator",
|
"Expected a {}, got a {:?} on the left side of the {} operator",
|
||||||
op_params[0], left_expr_type, op.value
|
op_params[0], left_expr_type, op.value
|
||||||
),
|
),
|
||||||
}));
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !right_expr_type.is_value(&op_params[1]) {
|
if !right_expr_type.is_value(&op_params[1]) {
|
||||||
let (error_start, error_end) = right_expr.get_position();
|
let (error_start, error_end) = right_expr.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!(
|
||||||
error_end,
|
|
||||||
reason: format!(
|
|
||||||
"Expected a {}, got a {:?} on the right side of the {} operator",
|
"Expected a {}, got a {:?} on the right side of the {} operator",
|
||||||
op_params[1], left_expr_type, op.value
|
op_params[1], left_expr_type, op.value
|
||||||
),
|
),
|
||||||
}));
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// After all these checks, we are ok
|
// After all these checks, we are ok
|
||||||
@ -206,13 +292,21 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
// TODO: if the array is empty then its
|
// TODO: if the array is empty then its
|
||||||
// datatype should be determined by its usage.
|
// datatype should be determined by its usage.
|
||||||
if arr.exps.is_empty() {
|
if arr.exps.is_empty() {
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start: arr.start,
|
message: format!(
|
||||||
error_end: arr.end,
|
|
||||||
reason: format!(
|
|
||||||
"An array must have at least 1 element to determine its type. This will be fixed later."
|
"An array must have at least 1 element to determine its type. This will be fixed later."
|
||||||
),
|
),
|
||||||
}));
|
start: arr.start,
|
||||||
|
end: arr.end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: COMPILER_TODO,
|
||||||
|
error_offset: arr.start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut expressions = arr.exps.iter();
|
let mut expressions = arr.exps.iter();
|
||||||
@ -227,15 +321,23 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
|
|
||||||
// error, found an item with a diferent datatype
|
// error, found an item with a diferent datatype
|
||||||
let (error_start, error_end) = exp.get_position();
|
let (error_start, error_end) = exp.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: format!(
|
||||||
error_end,
|
|
||||||
reason: format!(
|
|
||||||
"All elements of an array must have the same datatype. Expected {:?}, got {:?}",
|
"All elements of an array must have the same datatype. Expected {:?}, got {:?}",
|
||||||
first_type,
|
first_type,
|
||||||
exp_type,
|
exp_type,
|
||||||
),
|
),
|
||||||
}));
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: COMPILER_TODO,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{semantic_error::SemanticError, MistiError},
|
error_handling::{
|
||||||
|
error_messages::SEMANTIC_MISMATCHED_TYPES, ErrorContainer, ErrorLabel, MistiError,
|
||||||
|
},
|
||||||
semantic::{
|
semantic::{
|
||||||
impls::SemanticCheck,
|
impls::SemanticCheck,
|
||||||
symbol_table::SymbolTable,
|
symbol_table::SymbolTable,
|
||||||
@ -30,11 +32,19 @@ impl SemanticCheck for ForLoop<'_> {
|
|||||||
_ => {
|
_ => {
|
||||||
// error, types other than an Array are not supported
|
// error, types other than an Array are not supported
|
||||||
let (error_start, error_end) = self.collection.get_position();
|
let (error_start, error_end) = self.collection.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start,
|
message: String::from("Only Arrays are allowed here"),
|
||||||
error_end,
|
start: error_start,
|
||||||
reason: format!("Only Array[T] are allowed as a for-loop collection."),
|
end: error_end,
|
||||||
}));
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let item_type = &item_type[0];
|
let item_type = &item_type[0];
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{semantic_error::SemanticError, MistiError},
|
error_handling::{
|
||||||
|
error_messages::SEMANTIC_DUPLICATED_REFERENCE, ErrorContainer, ErrorLabel, MistiError,
|
||||||
|
},
|
||||||
semantic::{impls::SemanticCheck, symbol_table::SymbolTable, types::Type},
|
semantic::{impls::SemanticCheck, symbol_table::SymbolTable, types::Type},
|
||||||
syntax::ast::FunctionDeclaration,
|
syntax::ast::FunctionDeclaration,
|
||||||
};
|
};
|
||||||
@ -13,16 +15,24 @@ impl SemanticCheck for FunctionDeclaration<'_> {
|
|||||||
|
|
||||||
// Check that the function is not already defined
|
// Check that the function is not already defined
|
||||||
if scope.test(&function_name) {
|
if scope.test(&function_name) {
|
||||||
let error = SemanticError {
|
let (error_start, error_end) =
|
||||||
error_start: self.identifier.position,
|
(self.identifier.position, self.identifier.get_end_position());
|
||||||
error_end: self.identifier.get_end_position(),
|
let label = ErrorLabel {
|
||||||
reason: format!(
|
message: format!(
|
||||||
"Duplicated: A symbol with name {} was already defined",
|
"A symbol with name {} was already defined at this scope",
|
||||||
function_name
|
function_name,
|
||||||
),
|
),
|
||||||
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
};
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
return Err(MistiError::Semantic(error));
|
error_code: SEMANTIC_DUPLICATED_REFERENCE,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new scope and use it in the function block
|
// Create a new scope and use it in the function block
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{semantic_error::SemanticError, MistiError},
|
error_handling::{
|
||||||
|
error_messages::SEMANTIC_MISMATCHED_TYPES, ErrorContainer, ErrorLabel, MistiError,
|
||||||
|
},
|
||||||
semantic::{
|
semantic::{
|
||||||
impls::SemanticCheck,
|
impls::SemanticCheck,
|
||||||
symbol_table::SymbolTable,
|
symbol_table::SymbolTable,
|
||||||
@ -16,14 +18,23 @@ impl SemanticCheck for WhileLoop<'_> {
|
|||||||
|
|
||||||
if !condition_type.equals(&Type::Value("Bool".into())) {
|
if !condition_type.equals(&Type::Value("Bool".into())) {
|
||||||
let (error_start, error_end) = condition.get_position();
|
let (error_start, error_end) = condition.get_position();
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
|
||||||
error_start,
|
let label = ErrorLabel {
|
||||||
error_end,
|
message: format!(
|
||||||
reason: format!(
|
|
||||||
"Expected a condition of type Bool, found {:?}",
|
"Expected a condition of type Bool, found {:?}",
|
||||||
condition_type
|
condition_type
|
||||||
),
|
),
|
||||||
}));
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: Some(String::from("THP does not have truthy/falsey values.")),
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Define scoping rules for while loops
|
// TODO: Define scoping rules for while loops
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{semantic_error::SemanticError, MistiError},
|
error_handling::{
|
||||||
|
error_messages::{
|
||||||
|
COMPILER_TODO, SEMANTIC_INVALID_REFERENCE, SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
SEMANTIC_MISSING_REFERENCE,
|
||||||
|
},
|
||||||
|
ErrorContainer, ErrorLabel, MistiError,
|
||||||
|
},
|
||||||
semantic::symbol_table::SymbolTable,
|
semantic::symbol_table::SymbolTable,
|
||||||
syntax::ast::Expression,
|
syntax::ast::Expression,
|
||||||
};
|
};
|
||||||
@ -19,11 +25,19 @@ impl Typed for Expression<'_> {
|
|||||||
let datatype = match scope.get_type(&identifier.value) {
|
let datatype = match scope.get_type(&identifier.value) {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => {
|
None => {
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start: identifier.position,
|
message: String::from("Cannot find this identifier in this scope"),
|
||||||
error_end: identifier.get_end_position(),
|
start: identifier.position,
|
||||||
reason: format!("Cannot find `{}` in this scope.", identifier.value),
|
end: identifier.get_end_position(),
|
||||||
}))
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISSING_REFERENCE,
|
||||||
|
error_offset: identifier.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -43,20 +57,44 @@ impl Typed for Expression<'_> {
|
|||||||
// not the function itself
|
// not the function itself
|
||||||
Ok(Type::Value(return_type))
|
Ok(Type::Value(return_type))
|
||||||
}
|
}
|
||||||
Some(_) => Err(MistiError::Semantic(SemanticError {
|
Some(_) => {
|
||||||
error_start: id.position,
|
let label = ErrorLabel {
|
||||||
error_end: id.get_end_position(),
|
message: String::from(
|
||||||
reason: format!("Expected `{}` to be a function", &id.value),
|
"Expected this identifier to be a function",
|
||||||
})),
|
),
|
||||||
None => Err(MistiError::Semantic(SemanticError {
|
start: id.position,
|
||||||
error_start: id.position,
|
end: id.get_end_position(),
|
||||||
error_end: id.get_end_position(),
|
};
|
||||||
reason: format!("Cannot find `{}` in this scope.", id.value),
|
let econtainer = ErrorContainer {
|
||||||
})),
|
error_code: SEMANTIC_INVALID_REFERENCE,
|
||||||
|
error_offset: id.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let label = ErrorLabel {
|
||||||
|
message: String::from(
|
||||||
|
"Cannot find this identifier in this scope",
|
||||||
|
),
|
||||||
|
start: id.position,
|
||||||
|
end: id.get_end_position(),
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_INVALID_REFERENCE,
|
||||||
|
error_offset: id.position,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unimplemented!(
|
_ => unimplemented!(
|
||||||
"Get datatype of an expression that resolves into a function call"
|
"Get datatype of an expression that may resolve into a function call"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,35 +102,59 @@ impl Typed for Expression<'_> {
|
|||||||
let expr_type = match exp.get_type(scope) {
|
let expr_type = match exp.get_type(scope) {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(_reason) => {
|
Err(_reason) => {
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start: 0,
|
message: String::from("Error getting type of this expression"),
|
||||||
error_end: 1,
|
// TODO: Fix these positions
|
||||||
reason: format!("Error getting type of expression"),
|
start: 0,
|
||||||
}))
|
end: 1,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: COMPILER_TODO,
|
||||||
|
error_offset: 0,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only supported unary operator: - & !
|
// Only supported unary operator: - & !
|
||||||
if op.value == "-" {
|
if op.value == "-" {
|
||||||
if !expr_type.is_value("Int") && !expr_type.is_value("Float") {
|
if !expr_type.is_value("Int") && !expr_type.is_value("Float") {
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start: 0,
|
message: format!("Expected an `Int` or `Float`, got {:?}", expr_type),
|
||||||
error_end: 1,
|
// TODO: Fix positioning
|
||||||
reason: format!(
|
start: 0,
|
||||||
"Expected a Int or Float after unary `-`, got {:?}",
|
end: 1,
|
||||||
expr_type
|
};
|
||||||
),
|
let econtainer = ErrorContainer {
|
||||||
}));
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: 0,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
} else {
|
} else {
|
||||||
return Ok(Type::Value("Int".into()));
|
return Ok(Type::Value("Int".into()));
|
||||||
}
|
}
|
||||||
} else if op.value == "!" {
|
} else if op.value == "!" {
|
||||||
if !expr_type.is_value("Bool") {
|
if !expr_type.is_value("Bool") {
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start: 0,
|
message: format!("Expected a `Bool`, got {:?}", expr_type),
|
||||||
error_end: 1,
|
// TODO: Fix positioning
|
||||||
reason: format!("Expected a Bool after unary `!`, got {:?}", expr_type),
|
start: 0,
|
||||||
}));
|
end: 1,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: 0,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
} else {
|
} else {
|
||||||
return Ok(Type::Value("Bool".into()));
|
return Ok(Type::Value("Bool".into()));
|
||||||
}
|
}
|
||||||
@ -105,20 +167,27 @@ impl Typed for Expression<'_> {
|
|||||||
let t2 = exp2.get_type(scope)?;
|
let t2 = exp2.get_type(scope)?;
|
||||||
|
|
||||||
// TODO: There's definitely a better way to do this
|
// TODO: There's definitely a better way to do this
|
||||||
|
// maybe store operators as functions?
|
||||||
if operator.value == "+" && t1.is_value("Int") && t2.is_value("Int") {
|
if operator.value == "+" && t1.is_value("Int") && t2.is_value("Int") {
|
||||||
return Ok(Type::Value("Int".into()));
|
return Ok(Type::Value("Int".into()));
|
||||||
} else if operator.value == "-" && t1.is_value("Int") && t2.is_value("Int") {
|
} else if operator.value == "-" && t1.is_value("Int") && t2.is_value("Int") {
|
||||||
return Ok(Type::Value("Int".into()));
|
return Ok(Type::Value("Int".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
// TODO: fix positions
|
message: format!("Unsupported binary operator"),
|
||||||
error_start: 0,
|
// TODO: Fix positioning
|
||||||
error_end: 1,
|
start: 0,
|
||||||
reason: format!(
|
end: 1,
|
||||||
"Unsupported binary operator or invalid arguments to the operator."
|
};
|
||||||
),
|
let econtainer = ErrorContainer {
|
||||||
}));
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: 0,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
Expression::Array(arr) => {
|
Expression::Array(arr) => {
|
||||||
// The first expression found determines the
|
// The first expression found determines the
|
||||||
@ -129,13 +198,20 @@ impl Typed for Expression<'_> {
|
|||||||
// TODO: if the array is empty then its
|
// TODO: if the array is empty then its
|
||||||
// datatype should be determined by its usage.
|
// datatype should be determined by its usage.
|
||||||
if arr.exps.is_empty() {
|
if arr.exps.is_empty() {
|
||||||
return Err(MistiError::Semantic(SemanticError {
|
let label = ErrorLabel {
|
||||||
error_start: arr.start,
|
message: format!("Compiler limit: Arrays must have at least 1 element to determine their type"),
|
||||||
error_end: arr.end,
|
// TODO: Fix positioning
|
||||||
reason: format!(
|
start: arr.start,
|
||||||
"An array must have at least 1 element to determine its type. This will be fixed later."
|
end: arr.end,
|
||||||
),
|
};
|
||||||
}));
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: 0,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(MistiError::Semantic(econtainer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just get the first type and use it
|
// Just get the first type and use it
|
||||||
|
Loading…
Reference in New Issue
Block a user