mirror of
https://github.com/edg-l/edlang.git
synced 2024-11-09 09:38:24 +00:00
progress
This commit is contained in:
parent
8c212d948d
commit
071f5ce0f9
70
src/check.rs
70
src/check.rs
|
@ -3,6 +3,7 @@ use crate::{
|
|||
codegen::ProgramData,
|
||||
lexer::LexicalError,
|
||||
tokens::Token,
|
||||
type_analysis::TypeError,
|
||||
};
|
||||
use annotate_snippets::{
|
||||
display_list::{DisplayList, FormatOptions},
|
||||
|
@ -97,7 +98,6 @@ pub fn print_error(source: &str, err: ParseError<usize, Token, LexicalError>) {
|
|||
line_start: 1,
|
||||
fold: true,
|
||||
origin: None,
|
||||
|
||||
annotations: vec![SourceAnnotation {
|
||||
label: "invalid token",
|
||||
annotation_type: AnnotationType::Error,
|
||||
|
@ -126,14 +126,14 @@ pub fn print_error(source: &str, err: ParseError<usize, Token, LexicalError>) {
|
|||
}),
|
||||
footer: vec![],
|
||||
slices: vec![Slice {
|
||||
source: dbg!(source),
|
||||
source: source,
|
||||
line_start: 1,
|
||||
fold: false,
|
||||
origin: None,
|
||||
annotations: vec![SourceAnnotation {
|
||||
label: "invalid token (lexical error)",
|
||||
annotation_type: AnnotationType::Error,
|
||||
range: dbg!((range.start, range.end)),
|
||||
range: (range.start, range.end),
|
||||
}],
|
||||
}],
|
||||
opt: FormatOptions {
|
||||
|
@ -147,3 +147,67 @@ pub fn print_error(source: &str, err: ParseError<usize, Token, LexicalError>) {
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn print_type_error(source: &str, err: TypeError) {
|
||||
dbg!(&err);
|
||||
match err {
|
||||
TypeError::Mismatch {
|
||||
found,
|
||||
expected,
|
||||
span,
|
||||
} => {
|
||||
let snippet = Snippet {
|
||||
title: Some(Annotation {
|
||||
id: None,
|
||||
label: Some("type mismatch"),
|
||||
annotation_type: AnnotationType::Error,
|
||||
}),
|
||||
footer: vec![],
|
||||
slices: vec![Slice {
|
||||
source,
|
||||
line_start: 1,
|
||||
fold: false,
|
||||
origin: None,
|
||||
annotations: vec![SourceAnnotation {
|
||||
label: "type mismatch",
|
||||
annotation_type: AnnotationType::Error,
|
||||
range: span,
|
||||
}],
|
||||
}],
|
||||
opt: FormatOptions {
|
||||
color: true,
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
let dl = DisplayList::from(snippet);
|
||||
println!("{dl}");
|
||||
}
|
||||
TypeError::UndeclaredVariable { name, span } => {
|
||||
let snippet = Snippet {
|
||||
title: Some(Annotation {
|
||||
id: None,
|
||||
label: Some("undeclared variable"),
|
||||
annotation_type: AnnotationType::Error,
|
||||
}),
|
||||
footer: vec![],
|
||||
slices: vec![Slice {
|
||||
source,
|
||||
line_start: 1,
|
||||
fold: false,
|
||||
origin: None,
|
||||
annotations: vec![SourceAnnotation {
|
||||
label: "undeclared variable",
|
||||
annotation_type: AnnotationType::Error,
|
||||
range: span,
|
||||
}],
|
||||
}],
|
||||
opt: FormatOptions {
|
||||
color: true,
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
let dl = DisplayList::from(snippet);
|
||||
println!("{dl}");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -178,12 +178,12 @@ impl<'ctx> CodeGen<'ctx> {
|
|||
let args_types: Vec<BasicMetadataTypeEnum<'ctx>> =
|
||||
args_types.into_iter().map(|t| t.into()).collect_vec();
|
||||
|
||||
let (fn_type, ret_type) = match &function.return_type {
|
||||
let fn_type = match &function.return_type {
|
||||
Some(id) => {
|
||||
let return_type = self.get_llvm_type(id)?;
|
||||
(return_type.fn_type(&args_types, false), Some(id.clone()))
|
||||
return_type.fn_type(&args_types, false)
|
||||
}
|
||||
None => (self.context.void_type().fn_type(&args_types, false), None),
|
||||
None => self.context.void_type().fn_type(&args_types, false),
|
||||
};
|
||||
|
||||
self.module.add_function(&function.name, fn_type, None);
|
||||
|
@ -447,6 +447,8 @@ impl<'ctx> CodeGen<'ctx> {
|
|||
.compile_expression(rhs, variables, scope_info)?
|
||||
.expect("should have result");
|
||||
|
||||
assert_eq!(lhs.get_type(), rhs.get_type(), "type mismatch");
|
||||
|
||||
let lhs = lhs.into_int_value();
|
||||
let rhs = rhs.into_int_value();
|
||||
|
||||
|
|
30
src/main.rs
30
src/main.rs
|
@ -3,12 +3,15 @@
|
|||
use check::print_error;
|
||||
use clap::{Parser, Subcommand};
|
||||
use codegen::ProgramData;
|
||||
use color_eyre::Result;
|
||||
use inkwell::{context::Context, execution_engine::JitFunction, OptimizationLevel};
|
||||
use lalrpop_util::lalrpop_mod;
|
||||
use std::{fs, path::PathBuf, println};
|
||||
|
||||
use crate::{ast::Program, check::Check, lexer::Lexer};
|
||||
use crate::{
|
||||
ast::Program,
|
||||
check::{print_type_error, Check},
|
||||
lexer::Lexer,
|
||||
};
|
||||
|
||||
pub mod ast;
|
||||
pub mod check;
|
||||
|
@ -91,7 +94,7 @@ fn check_program(program: &ProgramData, ast: &ast::Program) -> bool {
|
|||
error_count == 0
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
tracing_subscriber::fmt::init();
|
||||
let args = Args::parse();
|
||||
|
@ -102,7 +105,10 @@ fn main() -> Result<()> {
|
|||
let lexer = Lexer::new(code.as_str());
|
||||
let parser = grammar::ProgramParser::new();
|
||||
let mut ast = parser.parse(lexer)?;
|
||||
type_analysis::type_inference(&mut ast);
|
||||
if let Err(e) = type_analysis::type_check(&mut ast) {
|
||||
print_type_error(&code, e);
|
||||
return Ok(());
|
||||
}
|
||||
let program = ProgramData::new(&input, &code);
|
||||
check_program(&program, &ast);
|
||||
}
|
||||
|
@ -112,7 +118,10 @@ fn main() -> Result<()> {
|
|||
let parser = grammar::ProgramParser::new();
|
||||
match parser.parse(lexer) {
|
||||
Ok(mut ast) => {
|
||||
type_analysis::type_inference(&mut ast);
|
||||
if let Err(e) = type_analysis::type_check(&mut ast) {
|
||||
print_type_error(&code, e);
|
||||
return Ok(());
|
||||
}
|
||||
println!("{ast:#?}");
|
||||
}
|
||||
Err(e) => {
|
||||
|
@ -130,7 +139,10 @@ fn main() -> Result<()> {
|
|||
let lexer = Lexer::new(code.as_str());
|
||||
let parser = grammar::ProgramParser::new();
|
||||
let mut ast: Program = parser.parse(lexer)?;
|
||||
type_analysis::type_inference(&mut ast);
|
||||
if let Err(e) = type_analysis::type_check(&mut ast) {
|
||||
print_type_error(&code, e);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let program = ProgramData::new(&input, &code);
|
||||
|
||||
|
@ -156,7 +168,11 @@ fn main() -> Result<()> {
|
|||
let code = fs::read_to_string(&input)?;
|
||||
let lexer = Lexer::new(&code[..]);
|
||||
let parser = grammar::ProgramParser::new();
|
||||
let ast = parser.parse(lexer).unwrap();
|
||||
let mut ast: Program = parser.parse(lexer)?;
|
||||
if let Err(e) = type_analysis::type_check(&mut ast) {
|
||||
print_type_error(&code, e);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let program = ProgramData::new(&input, &code);
|
||||
|
||||
|
|
|
@ -2,21 +2,30 @@ use std::collections::{HashMap, HashSet};
|
|||
|
||||
use crate::ast::{self, Expression, Function, Statement, TypeExp};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TypeError {
|
||||
Mismatch {
|
||||
found: TypeExp,
|
||||
expected: TypeExp,
|
||||
span: (usize, usize),
|
||||
},
|
||||
UndeclaredVariable {
|
||||
name: String,
|
||||
span: (usize, usize),
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct Storage {
|
||||
structs: HashMap<String, HashMap<String, TypeExp>>,
|
||||
functions: HashMap<String, Function>,
|
||||
}
|
||||
|
||||
// problem with scopes,
|
||||
// let x = 2;
|
||||
// let x = 2i64;
|
||||
|
||||
type ScopeMap = HashMap<String, Vec<Option<TypeExp>>>;
|
||||
|
||||
// this works, but need to find a way to store the found info + handle literal integer types (or not?)
|
||||
// maybe use scope ids
|
||||
pub fn type_inference(ast: &mut ast::Program) {
|
||||
pub fn type_check(ast: &mut ast::Program) -> Result<(), TypeError> {
|
||||
let mut storage = Storage::default();
|
||||
|
||||
// gather global constructs first
|
||||
|
@ -40,8 +49,6 @@ pub fn type_inference(ast: &mut ast::Program) {
|
|||
}
|
||||
}
|
||||
|
||||
dbg!(&storage);
|
||||
|
||||
for statement in ast.statements.iter_mut() {
|
||||
if let Statement::Function(function) = statement {
|
||||
let mut scope_vars: ScopeMap = HashMap::new();
|
||||
|
@ -52,7 +59,7 @@ pub fn type_inference(ast: &mut ast::Program) {
|
|||
|
||||
let func_info = function.clone();
|
||||
let (new_scope_vars, _) =
|
||||
type_inference_scope(&mut function.body, &scope_vars, &func_info, &storage);
|
||||
type_inference_scope(&mut function.body, &scope_vars, &func_info, &storage)?;
|
||||
// todo: check all vars have type info?
|
||||
function.scope_type_info = new_scope_vars
|
||||
.into_iter()
|
||||
|
@ -60,6 +67,7 @@ pub fn type_inference(ast: &mut ast::Program) {
|
|||
.collect();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Finds variable types in the scope, returns newly created variables to handle shadowing
|
||||
|
@ -68,7 +76,7 @@ fn type_inference_scope(
|
|||
scope_vars: &ScopeMap,
|
||||
func: &Function,
|
||||
storage: &Storage,
|
||||
) -> (ScopeMap, HashSet<String>) {
|
||||
) -> Result<(ScopeMap, HashSet<String>), TypeError> {
|
||||
let mut scope_vars = scope_vars.clone();
|
||||
let mut new_vars: HashSet<String> = HashSet::new();
|
||||
|
||||
|
@ -78,11 +86,11 @@ fn type_inference_scope(
|
|||
name,
|
||||
value,
|
||||
value_type,
|
||||
span: _,
|
||||
span,
|
||||
} => {
|
||||
new_vars.insert(name.clone());
|
||||
|
||||
let exp_type = type_inference_expression(value, &mut scope_vars, storage, None);
|
||||
let exp_type = type_inference_expression(value, &mut scope_vars, storage, None)?;
|
||||
|
||||
if !scope_vars.contains_key(name) {
|
||||
scope_vars.insert(name.clone(), vec![]);
|
||||
|
@ -94,27 +102,31 @@ fn type_inference_scope(
|
|||
var.push(exp_type);
|
||||
} else {
|
||||
if exp_type.is_some() && &exp_type != value_type {
|
||||
panic!("let type mismatch: {:?} != {:?}", value_type, exp_type);
|
||||
Err(TypeError::Mismatch {
|
||||
found: exp_type.clone().unwrap(),
|
||||
expected: value_type.clone().unwrap(),
|
||||
span: *span,
|
||||
})?;
|
||||
}
|
||||
var.push(value_type.clone());
|
||||
}
|
||||
}
|
||||
Statement::Mutate {
|
||||
name,
|
||||
value,
|
||||
span: _,
|
||||
} => {
|
||||
Statement::Mutate { name, value, span } => {
|
||||
if !scope_vars.contains_key(name) {
|
||||
panic!("undeclared variable");
|
||||
}
|
||||
|
||||
let exp_type = type_inference_expression(value, &mut scope_vars, storage, None);
|
||||
let exp_type = type_inference_expression(value, &mut scope_vars, storage, None)?;
|
||||
let var = scope_vars.get_mut(name).unwrap().last_mut().unwrap();
|
||||
|
||||
if var.is_none() {
|
||||
*var = exp_type;
|
||||
} else if exp_type.is_some() && &exp_type != var {
|
||||
panic!("mutate type mismatch: {:?} != {:?}", var, exp_type);
|
||||
Err(TypeError::Mismatch {
|
||||
found: exp_type.clone().unwrap(),
|
||||
expected: var.clone().unwrap(),
|
||||
span: *span,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Statement::If {
|
||||
|
@ -129,10 +141,10 @@ fn type_inference_scope(
|
|||
&mut scope_vars,
|
||||
storage,
|
||||
Some(TypeExp::Boolean),
|
||||
);
|
||||
)?;
|
||||
|
||||
let (new_scope_vars, new_vars) =
|
||||
type_inference_scope(body, &scope_vars, func, storage);
|
||||
type_inference_scope(body, &scope_vars, func, storage)?;
|
||||
|
||||
for (k, v) in new_scope_vars.iter() {
|
||||
// not a new var within the scope (shadowing), so type info is valid
|
||||
|
@ -148,7 +160,7 @@ fn type_inference_scope(
|
|||
|
||||
if let Some(body) = else_body {
|
||||
let (new_scope_vars, new_vars) =
|
||||
type_inference_scope(body, &scope_vars, func, storage);
|
||||
type_inference_scope(body, &scope_vars, func, storage)?;
|
||||
|
||||
for (k, v) in new_scope_vars.iter() {
|
||||
// not a new var within the scope (shadowing), so type info is valid
|
||||
|
@ -170,7 +182,7 @@ fn type_inference_scope(
|
|||
&mut scope_vars,
|
||||
storage,
|
||||
func.return_type.clone(),
|
||||
);
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Statement::Function(_) => unreachable!(),
|
||||
|
@ -178,7 +190,7 @@ fn type_inference_scope(
|
|||
}
|
||||
}
|
||||
|
||||
(scope_vars, new_vars)
|
||||
Ok((scope_vars, new_vars))
|
||||
}
|
||||
|
||||
fn type_inference_expression(
|
||||
|
@ -186,8 +198,8 @@ fn type_inference_expression(
|
|||
scope_vars: &mut ScopeMap,
|
||||
storage: &Storage,
|
||||
expected_type: Option<TypeExp>,
|
||||
) -> Option<TypeExp> {
|
||||
match exp {
|
||||
) -> Result<Option<TypeExp>, TypeError> {
|
||||
Ok(match exp {
|
||||
Expression::Literal(lit) => {
|
||||
match lit {
|
||||
ast::LiteralValue::String(_) => None, // todo
|
||||
|
@ -214,7 +226,13 @@ fn type_inference_expression(
|
|||
*var = expected_type.clone();
|
||||
expected_type
|
||||
} else if expected_type.is_some() {
|
||||
assert_eq!(*var, expected_type, "type mismatch with variables");
|
||||
if *var != expected_type {
|
||||
Err(TypeError::Mismatch {
|
||||
found: expected_type.clone().unwrap(),
|
||||
expected: var.clone().unwrap(),
|
||||
span: name.span,
|
||||
})?;
|
||||
}
|
||||
expected_type
|
||||
} else {
|
||||
var.clone()
|
||||
|
@ -229,7 +247,7 @@ fn type_inference_expression(
|
|||
for (i, arg) in args.iter().enumerate() {
|
||||
let arg_type = func.params[i].type_exp.clone();
|
||||
// result is ignored, but need these to infer call arg types
|
||||
type_inference_expression(arg, scope_vars, storage, Some(arg_type));
|
||||
type_inference_expression(arg, scope_vars, storage, Some(arg_type))?;
|
||||
}
|
||||
|
||||
func.return_type
|
||||
|
@ -238,15 +256,19 @@ fn type_inference_expression(
|
|||
ast::OpCode::Eq | ast::OpCode::Ne => Some(TypeExp::Boolean),
|
||||
_ => {
|
||||
let lhs_type =
|
||||
type_inference_expression(lhs, scope_vars, storage, expected_type.clone());
|
||||
let rhs_type = type_inference_expression(rhs, scope_vars, storage, expected_type);
|
||||
type_inference_expression(lhs, scope_vars, storage, expected_type.clone())?;
|
||||
let rhs_type = type_inference_expression(rhs, scope_vars, storage, expected_type)?;
|
||||
|
||||
if lhs_type.is_some() && rhs_type.is_some() {
|
||||
assert_eq!(lhs_type, rhs_type, "types should match");
|
||||
if lhs_type.is_some() && rhs_type.is_some() && lhs_type != rhs_type {
|
||||
Err(TypeError::Mismatch {
|
||||
found: rhs_type.clone().unwrap(),
|
||||
expected: lhs_type.clone().unwrap(),
|
||||
span: (0, 0), // todo
|
||||
})?;
|
||||
}
|
||||
|
||||
lhs_type.or(rhs_type)
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue