Compare commits

...

2 Commits

Author SHA1 Message Date
19cba2a7b3 Split Number into Int & Float 2024-05-06 10:13:21 -05:00
7218898ce0 Naive typechecking of binary operators 2024-05-06 09:53:18 -05:00
12 changed files with 100 additions and 70 deletions

View File

@ -26,11 +26,11 @@
## v0.0.12
- [x] Infer datatype of an identifier
- [ ] Infer datatype of a binary operatior
- [x] 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
- [x] 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

View File

@ -30,7 +30,7 @@ mod tests {
let binding = Binding {
datatype: None,
identifier: &id_token,
expression: Expression::Number(&value),
expression: Expression::Int(&value),
is_mutable: false,
};

View File

@ -11,7 +11,8 @@ impl Transpilable for Expression<'_> {
/// - Identifier
fn transpile(&self) -> String {
match self {
Expression::Number(value) => format!("{}", value),
Expression::Int(value) => format!("{}", value),
Expression::Float(value) => format!("{}", value),
Expression::String(value) => {
format!("{}", *value)
}
@ -41,7 +42,7 @@ mod tests {
#[test]
fn should_transpile_number() {
let str = String::from("42");
let exp = Expression::Number(&str);
let exp = Expression::Int(&str);
let result = exp.transpile();
assert_eq!("42", result);

View File

@ -35,7 +35,7 @@ mod tests {
let binding = Binding {
datatype: None,
identifier: &id_token,
expression: Expression::Number(&value),
expression: Expression::Int(&value),
is_mutable: false,
};

View File

@ -256,15 +256,15 @@ mod tests {
let tokens = get_tokens(&input).unwrap();
let t1 = tokens.get(0).unwrap();
assert_eq!(TokenType::Number, t1.token_type);
assert_eq!(TokenType::Int, t1.token_type);
assert_eq!("126", t1.value);
let t2 = tokens.get(1).unwrap();
assert_eq!(TokenType::Number, t2.token_type);
assert_eq!(TokenType::Float, t2.token_type);
assert_eq!("278.98", t2.value);
let t3 = tokens.get(2).unwrap();
assert_eq!(TokenType::Number, t3.token_type);
assert_eq!(TokenType::Float, t3.token_type);
assert_eq!("0.282398", t3.value);
assert_eq!("1789e+1", tokens.get(3).unwrap().value);
@ -324,7 +324,7 @@ mod tests {
let tokens = get_tokens(&input).unwrap();
assert_eq!(TokenType::NewLine, tokens[1].token_type);
assert_eq!(TokenType::Number, tokens[2].token_type);
assert_eq!(TokenType::Int, tokens[2].token_type);
}
#[test]
@ -333,7 +333,7 @@ mod tests {
let tokens = get_tokens(&input).unwrap();
assert_eq!(TokenType::NewLine, tokens[1].token_type);
assert_eq!(TokenType::Number, tokens[2].token_type);
assert_eq!(TokenType::Int, tokens[2].token_type);
}
#[test]
@ -341,10 +341,10 @@ mod tests {
let input = String::from("3\n \n 22");
let tokens = get_tokens(&input).unwrap();
assert_eq!(TokenType::Number, tokens[0].token_type);
assert_eq!(TokenType::Int, tokens[0].token_type);
assert_eq!(TokenType::NewLine, tokens[1].token_type);
assert_eq!(TokenType::INDENT, tokens[2].token_type);
assert_eq!(TokenType::Number, tokens[3].token_type);
assert_eq!(TokenType::Int, tokens[3].token_type);
}
#[test]
@ -352,13 +352,13 @@ mod tests {
let input = String::from("3\n \n 22\n 111");
let tokens = get_tokens(&input).unwrap();
assert_eq!(TokenType::Number, tokens[0].token_type);
assert_eq!(TokenType::Int, tokens[0].token_type);
assert_eq!(TokenType::NewLine, tokens[1].token_type);
assert_eq!(TokenType::INDENT, tokens[2].token_type);
assert_eq!(TokenType::Number, tokens[3].token_type);
assert_eq!(TokenType::Int, tokens[3].token_type);
assert_eq!(TokenType::NewLine, tokens[4].token_type);
assert_eq!(TokenType::INDENT, tokens[5].token_type);
assert_eq!(TokenType::Number, tokens[6].token_type);
assert_eq!(TokenType::Int, tokens[6].token_type);
}
#[test]
@ -366,12 +366,12 @@ mod tests {
let input = String::from("3\n \n 22\n 111");
let tokens = get_tokens(&input).unwrap();
assert_eq!(TokenType::Number, tokens[0].token_type);
assert_eq!(TokenType::Int, tokens[0].token_type);
assert_eq!(TokenType::NewLine, tokens[1].token_type);
assert_eq!(TokenType::INDENT, tokens[2].token_type);
assert_eq!(TokenType::Number, tokens[3].token_type);
assert_eq!(TokenType::Int, tokens[3].token_type);
assert_eq!(TokenType::NewLine, tokens[4].token_type);
assert_eq!(TokenType::Number, tokens[5].token_type);
assert_eq!(TokenType::Int, tokens[5].token_type);
}
#[test]
@ -379,13 +379,13 @@ mod tests {
let input = String::from("3\n \n 22\n111");
let tokens = get_tokens(&input).unwrap();
assert_eq!(TokenType::Number, tokens[0].token_type);
assert_eq!(TokenType::Int, tokens[0].token_type);
assert_eq!(TokenType::NewLine, tokens[1].token_type);
assert_eq!(TokenType::INDENT, tokens[2].token_type);
assert_eq!(TokenType::Number, tokens[3].token_type);
assert_eq!(TokenType::Int, tokens[3].token_type);
assert_eq!(TokenType::NewLine, tokens[4].token_type);
assert_eq!(TokenType::DEDENT, tokens[5].token_type);
assert_eq!(TokenType::Number, tokens[6].token_type);
assert_eq!(TokenType::Int, tokens[6].token_type);
}
#[test]
@ -393,16 +393,16 @@ mod tests {
let input = String::from("1\n 2\n 3\n 4\n5");
let tokens = get_tokens(&input).unwrap();
assert_eq!(TokenType::Number, tokens[0].token_type);
assert_eq!(TokenType::Int, tokens[0].token_type);
assert_eq!(TokenType::NewLine, tokens[1].token_type);
assert_eq!(TokenType::INDENT, tokens[2].token_type);
assert_eq!(TokenType::Number, tokens[3].token_type);
assert_eq!(TokenType::Int, tokens[3].token_type);
assert_eq!(TokenType::NewLine, tokens[4].token_type);
assert_eq!(TokenType::INDENT, tokens[5].token_type);
assert_eq!(TokenType::Number, tokens[6].token_type);
assert_eq!(TokenType::Int, tokens[6].token_type);
assert_eq!(TokenType::NewLine, tokens[7].token_type);
assert_eq!(TokenType::DEDENT, tokens[8].token_type);
assert_eq!(TokenType::Number, tokens[9].token_type);
assert_eq!(TokenType::Int, tokens[9].token_type);
assert_eq!(TokenType::NewLine, tokens[10].token_type);
assert_eq!(TokenType::DEDENT, tokens[11].token_type);
}
@ -412,13 +412,13 @@ mod tests {
let input = String::from("1\n 2\n 3\n4");
let tokens = get_tokens(&input).unwrap();
assert_eq!(TokenType::Number, tokens[0].token_type);
assert_eq!(TokenType::Int, tokens[0].token_type);
assert_eq!(TokenType::NewLine, tokens[1].token_type);
assert_eq!(TokenType::INDENT, tokens[2].token_type);
assert_eq!(TokenType::Number, tokens[3].token_type);
assert_eq!(TokenType::Int, tokens[3].token_type);
assert_eq!(TokenType::NewLine, tokens[4].token_type);
assert_eq!(TokenType::INDENT, tokens[5].token_type);
assert_eq!(TokenType::Number, tokens[6].token_type);
assert_eq!(TokenType::Int, tokens[6].token_type);
assert_eq!(TokenType::NewLine, tokens[7].token_type);
assert_eq!(TokenType::DEDENT, tokens[8].token_type);
assert_eq!(TokenType::DEDENT, tokens[9].token_type);
@ -435,10 +435,10 @@ mod indentation_tests {
let input = String::from("1\n 2");
let tokens = get_tokens(&input).unwrap();
assert_eq!(TokenType::Number, tokens[0].token_type);
assert_eq!(TokenType::Int, tokens[0].token_type);
assert_eq!(TokenType::NewLine, tokens[1].token_type);
assert_eq!(TokenType::INDENT, tokens[2].token_type);
assert_eq!(TokenType::Number, tokens[3].token_type);
assert_eq!(TokenType::Int, tokens[3].token_type);
assert_eq!(TokenType::DEDENT, tokens[4].token_type);
assert_eq!(TokenType::EOF, tokens[5].token_type);
}
@ -448,13 +448,13 @@ mod indentation_tests {
let input = String::from("1\n 2\n 3");
let tokens = get_tokens(&input).unwrap();
assert_eq!(TokenType::Number, tokens[0].token_type);
assert_eq!(TokenType::Int, tokens[0].token_type);
assert_eq!(TokenType::NewLine, tokens[1].token_type);
assert_eq!(TokenType::INDENT, tokens[2].token_type);
assert_eq!(TokenType::Number, tokens[3].token_type);
assert_eq!(TokenType::Int, tokens[3].token_type);
assert_eq!(TokenType::NewLine, tokens[4].token_type);
assert_eq!(TokenType::INDENT, tokens[5].token_type);
assert_eq!(TokenType::Number, tokens[6].token_type);
assert_eq!(TokenType::Int, tokens[6].token_type);
assert_eq!(TokenType::DEDENT, tokens[7].token_type);
assert_eq!(TokenType::DEDENT, tokens[8].token_type);
assert_eq!(TokenType::EOF, tokens[9].token_type);

View File

@ -1,7 +1,7 @@
use crate::error_handling::LexError;
use crate::lexic::{token::Token, utils, LexResult};
/// Function to scan a number
/// Function to scan an int/float
///
/// This function assumes that the character at `start_pos` is a number [0-9],
/// if not it will panic
@ -36,7 +36,7 @@ fn scan_decimal(chars: &Vec<char>, start_pos: usize, current: String) -> LexResu
let current_len = current.len();
LexResult::Some(
Token::new_number(current, start_pos - current_len),
Token::new_int(current, start_pos - current_len),
start_pos,
)
}
@ -98,7 +98,7 @@ fn scan_double_impl(chars: &Vec<char>, start_pos: usize, current: String) -> Lex
let current_len = current.len();
LexResult::Some(
Token::new_number(current, start_pos - current_len),
Token::new_float(current, start_pos - current_len),
start_pos,
)
}
@ -144,7 +144,7 @@ fn scan_digits(chars: &Vec<char>, start_pos: usize, current: String) -> (Token,
let current_len = current.len();
(
Token::new_number(current, start_pos - current_len),
Token::new_float(current, start_pos - current_len),
start_pos,
)
}
@ -163,7 +163,7 @@ fn scan_hex_digits(chars: &Vec<char>, start_pos: usize, current: String) -> (Tok
let current_len = current.len();
(
Token::new_number(current, start_pos - current_len),
Token::new_int(current, start_pos - current_len),
start_pos,
)
}
@ -187,7 +187,7 @@ mod tests {
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(3, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Int, token.token_type);
assert_eq!("123", token.value);
assert_eq!(0, token.position);
} else {
@ -199,7 +199,7 @@ mod tests {
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(4, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Int, token.token_type);
assert_eq!("0123", token.value);
assert_eq!(0, token.position);
} else {
@ -211,7 +211,7 @@ mod tests {
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(8, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Int, token.token_type);
assert_eq!("123456", token.value);
assert_eq!(2, token.position);
} else {
@ -227,7 +227,7 @@ mod tests {
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(3, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Int, token.token_type);
assert_eq!("123", token.value);
} else {
panic!()
@ -241,7 +241,7 @@ mod tests {
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(4, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Int, token.token_type);
assert_eq!("0x20", token.value);
assert_eq!(0, token.position);
} else {
@ -253,7 +253,7 @@ mod tests {
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(12, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Int, token.token_type);
assert_eq!("0xff23DA", token.value);
assert_eq!(4, token.position);
} else {
@ -277,7 +277,7 @@ mod tests {
let input = str_to_vec("0 x20 ");
let start_pos = 0;
if let LexResult::Some(token, _) = scan(&input, start_pos) {
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Int, token.token_type);
assert_eq!("0", token.value);
} else {
panic!()
@ -290,7 +290,7 @@ mod tests {
let input = str_to_vec("1x20");
let start_pos = 0;
if let LexResult::Some(token, _) = scan(&input, start_pos) {
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Int, token.token_type);
assert_eq!("1", token.value);
} else {
panic!()
@ -304,7 +304,7 @@ mod tests {
let start_pos = 0;
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(4, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Float, token.token_type);
assert_eq!("3.22", token.value);
assert_eq!(0, token.position);
} else {
@ -315,7 +315,7 @@ mod tests {
let start_pos = 0;
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(11, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Float, token.token_type);
assert_eq!("123456.7890", token.value);
assert_eq!(0, token.position);
} else {
@ -356,7 +356,7 @@ mod tests {
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!("1e+0", token.value);
assert_eq!(4, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Float, token.token_type);
assert_eq!(0, token.position);
} else {
panic!()
@ -366,7 +366,7 @@ mod tests {
let start_pos = 0;
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(4, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Float, token.token_type);
assert_eq!("1e-0", token.value);
assert_eq!(0, token.position);
} else {
@ -377,7 +377,7 @@ mod tests {
let start_pos = 0;
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(4, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Float, token.token_type);
assert_eq!("0e+0", token.value);
assert_eq!(0, token.position);
} else {
@ -388,7 +388,7 @@ mod tests {
let start_pos = 0;
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(19, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Float, token.token_type);
assert_eq!("123498790e+12349870", token.value);
assert_eq!(0, token.position);
} else {
@ -404,7 +404,7 @@ mod tests {
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!("1.24e+1", token.value);
assert_eq!(7, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Float, token.token_type);
assert_eq!(0, token.position);
} else {
panic!()
@ -415,7 +415,7 @@ mod tests {
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!("0.00000000000001e+1", token.value);
assert_eq!(19, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Float, token.token_type);
assert_eq!(0, token.position);
} else {
panic!()
@ -429,7 +429,7 @@ mod tests {
if let LexResult::Some(token, next) = scan(&input, start_pos) {
assert_eq!(5, next);
assert_eq!(TokenType::Number, token.token_type);
assert_eq!(TokenType::Int, token.token_type);
assert_eq!("123", token.value);
assert_eq!(2, token.position);
} else {

View File

@ -2,7 +2,8 @@
pub enum TokenType {
Identifier,
Datatype,
Number,
Int,
Float,
String,
Operator,
LeftParen,
@ -47,9 +48,17 @@ impl Token {
}
}
pub fn new_number(value: String, position: usize) -> Token {
pub fn new_int(value: String, position: usize) -> Token {
Token {
token_type: TokenType::Number,
token_type: TokenType::Int,
value,
position,
}
}
pub fn new_float(value: String, position: usize) -> Token {
Token {
token_type: TokenType::Float,
value,
position,
}

View File

@ -10,8 +10,8 @@ impl Typed for Expression<'_> {
/// Attempts to get the datatype for an expression.
fn get_type(&self, scope: &SymbolTable) -> Result<String, MistiError> {
match self {
// TODO: Distinguish between Int & Float
Expression::Number(_) => Ok("Int".into()),
Expression::Int(_) => Ok("Int".into()),
Expression::Float(_) => Ok("Float".into()),
Expression::String(_) => Ok("String".into()),
Expression::Boolean(_) => Ok("Bool".into()),
Expression::Identifier(identifier) => {
@ -31,7 +31,25 @@ impl Typed for Expression<'_> {
}
Expression::FunctionCall(_) => todo!(),
Expression::UnaryOperator(_, _) => todo!(),
Expression::BinaryOperator(_, _, _) => todo!(),
Expression::BinaryOperator(exp1, exp2, operator) => {
let t1 = exp1.get_type(scope)?;
let t2 = exp2.get_type(scope)?;
// TODO: There's definitely a better way to do this
if *operator == "+" && t1 == "Int" && t2 == "Int" {
return Ok("Int".into());
} else if *operator == "-" && t1 == "Int" && t2 == "Int" {
return Ok("Int".into());
}
return Err(MistiError::Semantic(SemanticError {
error_start: 0,
error_end: 1,
reason: format!(
"Unsupported binary operator or invalid arguments to the operator."
),
}));
}
}
}
}

View File

@ -43,7 +43,8 @@ pub struct Parameter<'a> {
#[derive(Debug)]
pub enum Expression<'a> {
Number(&'a String),
Int(&'a String),
Float(&'a String),
String(&'a String),
Boolean(bool),
Identifier(&'a String),

View File

@ -12,7 +12,8 @@ use crate::{
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
match tokens.get_significant(pos) {
Some((token, token_pos)) => match token.token_type {
TokenType::Number => Ok((Expression::Number(&token.value), token_pos + 1)),
TokenType::Int => Ok((Expression::Int(&token.value), token_pos + 1)),
TokenType::Float => Ok((Expression::Float(&token.value), token_pos + 1)),
TokenType::String => Ok((Expression::String(&token.value), token_pos + 1)),
TokenType::Identifier if token.value == "true" || token.value == "false" => {
Ok((Expression::Boolean(token.value == "true"), token_pos + 1))
@ -50,7 +51,7 @@ mod tests {
let expression = try_parse(&tokens, 0);
match expression {
Ok((Expression::Number(value), _)) => {
Ok((Expression::Int(value), _)) => {
assert_eq!("40", format!("{}", value))
}
_ => panic!(),

View File

@ -52,7 +52,7 @@ mod tests {
match expression {
Ok((Expression::UnaryOperator(operator, expression), _)) => {
match (operator, *expression) {
(op, Expression::Number(value)) => {
(op, Expression::Int(value)) => {
assert_eq!(*op, "-");
assert_eq!(*value, "10");
}

View File

@ -135,7 +135,7 @@ mod tests {
let first_argument = arguments_list.arguments.get(0).unwrap();
let Expression::Number(_) = first_argument else {
let Expression::Int(_) = first_argument else {
panic!("Expected a number")
};
}
@ -153,7 +153,7 @@ mod tests {
assert_eq!(arguments_list.arguments.len(), 1);
let first_argument = arguments_list.arguments.get(0).unwrap();
let Expression::Number(_) = first_argument else {
let Expression::Int(_) = first_argument else {
panic!("Expected a number")
};
}
@ -175,7 +175,7 @@ mod tests {
};
let second_argument = arguments_list.arguments.get(1).unwrap();
let Expression::Number(_) = second_argument else {
let Expression::Int(_) = second_argument else {
panic!("Expected a number")
};
}