diff --git a/.vscode/launch.json b/.vscode/launch.json index 3595beb..b4a91bf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,7 +16,7 @@ {"name": "RUST_BACKTRACE", "value": "1"} ], "console": "externalTerminal", - "preLaunchTask": "rust: cargo build" + "preLaunchTask": "build" }, { "name": "test", @@ -37,7 +37,7 @@ "cwd": "${workspaceFolder}", "env": {"RUST_BACKTRACE": "1"}, "console": "externalTerminal", - "preLaunchTask": "rust: cargo build" + "preLaunchTask": "build" } ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index eb50929..a2cd6a9 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,18 +4,12 @@ "version": "2.0.0", "tasks": [ { - "label": "MyTask", + "label": "build", "type": "shell", - "command": "cargo build" - }, - { - "type": "cargo", - "command": "build", + "command": "cargo build", "problemMatcher": [ "$rustc" ], - "group": "build", - "label": "rust: cargo build" - } + }, ] } \ No newline at end of file diff --git a/cli/test.fb b/cli/test.fb index 808cbd6..64ae466 100644 --- a/cli/test.fb +++ b/cli/test.fb @@ -1,3 +1,4 @@ +/* let test_ifs a b : bool -> bool -> int32 = if a then print_str "a\n"; @@ -20,7 +21,9 @@ let test_ifexpr a b : bool -> bool -> int32 = if a then 4 extern "C" let externed : int32 -> int32; - +*/ +let f (a:[int32;5]) = (); +/* let show_short_curicuit _ : () -> () = if (show_something ()) && (show_something_else ()) then print_str "this is a seperator\n"; @@ -41,14 +44,15 @@ let show_something_else _ : () -> bool = let test (a:(int32,int32)) = let x : int32 = 0; return x; - +*/ let main _ : () -> () = - let a : bool = true; - let x : int32 = 0; - match x where - | 1 -> print_str "one", - | 2 -> print_str "two", - print_str "main"; - show_short_curicuit (); - let y = externed 0; + // let a : bool = true; + // let x : int32 = 0; + // match x where + // | 1 -> print_str "one", + // | 2 -> print_str "two", + // print_str "main"; + // show_short_curicuit (); + // let y = externed 0; + f [1,2,3,4,5]; return (); \ No newline at end of file diff --git a/compiler/src/inference.rs b/compiler/src/inference.rs index 0eb9154..49d2b46 100644 --- a/compiler/src/inference.rs +++ b/compiler/src/inference.rs @@ -2405,4 +2405,92 @@ let consume a = fst a; "produces" ); } + + #[test] + fn array() { + const SRC : &'static str = " +let f (a:[int32;5]) = (); + +let main _ : () -> () = + f [1,2,3,4,5]; + return (); +"; + + let ast = crate::Parser::from_source(SRC).module(String::new()).ast; + let dtree = ast.get_dependencies(); + let dtree = dtree.into_iter().map(|(key,value)| (key,value.into_iter().collect())).collect(); + let mut inference_ctx = super::Context::new( + dtree, + HashMap::new(), + HashMap::new(), + HashMap::new(), + HashMap::new() + ); + let mut ast = inference_ctx.inference(ast); + ast.decls.sort_by_key(|decl| decl.get_ident()); + let [f,main]=&ast.decls[..] else { unreachable!() }; + assert_eq!( + &super::ast::Declaration::Value(super::ast::ValueDeclaration{ + loc : (1,4), + is_op:false, + ident:"f".to_string(), + args:vec![ + super::ast::ArgDeclaration { + loc:(1,7), + ident:"a".to_string(), + ty : ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }, + id:1, + }, + ], + ty:ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }.fn_ty(&types::UNIT), + value:super::ast::ValueType::Expr(super::ast::Expr::UnitLiteral), + generics:None, + abi:None, + id:0 + }), + f, + "the function" + ); + assert_eq!( + &super::ast::Declaration::Value(super::ast::ValueDeclaration{ + loc : (3,4), + is_op:false, + ident:"main".to_string(), + args:vec![ + super::ast::ArgDeclaration { + loc:(3,9), + ident:"_".to_string(), + ty : types::UNIT, + id:3, + }, + ], + ty:types::UNIT.fn_ty(&types::UNIT), + value:super::ast::ValueType::Function(vec![ + super::ast::Statement::FnCall(super::ast::FnCall { + loc:(4,4), + value:super::ast::Expr::ValueRead("f".to_string(), (4,4), 10).boxed(), + arg:super::ast::Expr::ArrayLiteral { + contents: vec![ + super::ast::Expr::NumericLiteral { value: "1".to_string(), id: 5, ty: types::INT32 }, + super::ast::Expr::NumericLiteral { value: "2".to_string(), id: 6, ty: types::INT32 }, + super::ast::Expr::NumericLiteral { value: "3".to_string(), id: 7, ty: types::INT32 }, + super::ast::Expr::NumericLiteral { value: "4".to_string(), id: 8, ty: types::INT32 }, + super::ast::Expr::NumericLiteral { value: "5".to_string(), id: 9, ty: types::INT32 }, + ], + loc: (4,6), + id: 4 + }.boxed(), + id:11, + returns:types::UNIT + }), + super::ast::Statement::Return(super::ast::Expr::UnitLiteral, (5,4)) + ]), + generics:None, + abi:None, + id:2 + }), + main, + "main" + ); + } } diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index 0f44682..602df04 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -146,8 +146,8 @@ pub fn from_file<'ctx>( ); let ast = inference_context.inference(ast); let mut ast = TypedModuleDeclaration::from(ast, &fwd_declarations, &HashMap::new()); //TODO: foward declare std lib - #[cfg(debug_assertions)] - println!("{:?}", ast.declarations); + // #[cfg(debug_assertions)] + // println!("{:?}", ast.declarations); ast.lower_generics(&HashMap::new()); ( if errors.is_empty() { diff --git a/compiler/src/parser.rs b/compiler/src/parser.rs index 6a6a681..24ffcff 100644 --- a/compiler/src/parser.rs +++ b/compiler/src/parser.rs @@ -114,7 +114,7 @@ where } pub fn next_statement(&mut self) -> ParserReturns { - match self.stream.clone().next() { + match dbg!(self.stream.clone().next()) { Some((Token::Let, _)) | Some((Token::For, _)) => { let ParserReturns { ast: generics, @@ -719,6 +719,7 @@ where | Token::StringLiteral(_) | Token::True | Token::False + | Token::BracketOpen ,_ )) = self.stream.peek() { match self.stream.peek().map(|(a,_)| a) { @@ -736,7 +737,7 @@ where errors.extend(expr_errors); } } - Some(Token::GroupOpen) =>{ + Some(Token::GroupOpen | Token::BracketOpen) =>{ let value = self.next_expr(); errors.extend(value.errors); warnings.extend(value.warnings); diff --git a/compiler/src/typed_ast.rs b/compiler/src/typed_ast.rs index 23f3c35..b5d9edb 100644 --- a/compiler/src/typed_ast.rs +++ b/compiler/src/typed_ast.rs @@ -1143,6 +1143,7 @@ pub enum TypedExpr { ValueRead(String, ResolvedType, crate::Location), ArrayLiteral { contents: Vec, + underlining: ResolvedType, }, /// NOT IMPLEMENTED YET /// defined like [| expr, expr, expr, ... |] @@ -1265,7 +1266,13 @@ impl TypedExpr { { Err(TypingError::ArgTypeMismatch) } else { - Ok(Self::ArrayLiteral { contents }) + let underlining = contents.first() + .map(|it| it.get_ty()) + .unwrap_or(types::ERROR); + Ok(Self::ArrayLiteral { + contents, + underlining, + }) } } #[allow(unused)] @@ -1274,8 +1281,6 @@ impl TypedExpr { loc, id: _, } => todo!(), - // #[allow(unused)] - // Expr::TupleLiteral { contents, loc } => todo!(), // TODO! tuples Expr::StructConstruction(strct) => Ok(Self::StructConstruction( TypedStructConstruction::from(strct, known_externs, known_values, known_types)?, )), @@ -1308,7 +1313,7 @@ impl TypedExpr { Self::UnaryOpCall(_) => todo!(), Self::FnCall(call) => call.loc, Self::BoolLiteral(_, loc) | Self::ValueRead(_, _, loc) => *loc, - Self::ArrayLiteral { contents: _ } => todo!(), + Self::ArrayLiteral { contents: _, underlining:_ } => todo!(), Self::ListLiteral { contents: _ } => todo!(), Self::TupleLiteral { contents: _, loc } => *loc, Self::StructConstruction(con) => con.loc, @@ -1335,8 +1340,8 @@ impl TypedExpr { Self::UnaryOpCall(data) => data.rt.clone(), Self::FnCall(data) => data.rt.clone(), Self::ValueRead(_, ty, _) => ty.clone(), - Self::ArrayLiteral { contents } => ResolvedType::Array { - underlining: contents.first().unwrap().get_ty().boxed(), + Self::ArrayLiteral { contents, underlining } => ResolvedType::Array { + underlining:underlining.clone().boxed(), size: contents.len(), }, Self::ListLiteral { .. } | Self::TupleLiteral { .. } => todo!(), @@ -1370,9 +1375,23 @@ impl TypedExpr { Self::UnaryOpCall(_) => todo!(), Self::FnCall(data) => data.replace_type(name, new_ty), Self::ValueRead(_, ty, _) => *ty = ty.replace_generic(name, new_ty.clone()), - Self::ArrayLiteral { contents } => contents + Self::ArrayLiteral { contents, underlining } => { + if let Some(ty) = contents .iter_mut() - .for_each(|it| it.replace_type(name, new_ty)), + .fold( + None, + |accum, it| { + it.replace_type(name, new_ty); + if accum.is_none() { + Some(it.get_ty()) + } else { + accum + } + } + ) { + *underlining=ty; + } + }, Self::ListLiteral { contents } => contents .iter_mut() .for_each(|it| it.replace_type(name, new_ty)), @@ -1455,7 +1474,7 @@ impl TypedExpr { *ident = new_name; *ty = fun_t; } - Self::ArrayLiteral { contents } + Self::ArrayLiteral { contents, underlining:_ } | Self::ListLiteral { contents } | Self::TupleLiteral { contents, loc:_ } => { let mut old_args = Vec::new(); @@ -4424,6 +4443,7 @@ let not_so_simple a : int32 -> [int32;4] = size: types::IntWidth::ThirtyTwo }, ], + underlining:types::INT32, }), ty: ResolvedType::Function { arg: types::UNIT.boxed(), @@ -4442,5 +4462,95 @@ let not_so_simple a : int32 -> [int32;4] = "simple" ); println!("{should_fail:?}"); + + const USAGE : &'static str = " +let f (a:[int32;5]) = (); + +let main _ : () -> () = + f [1,2,3,4,5]; + return (); +"; + + let ast = crate::Parser::from_source(USAGE).module(String::new()).ast; + let dtree = ast.get_dependencies(); + let dtree = dtree.into_iter().map(|(key,value)| (key,value.into_iter().collect())).collect(); + let mut inference_ctx = crate::inference::Context::new( + dtree, + HashMap::new(), + HashMap::new(), + HashMap::new(), + HashMap::new() + ); + let ast = inference_ctx.inference(ast); + let mut ast = TypedModuleDeclaration::from( + ast, + &HashMap::new(), + &HashMap::new(), + ); + ast.declarations.sort_by_key(|decl| decl.get_ident()); + let [f,main]=&ast.declarations[..] else { unreachable!() }; + assert_eq!( + &TypedDeclaration::Value(TypedValueDeclaration{ + loc : (1,4), + is_op:false, + is_curried:false, + ident:"f".to_string(), + args:vec![ + ArgDeclaration { + loc:(1,7), + ident:"a".to_string(), + ty : ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }, + id:1, + }, + ], + ty:ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }.fn_ty(&types::UNIT), + value:TypedValueType::Expr(TypedExpr::UnitLiteral), + generictypes:None, + abi:None, + }), + f, + "the function" + ); + assert_eq!( + &TypedDeclaration::Value(TypedValueDeclaration{ + loc : (3,4), + is_op:false, + ident:"main".to_string(), + args:vec![ + ArgDeclaration { + loc:(3,9), + ident:"_".to_string(), + ty : types::UNIT, + id:3, + }, + ], + ty:types::UNIT.fn_ty(&types::UNIT), + value:TypedValueType::Function(vec![ + TypedStatement::FnCall(TypedFnCall { + loc:(4,4), + value:TypedExpr::ValueRead("f".to_string(), ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }.fn_ty(&types::UNIT),(4,4)).boxed(), + arg:Some(TypedExpr::ArrayLiteral { + contents: vec![ + TypedExpr::IntegerLiteral { value: "1".to_string(), size: types::IntWidth::ThirtyTwo }, + TypedExpr::IntegerLiteral { value: "2".to_string(), size: types::IntWidth::ThirtyTwo }, + TypedExpr::IntegerLiteral { value: "3".to_string(), size: types::IntWidth::ThirtyTwo }, + TypedExpr::IntegerLiteral { value: "4".to_string(), size: types::IntWidth::ThirtyTwo }, + TypedExpr::IntegerLiteral { value: "5".to_string(), size: types::IntWidth::ThirtyTwo }, + ], + underlining:types::INT32, + }.boxed()), + rt:types::UNIT, + arg_t : ResolvedType::Array { underlining: types::INT32.boxed(), size: 5 }, + is_extern:false, + }), + TypedStatement::Return(TypedExpr::UnitLiteral, (5,4)) + ]), + generictypes:None, + abi:None, + is_curried:false + }), + main, + "main" + ); } } diff --git a/compiler/src/types.rs b/compiler/src/types.rs index ad1b759..97f9f6f 100644 --- a/compiler/src/types.rs +++ b/compiler/src/types.rs @@ -282,6 +282,20 @@ impl ResolvedType { } } + pub fn pass_by_pointer(&self) -> bool { + match self { + Self::Array { .. } + | Self::Tuple { .. } + | Self::Function { .. } + | Self::User { .. } => true, + _ => false + } + } + + pub fn is_array(&self) -> bool { + matches!(self,Self::Array { .. }) + } + pub fn is_user(&self) -> bool { matches!(self, Self::User { .. }) } diff --git a/llvm-codegen/src/code_gen.rs b/llvm-codegen/src/code_gen.rs index 3fba539..bdff5f8 100644 --- a/llvm-codegen/src/code_gen.rs +++ b/llvm-codegen/src/code_gen.rs @@ -1382,6 +1382,7 @@ impl<'ctx> CodeGen<'ctx> { let arg = self.compile_expr(*arg); let arg: BasicValueEnum = arg.try_into().unwrap(); let arg = if arg.is_pointer_value() + && !arg_t.is_pointer_type() && !arg .into_pointer_value() .get_type() @@ -1711,9 +1712,38 @@ impl<'ctx> CodeGen<'ctx> { } } TypedExpr::Match(match_) => self.compile_match(match_), - TypedExpr::ArrayLiteral { .. } => todo!(), - TypedExpr::ListLiteral { .. } => todo!(), - TypedExpr::TupleLiteral { .. } => todo!(), + TypedExpr::ArrayLiteral { contents, underlining } => { + let arr_ty = self.type_resolver.resolve_type_as_basic(underlining).array_type(contents.len() as u32); + let arr = self.builder.build_alloca(arr_ty, "").unwrap(); + for (idx,expr) in contents.into_iter().enumerate() { + let ele = convert_to_basic_value(self.compile_expr(expr)); + let loc = unsafe { + self.builder.build_in_bounds_gep( + arr, + &[ + self.ctx.i32_type().const_zero(), + self.ctx.i32_type().const_int(idx as u64, false) + ], + "" + ).unwrap() + }; + self.builder.build_store(loc,ele).unwrap(); + } + arr.as_any_value_enum() + }, + TypedExpr::ListLiteral { contents } => todo!(), + TypedExpr::TupleLiteral { contents, .. } => { + + let tys = contents.iter().map(|it| it.get_ty()).collect(); + let ty = self.type_resolver.resolve_type_as_basic(ResolvedType::Tuple { underlining: tys, loc: (0,0) }); + let tuple = self.builder.build_alloca(ty, "").unwrap(); + let loaded = self.builder.build_load(tuple,"").unwrap(); + for (idx,expr) in contents.into_iter().enumerate() { + let r = convert_to_basic_value(self.compile_expr(expr)); + self.builder.build_insert_value(loaded.into_array_value(), r, idx as u32, "").unwrap(); + } + tuple.as_any_value_enum() + }, TypedExpr::ErrorNode => unreachable!(), } } diff --git a/llvm-codegen/src/type_resolver.rs b/llvm-codegen/src/type_resolver.rs index 5db3d19..8739815 100644 --- a/llvm-codegen/src/type_resolver.rs +++ b/llvm-codegen/src/type_resolver.rs @@ -93,7 +93,11 @@ impl<'ctx> TypeResolver<'ctx> { if self.has_type(&ty) { return; } - match &ty { + match dbg!(&ty) { + ResolvedType::Array { underlining, size } => { + let result = self.resolve_type_as_basic(underlining.as_ref().clone()).array_type(*size as u32); + self.known.insert(ty,result.as_any_type_enum()); + }, ResolvedType::Ref { ref underlining } | ResolvedType::Pointer { ref underlining } => { if let ResolvedType::Function { .. } = underlining.as_ref() { let result = self @@ -201,7 +205,7 @@ impl<'ctx> TypeResolver<'ctx> { .struct_type(&[i8_ptr.into()], false) .ptr_type(AddressSpace::default()) .as_basic_type_enum() - } else if ty == &ResolvedType::Str || ty.is_user() { + } else if ty == &ResolvedType::Str || ty.pass_by_pointer() { self.resolve_type_as_basic(ty.clone()) .ptr_type(AddressSpace::default()) .as_basic_type_enum()