feat: typecheck arrays
This commit is contained in:
parent
438802d011
commit
441db4bcad
@ -25,6 +25,7 @@
|
||||
- [x] Parse arrays
|
||||
- [x] Parse for loops
|
||||
- [x] Parse while loops
|
||||
- [x] Typecheck arrays
|
||||
|
||||
|
||||
## v0.1.1
|
||||
|
@ -137,10 +137,10 @@ impl SemanticCheck for Expression<'_> {
|
||||
// Operators are treated as functions
|
||||
let (op_params, _) = match scope.get_type(&op.value) {
|
||||
Some(Type::Function(params, return_t)) => (params, return_t),
|
||||
Some(Type::Value(v)) => {
|
||||
// If a operator is stored as a value,
|
||||
Some(t) => {
|
||||
// If a operator is stored as anything else
|
||||
// it's a bug in the compiler
|
||||
unreachable!("Compiler bug: a binary operator was registered in the symbol table as a value of type {}", v)
|
||||
unreachable!("Compiler bug: a binary operator was registered in the symbol table as a value of type {:?}", t)
|
||||
}
|
||||
None => {
|
||||
// If the operator is not found its a user error,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
error_handling::{semantic_error::SemanticError, MistiError},
|
||||
semantic::symbol_table::SymbolTable,
|
||||
syntax::ast::Expression,
|
||||
syntax::ast::{Expression, Positionable},
|
||||
};
|
||||
|
||||
use super::{Type, Typed};
|
||||
@ -31,12 +31,9 @@ impl Typed for Expression<'_> {
|
||||
Ok(datatype)
|
||||
}
|
||||
Expression::FunctionCall(f) => {
|
||||
// TODO: Must implement functions as first class citizens
|
||||
// for this to work with any arbitrary expression.
|
||||
// for now it justs expects an identifier
|
||||
|
||||
// TODO: Should this check that the type signature is correct?
|
||||
// or is this done elsewhere?
|
||||
// TODO: allow arbitrary expressions and
|
||||
// check that they resolve into a function
|
||||
// (e.g. object.member)
|
||||
|
||||
match &*f.function {
|
||||
Expression::Identifier(id) => {
|
||||
@ -115,6 +112,7 @@ impl Typed for Expression<'_> {
|
||||
}
|
||||
|
||||
return Err(MistiError::Semantic(SemanticError {
|
||||
// TODO: fix positions
|
||||
error_start: 0,
|
||||
error_end: 1,
|
||||
reason: format!(
|
||||
@ -122,7 +120,51 @@ impl Typed for Expression<'_> {
|
||||
),
|
||||
}));
|
||||
}
|
||||
Expression::Array(_) => unimplemented!("get type of array"),
|
||||
Expression::Array(arr) => {
|
||||
// The first expression found determines the
|
||||
// type of the array
|
||||
|
||||
// TODO: for now an array must have at least 1 element,
|
||||
// if the array is empty there is no way to know its type.
|
||||
// TODO: if the array is empty then its
|
||||
// datatype should be determined by its usage.
|
||||
if arr.exps.is_empty() {
|
||||
return Err(MistiError::Semantic(SemanticError {
|
||||
error_start: arr.start,
|
||||
error_end: arr.end,
|
||||
reason: format!(
|
||||
"An array must have at least 1 element to determine its type. This will be fixed later."
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
let mut expressions = arr.exps.iter();
|
||||
let first_expr = expressions.next().unwrap();
|
||||
let first_type = first_expr.get_type(scope)?;
|
||||
|
||||
// then check that every expression has the same type
|
||||
for exp in expressions {
|
||||
let exp_type = exp.get_type(scope)?;
|
||||
if !exp_type.equals(&first_type) {
|
||||
// TODO: subtyping
|
||||
|
||||
// error, found an item with a diferent datatype
|
||||
let (error_start, error_end) = exp.get_position();
|
||||
return Err(MistiError::Semantic(SemanticError {
|
||||
error_start,
|
||||
error_end,
|
||||
reason: format!(
|
||||
"All elements of an array must have the same datatype. Expected {:?}, got {:?}",
|
||||
first_type,
|
||||
exp_type,
|
||||
),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// return the Array type
|
||||
Ok(Type::Generic("Array".into(), vec![first_type]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,13 @@ pub enum Type {
|
||||
// TODO: Use Type instead of String to allow
|
||||
// arbitrary types
|
||||
Function(Vec<String>, String),
|
||||
/// The concrete type, the type parameters.
|
||||
///
|
||||
/// E.g.: Array[Int] -> ("Array", vec!["Int"])
|
||||
///
|
||||
/// E.g.: Map[String, Float] -> ("Map", vec!["String", "Float"])
|
||||
Generic(String, Vec<Type>),
|
||||
// TODO: tuple, union types
|
||||
// TODO: generics
|
||||
}
|
||||
|
||||
impl Type {
|
||||
@ -25,6 +30,18 @@ impl Type {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares this type to another
|
||||
pub fn equals(&self, other: &Self) -> bool {
|
||||
use Type::*;
|
||||
|
||||
match (self, other) {
|
||||
(Value(v1), Value(v2)) => v1 == v2,
|
||||
(Function(_, _), Function(_, _)) => unimplemented!("Comparison of 2 function types"),
|
||||
(Generic(_, _), Generic(_, _)) => unimplemented!("Comparison of 2 generic types"),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Typed {
|
||||
|
@ -24,4 +24,3 @@ pub struct WhileLoop<'a> {
|
||||
pub condition: Expression<'a>,
|
||||
pub body: Block<'a>,
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
/// Parses a factor expression.
|
||||
///
|
||||
/// ```ebnf
|
||||
/// factor = unary, (("/" | "*"), unary)*;
|
||||
/// factor = unary, (("/" | "*", "%"), unary)*;
|
||||
/// ```
|
||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||
let (unary, next_pos) = match super::unary::try_parse(tokens, pos) {
|
||||
@ -25,12 +25,12 @@ fn parse_many<'a>(
|
||||
prev_expr: Expression<'a>,
|
||||
indentation_level: u32,
|
||||
) -> ParsingResult<'a, Expression<'a>> {
|
||||
// (("/" | "*"), unary)*
|
||||
// (("/" | "*" | "%"), unary)*
|
||||
try_binary_op(
|
||||
tokens,
|
||||
pos,
|
||||
prev_expr,
|
||||
vec!["/", "*"],
|
||||
vec!["/", "*", "%"],
|
||||
indentation_level,
|
||||
|tokens, next_pos, prev_expr, token, indent_count: u32| {
|
||||
// match next
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
/// Parses a factor expression.
|
||||
///
|
||||
/// ```ebnf
|
||||
/// term = factor, (("-" | "+"), factor)*;
|
||||
/// term = factor, (("-" | "+" | "++"), factor)*;
|
||||
/// ```
|
||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParsingResult<Expression> {
|
||||
let (factor, next_pos) = match super::factor::try_parse(tokens, pos) {
|
||||
@ -24,13 +24,13 @@ fn parse_many<'a>(
|
||||
prev_expr: Expression<'a>,
|
||||
indentation_level: u32,
|
||||
) -> ParsingResult<'a, Expression<'a>> {
|
||||
// term = factor, (("-" | "+"), factor)*;
|
||||
// term = factor, (("-" | "+" | "++"), factor)*;
|
||||
|
||||
try_binary_op(
|
||||
tokens,
|
||||
pos,
|
||||
prev_expr,
|
||||
vec!["+", "-"],
|
||||
vec!["+", "-", "++"],
|
||||
indentation_level,
|
||||
|tokens, pos, prev_expr, token, indent_count: u32| {
|
||||
// Parse the next factor
|
||||
|
@ -2,8 +2,9 @@ use crate::{
|
||||
lexic::token::Token,
|
||||
syntax::{
|
||||
ast::{
|
||||
loops::{ForLoop, WhileLoop}, var_binding::VariableBinding, Conditional, FunctionDeclaration,
|
||||
Statement,
|
||||
loops::{ForLoop, WhileLoop},
|
||||
var_binding::VariableBinding,
|
||||
Conditional, FunctionDeclaration, Statement,
|
||||
},
|
||||
parseable::{Parseable, ParsingError, ParsingResult},
|
||||
},
|
||||
|
@ -1,8 +1,11 @@
|
||||
use crate::{
|
||||
error_handling::SyntaxError, lexic::token::{Token, TokenType}, syntax::{
|
||||
error_handling::SyntaxError,
|
||||
lexic::token::{Token, TokenType},
|
||||
syntax::{
|
||||
ast::{loops::WhileLoop, Block, Expression, Positionable},
|
||||
parseable::{Parseable, ParsingError, ParsingResult}, utils::parse_token_type,
|
||||
}
|
||||
parseable::{Parseable, ParsingError, ParsingResult},
|
||||
utils::parse_token_type,
|
||||
},
|
||||
};
|
||||
|
||||
impl<'a> Parseable<'a> for WhileLoop<'a> {
|
||||
@ -46,10 +49,7 @@ impl<'a> Parseable<'a> for WhileLoop<'a> {
|
||||
return Err(ParsingError::Err(SyntaxError {
|
||||
error_start: e.position,
|
||||
error_end: e.get_end_position(),
|
||||
reason: format!(
|
||||
"Expected a block after the condition, found {}",
|
||||
e.value
|
||||
),
|
||||
reason: format!("Expected a block after the condition, found {}", e.value),
|
||||
}))
|
||||
}
|
||||
Err(ParsingError::Unmatched) => {
|
||||
|
Loading…
Reference in New Issue
Block a user