Compare commits

...

11 Commits

22 changed files with 630 additions and 206 deletions

View File

@ -9,8 +9,8 @@ contains the relevant abstraction to produce a more Rust'y API from that.
Much of the syntax in Reid is directly inspired by rust, but mostly it is driven Much of the syntax in Reid is directly inspired by rust, but mostly it is driven
by simplicity. by simplicity.
Specifications and documentation for the language can be found Specifications and a bunch of [documentation for the language can be found
[here](./documentation/). here](./documentation/).
Reid is currently able to (non-exhaustively): Reid is currently able to (non-exhaustively):
- Do basic algebra binary and unary-operations (e.g. Add, Sub, Div, Mult, And, - Do basic algebra binary and unary-operations (e.g. Add, Sub, Div, Mult, And,

View File

@ -18,6 +18,12 @@ A collection of documentation and examples to get you going can be found at [the
Book of Reid](./book.md). It is recommended you read through the chapter about Book of Reid](./book.md). It is recommended you read through the chapter about
Syntax first though to familiarize yourself with the basic concepts of Reid. Syntax first though to familiarize yourself with the basic concepts of Reid.
## Intrinsics
Reid also has intrinsic functions that are good to know about. These are more
in-depth, but when you're feeling up to it, you can read about them
[here](./intrinsics.md).
## Syntax and general information ## Syntax and general information
Syntax for Reid is very much inspired by rust, and examples of the language can Syntax for Reid is very much inspired by rust, and examples of the language can
@ -247,6 +253,8 @@ calls, literals, or if-expressions. Types of supported expressions include:
- **Function calls**, to invoke a predefined function with given parameters - **Function calls**, to invoke a predefined function with given parameters
- **Associated function calls**, to invoke a predefined function on a certain - **Associated function calls**, to invoke a predefined function on a certain
*associated type* with given parameters. *associated type* with given parameters.
- **Accessing function calls**, a shorthand to call associated function calls
which have `&self` or `&mut self` as their first parameter.
- **Block-expressions**, which can return a value to the higher-level expression - **Block-expressions**, which can return a value to the higher-level expression
if they have a statement with a soft-return. Otherwise they return void. if they have a statement with a soft-return. Otherwise they return void.
- **If-expressions**, which can execute one of two expressions depending on the - **If-expressions**, which can execute one of two expressions depending on the
@ -263,7 +271,7 @@ In formal grammar:
<array> | <struct> | <array> | <struct> |
<indexing> | <accessing> | <indexing> | <accessing> |
<binary-exp> | <unary-exp> | <binary-exp> | <unary-exp> |
<function-call> | <assoc-function-call> <function-call> | <accessing-function-call> | <assoc-function-call>
<block> | <if-expr> | <cast> | <block> | <if-expr> | <cast> |
( "(" <expression> ")" ) ( "(" <expression> ")" )
@ -278,6 +286,7 @@ In formal grammar:
<binary-exp> :: <expression> <binop> <expression> <binary-exp> :: <expression> <binop> <expression>
<unary-exp> :: <unary> <expression> <unary-exp> :: <unary> <expression>
<function-call> :: <expression> "(" [ <expression> ( "," <expression> )* ] ")" <function-call> :: <expression> "(" [ <expression> ( "," <expression> )* ] ")"
<accessing-function-call> :: <accessing> "(" [ <expression> ( "," <expression> )* ] ")"
<assoc-function-call> :: <type> "::" <function-call> <assoc-function-call> :: <type> "::" <function-call>
<if-expr> :: "if" <expression> <expression> [ "else" <expression> ] <if-expr> :: "if" <expression> <expression> [ "else" <expression> ]
<cast> :: <expression> "as" <type> <cast> :: <expression> "as" <type>
@ -296,6 +305,7 @@ test.first // Accessing
!bool_value // Unary !bool_value // Unary
func(value, 14) // Function call func(value, 14) // Function call
Test::get_field(&test); // Associated function call Test::get_field(&test); // Associated function call
test.get_field(); // Same, but using a the dot-form shorthand
if varname {} else {} // If-expression if varname {} else {} // If-expression
value as u32 // cast value as u32 // cast
(value + 2) // Binop within parenthesis (value + 2) // Binop within parenthesis

View File

@ -22,6 +22,7 @@ or simply casting the value (e.g. `5 as u32`).
## Table of Contents: ## Table of Contents:
- [Hello World](#hello-world) - [Hello World](#hello-world)
- [Borrowing and Pointers](#borrowing-and-pointers) - [Borrowing and Pointers](#borrowing-and-pointers)
- [Harder Hello World](#harder-hello-world)
### Hello World ### Hello World
@ -119,4 +120,74 @@ fn mutate(value: &mut [u32; 3]) {
This example will always return `17`. Notice also, how a **mutable** borrow was This example will always return `17`. Notice also, how a **mutable** borrow was
passed to `mutate`-function. While borrows do not always need to be mutable, passed to `mutate`-function. While borrows do not always need to be mutable,
this example would not work without the `mut`-keyword. Try it out for yourself this example would not work without the `mut`-keyword. Try it out for yourself
to see why! to see why!
### Harder Hello World
A little bit harder example to the previous hello world would be
`hello_world_harder.reid` from [examples](../examples/hello_world_harder.reid)
```rust
import std::print;
import std::String;
fn main() {
let mut test = String::from("hello");
test.push(String::from(" world: "));
test.push_num(175);
print(test);
test.free();
return;
}
```
Let's go through this again line-by-line
```rust
import std::print;
import std::String;
```
At the start are the standard imports, like in the original Hello World, but
notice that instead of importing just functions we import the type `String` as
well. When importing types, not only are the type imported, but also any binary
functions or associated functions related to it with it.
```rust
let mut test = String::from("hello");
```
Next we create the initial string, just like in our original example, but this
time the message is not complete. We also use an associated function to create
the string instead one of the now-deprecated global functions.
```rust
test.push(String::from(" world: "));
test.push_num(175);
```
After that we edit the message by first pushing ` world: ` to it, and also
appending the number `175` at the end of it. For both of these operations we are
again using associated functions, but in a different short-hand syntax.
These two lines would be actually equivalent to the above ones:
```rust
String::push(&mut test, String::from(" world: "));
String::push_num(&mut test, 175);
```
----
```rust
print(test);
test.free();
return;
```
After that we simply print the string, and free up the string (again with an
associated function) before returning. Nothing special there!

View File

@ -0,0 +1,28 @@
## Intrinsics
Intrinsics are functions that are defined within the language compiler but not
in standard library, thus they do not require importing in order to use (and
trying to re-define these will end up causing issues). Intrinsics include all
pre-existing binary-operators, but also some regular functions and associated
functions (that every type has by-default). This document lists them all (except
for the binary operators, because there are hundreds of those).
### Associated Intrinsics
#### `<T>::sizeof() -> u64`
Simply returns the size of type `T` in bits.
```rust
i32::sizeof(); // Returns 32
```
#### `<T>::alloca(size: u64) -> *T`
Allocates `T::sizeof() * size` bits and returns a pointer to `T`.
**Note:** This does not seem to work correctly currently.
```rust
i32::alloca(30); // Returns *i32
```

View File

@ -10,30 +10,58 @@ Has the following binops defined:
- `String` + `*char` = `String` - `String` + `*char` = `String`
- `String` + `u64` = `String` - `String` + `u64` = `String`
#### `pub fn print(message: String)` ##### `String::new() -> String`
Prints given `message` to the standard output Returns a new empty `String`-object, which must later be manually freed.
##### `String::from(str: *char) -> String`
Creates a new `String`-object containing initially data from the given string-literal which must be later freed.
##### `String::set(&mut self, c: char, position: u64)`
Edits given `string` by setting the character at index `position` to be `c`.
##### `String::push_num(&mut self, num: u64)`
Formats the given number into the end of the string.
##### `String::concat(&mut self, source: String)`
Concatenates `source` to the end of `destination`.
### Deprecated functions
#### `pub fn new_string() -> String` #### `pub fn new_string() -> String`
Returns a new empty `String`-object, which must later be manually freed. Returns a new empty `String`-object, which must later be manually freed.
_deprecated: Use `String::new()`_
#### `pub fn from_str(string: *char) -> String` #### `pub fn from_str(string: *char) -> String`
Creates a new `String`-object containing initially data from the given string-literal which must be later freed. Creates a new `String`-object containing initially data from the given string-literal which must be later freed.
_deprecated: Use `String::from()`_
#### `pub fn set_char(string: &mut String, c: char, position: u64)` #### `pub fn set_char(string: &mut String, c: char, position: u64)`
Edits given `string` by setting the character at index `position` to be `c`. Edits given `string` by setting the character at index `position` to be `c`.
_deprecated: Use `String::set()`_
#### `pub fn add_num_to_string(string: &mut String, num: u64)` #### `pub fn add_num_to_string(string: &mut String, num: u64)`
Formats the given number into the end of the string. Formats the given number into the end of the string.
_deprecated: Use `String::push_num()`_
#### `pub fn concat_strings(destination: &mut String, source: String)` #### `pub fn concat_strings(destination: &mut String, source: String)`
Concatenates `source` to the end of `destination`. Concatenates `source` to the end of `destination`.
_deprecated: Use `String::concat()`_
## General ## General
#### `pub fn allocate(size: u64) -> *u8` #### `pub fn allocate(size: u64) -> *u8`

View File

@ -7,8 +7,8 @@ struct Otus {
} }
impl Otus { impl Otus {
fn test(self) -> u32 { fn test(&self) -> u32 {
self.field *self.field
} }
} }

View File

@ -12,4 +12,4 @@ fn main() -> u32 {
fn mutate(value: &mut [u32; 3]) { fn mutate(value: &mut [u32; 3]) {
// Dereference the borrow to mutate it // Dereference the borrow to mutate it
*value[1] = 17; *value[1] = 17;
} }

View File

@ -1,25 +1,16 @@
import std::print; import std::print;
import std::from_str; import std::String;
import std::add_char;
import std::set_char;
import std::free_string;
import std::new_string;
import std::add_num_to_str;
import std::concat_strings;
fn main() { fn main() {
let mut test = from_str("hello"); let mut test = String::from("hello");
concat_strings(&mut test, from_str(" world")); test.push(String::from(" world: "));
add_char(&mut test, '!'); test.push_num(175);
add_char(&mut test, '\n');
add_num_to_str(&mut test, 175);
print(test); print(test);
free_string(&test); test.free();
return; return;
} }

View File

@ -11,6 +11,88 @@ struct String {
must_be_freed: bool, must_be_freed: bool,
} }
impl String {
pub fn new() -> String {
String {
inner: allocate(0),
length: 0,
max_length: 0,
must_be_freed: true,
}
}
pub fn from(str: *char) -> String {
let length = str_length(str) as u64;
let mut new = String::new();
let static = String {
inner: str,
length: length - 1,
max_length: length,
must_be_freed: false,
};
concat_strings(&mut new, static);
return new;
}
pub fn push(&mut self, other: String) {
for i in 0 .. (str_length(other.inner) - 1) {
add_char(self, other.inner[i]);
}
}
pub fn add_char(&mut self, c: char) {
if ((*self).length + 1) >= (*self).max_length {
let new = allocate((*self).max_length + 4) as *char;
copy_bits((*self).inner, new, (*self).max_length);
if (*self).must_be_freed == true {
free((*self).inner as *u8);
}
(*self).max_length = (*self).max_length + 4;
(*self).inner = new;
(*self).must_be_freed = true;
}
(*self).inner[(*self).length] = c;
(((*self).inner) as *u8)[(*self).length + 1] = 0;
(*self).length = (*self).length + 1;
}
pub fn push_num(&mut self, num: u64) {
if num >= 10 {
self.push_num(num / 10)
}
let rem = num % 10;
if rem == 0 { self.add_char('0'); }
else if rem == 1 { self.add_char('1'); }
else if rem == 2 { self.add_char('2'); }
else if rem == 3 { self.add_char('3'); }
else if rem == 4 { self.add_char('4'); }
else if rem == 5 { self.add_char('5'); }
else if rem == 6 { self.add_char('6'); }
else if rem == 7 { self.add_char('7'); }
else if rem == 8 { self.add_char('8'); }
else if rem == 9 { self.add_char('9'); }
}
pub fn concat(&mut self, other: &String) {
for i in 0 .. *other.length {
self.add_char(*other.inner[i]);
}
}
pub fn set(&mut self, c: char, position: u64) {
if position <= (*self).length {
(*self).inner[position] = c;
}
}
pub fn free(&self) {
free((*self).inner as *u8);
}
}
impl binop (lhs: String) + (rhs: *char) -> String { impl binop (lhs: String) + (rhs: *char) -> String {
let mut new = lhs; let mut new = lhs;
let added = from_str(rhs); let added = from_str(rhs);

View File

@ -80,8 +80,8 @@ pub struct Expression(pub ExpressionKind, pub TokenRange);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ExpressionKind { pub enum ExpressionKind {
VariableName(String), VariableName(String),
Borrow(String, bool), Borrow(Box<Expression>, bool),
Deref(String), Deref(Box<Expression>),
Literal(Literal), Literal(Literal),
Array(Vec<Expression>), Array(Vec<Expression>),
ArrayShort(Box<Expression>, u64), ArrayShort(Box<Expression>, u64),

View File

@ -179,6 +179,36 @@ impl Parse for AssociatedFunctionCall {
} }
} }
fn apply_inner<T>(expr: PrimaryExpression, fun: T) -> Expression
where
T: FnOnce(PrimaryExpression) -> Expression,
{
match &expr.0 .0 {
ExpressionKind::Indexed(value_expr, index_expr) => Expression(
ExpressionKind::Indexed(
Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)),
index_expr.clone(),
),
expr.0 .1,
),
ExpressionKind::Accessed(value_expr, index_name) => Expression(
ExpressionKind::Accessed(
Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)),
index_name.clone(),
),
expr.0 .1,
),
ExpressionKind::AccessCall(value_expr, fn_call) => Expression(
ExpressionKind::AccessCall(
Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)),
fn_call.clone(),
),
expr.0 .1,
),
_ => fun(expr),
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct PrimaryExpression(Expression); pub struct PrimaryExpression(Expression);
@ -195,18 +225,21 @@ impl Parse for PrimaryExpression {
} else if let (Some(Token::Et), Some(Token::MutKeyword)) = (stream.peek(), stream.peek2()) { } else if let (Some(Token::Et), Some(Token::MutKeyword)) = (stream.peek(), stream.peek2()) {
stream.next(); // Consume Et stream.next(); // Consume Et
stream.next(); // Consume mut stream.next(); // Consume mut
let Some(Token::Identifier(name)) = stream.next() else { Expression(
return Err(stream.expected_err("identifier")?); Kind::Borrow(Box::new(stream.parse()?), true),
}; stream.get_range().unwrap(),
Expression(Kind::Borrow(name, true), stream.get_range().unwrap()) )
} else if let (Some(Token::Et), Some(Token::Identifier(name))) = (stream.peek(), stream.peek2()) { } else if let Some(Token::Et) = stream.peek() {
stream.next(); // Consume Et stream.next(); // Consume Et
stream.next(); // Consume identifier Expression(
Expression(Kind::Borrow(name, false), stream.get_range().unwrap()) Kind::Borrow(Box::new(stream.parse()?), false),
} else if let (Some(Token::Star), Some(Token::Identifier(name))) = (stream.peek(), stream.peek2()) { stream.get_range().unwrap(),
)
} else if let Some(Token::Star) = stream.peek() {
stream.next(); // Consume Et stream.next(); // Consume Et
stream.next(); // Consume identifier apply_inner(stream.parse()?, |e| {
Expression(Kind::Deref(name), stream.get_range().unwrap()) Expression(Kind::Deref(Box::new(e.0)), stream.get_range().unwrap())
})
} else if let Ok(unary) = stream.parse() { } else if let Ok(unary) = stream.parse() {
Expression( Expression(
Kind::UnaryOperation(unary, Box::new(stream.parse()?)), Kind::UnaryOperation(unary, Box::new(stream.parse()?)),
@ -658,12 +691,23 @@ impl Parse for FunctionSignature {
let self_kind = stream.parse::<SelfParam>().map(|s| s.0).unwrap_or(SelfKind::None); let self_kind = stream.parse::<SelfParam>().map(|s| s.0).unwrap_or(SelfKind::None);
if let Ok(param) = stream.parse::<FunctionParam>() { match &self_kind {
params.push((param.0, param.1)); SelfKind::None => {
while let Some(Token::Comma) = stream.peek() { if let Ok(param) = stream.parse::<FunctionParam>() {
stream.next(); params.push((param.0, param.1));
let param = stream.parse::<FunctionParam>()?; while let Some(Token::Comma) = stream.peek() {
params.push((param.0, param.1)); stream.next();
let param = stream.parse::<FunctionParam>()?;
params.push((param.0, param.1));
}
}
}
_ => {
while let Some(Token::Comma) = stream.peek() {
stream.next();
let param = stream.parse::<FunctionParam>()?;
params.push((param.0, param.1));
}
} }
} }
@ -1019,15 +1063,20 @@ impl Parse for AssociatedFunctionBlock {
let ty = stream.parse::<Type>()?; let ty = stream.parse::<Type>()?;
stream.expect(Token::BraceOpen)?; stream.expect(Token::BraceOpen)?;
let mut functions = Vec::new(); let mut functions = Vec::new();
while let Some(Token::FnKeyword) = stream.peek() { loop {
let mut fun: FunctionDefinition = stream.parse()?; match stream.peek() {
fun.0.self_kind = match fun.0.self_kind { Some(Token::FnKeyword) | Some(Token::PubKeyword) => {
SelfKind::Owned(_) => SelfKind::Owned(ty.0.clone()), let mut fun: FunctionDefinition = stream.parse()?;
SelfKind::Borrow(_) => SelfKind::Borrow(ty.0.clone()), fun.0.self_kind = match fun.0.self_kind {
SelfKind::MutBorrow(_) => SelfKind::MutBorrow(ty.0.clone()), SelfKind::Owned(_) => SelfKind::Owned(ty.0.clone()),
SelfKind::None => SelfKind::None, SelfKind::Borrow(_) => SelfKind::Borrow(ty.0.clone()),
}; SelfKind::MutBorrow(_) => SelfKind::MutBorrow(ty.0.clone()),
functions.push(fun); SelfKind::None => SelfKind::None,
};
functions.push(fun);
}
_ => break,
}
} }
stream.expect(Token::BraceClose)?; stream.expect(Token::BraceClose)?;

View File

@ -36,6 +36,7 @@ impl ast::Module {
ExternFunction(signature) => { ExternFunction(signature) => {
let def = mir::FunctionDefinition { let def = mir::FunctionDefinition {
name: signature.name.clone(), name: signature.name.clone(),
linkage_name: None,
is_pub: false, is_pub: false,
is_imported: false, is_imported: false,
return_type: signature return_type: signature
@ -149,6 +150,7 @@ impl ast::FunctionDefinition {
); );
mir::FunctionDefinition { mir::FunctionDefinition {
name: signature.name.clone(), name: signature.name.clone(),
linkage_name: None,
is_pub: *is_pub, is_pub: *is_pub,
is_imported: false, is_imported: false,
return_type: signature return_type: signature
@ -361,19 +363,10 @@ impl ast::Expression {
mir::TypeKind::Vague(mir::VagueType::Unknown), mir::TypeKind::Vague(mir::VagueType::Unknown),
name.clone(), name.clone(),
), ),
ast::ExpressionKind::Borrow(name, mutable) => mir::ExprKind::Borrow( ast::ExpressionKind::Borrow(expr, mutable) => {
NamedVariableRef( mir::ExprKind::Borrow(Box::new(expr.process(module_id)), *mutable)
mir::TypeKind::Vague(mir::VagueType::Unknown), }
name.clone(), ast::ExpressionKind::Deref(expr) => mir::ExprKind::Deref(Box::new(expr.process(module_id))),
self.1.as_meta(module_id),
),
*mutable,
),
ast::ExpressionKind::Deref(name) => mir::ExprKind::Deref(NamedVariableRef(
mir::TypeKind::Vague(mir::VagueType::Unknown),
name.clone(),
self.1.as_meta(module_id),
)),
ast::ExpressionKind::UnaryOperation(unary_operator, expr) => match unary_operator { ast::ExpressionKind::UnaryOperation(unary_operator, expr) => match unary_operator {
ast::UnaryOperator::Plus => mir::ExprKind::BinOp( ast::UnaryOperator::Plus => mir::ExprKind::BinOp(
mir::BinaryOperator::Add, mir::BinaryOperator::Add,
@ -424,7 +417,13 @@ impl ast::Expression {
), ),
ast::ExpressionKind::AccessCall(expression, fn_call_expr) => { ast::ExpressionKind::AccessCall(expression, fn_call_expr) => {
let mut params: Vec<_> = fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(); let mut params: Vec<_> = fn_call_expr.1.iter().map(|e| e.process(module_id)).collect();
params.insert(0, expression.process(module_id)); params.insert(
0,
mir::Expression(
mir::ExprKind::Borrow(Box::new(expression.process(module_id)), true),
expression.1.as_meta(module_id),
),
);
mir::ExprKind::AssociatedFunctionCall( mir::ExprKind::AssociatedFunctionCall(
mir::TypeKind::Vague(mir::VagueType::Unknown), mir::TypeKind::Vague(mir::VagueType::Unknown),
mir::FunctionCall { mir::FunctionCall {

View File

@ -40,6 +40,7 @@ pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDef
match name { match name {
"sizeof" => Some(FunctionDefinition { "sizeof" => Some(FunctionDefinition {
name: "sizeof".to_owned(), name: "sizeof".to_owned(),
linkage_name: None,
is_pub: true, is_pub: true,
is_imported: false, is_imported: false,
return_type: TypeKind::U64, return_type: TypeKind::U64,
@ -48,6 +49,7 @@ pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDef
}), }),
"alloca" => Some(FunctionDefinition { "alloca" => Some(FunctionDefinition {
name: "alloca".to_owned(), name: "alloca".to_owned(),
linkage_name: None,
is_pub: true, is_pub: true,
is_imported: false, is_imported: false,
return_type: TypeKind::UserPtr(Box::new(ty.clone())), return_type: TypeKind::UserPtr(Box::new(ty.clone())),
@ -56,6 +58,7 @@ pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDef
}), }),
"null" => Some(FunctionDefinition { "null" => Some(FunctionDefinition {
name: "null".to_owned(), name: "null".to_owned(),
linkage_name: None,
is_pub: true, is_pub: true,
is_imported: false, is_imported: false,
return_type: TypeKind::UserPtr(Box::new(ty.clone())), return_type: TypeKind::UserPtr(Box::new(ty.clone())),

View File

@ -187,7 +187,7 @@ impl mir::Module {
let is_main = self.is_main && function.name == "main"; let is_main = self.is_main && function.name == "main";
let func = match &function.kind { let func = match &function.kind {
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function( mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
&function.name, &function.linkage_name.clone().unwrap_or(function.name.clone()),
function.return_type.get_type(&type_values), function.return_type.get_type(&type_values),
param_types, param_types,
FunctionFlags { FunctionFlags {
@ -198,7 +198,7 @@ impl mir::Module {
}, },
)), )),
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function( mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
&function.name, &function.linkage_name.clone().unwrap_or(function.name.clone()),
function.return_type.get_type(&type_values), function.return_type.get_type(&type_values),
param_types, param_types,
FunctionFlags { FunctionFlags {
@ -238,7 +238,7 @@ impl mir::Module {
}, },
)), )),
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function( mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
&function.name, &function.linkage_name.clone().unwrap_or(function.name.clone()),
function.return_type.get_type(&type_values), function.return_type.get_type(&type_values),
param_types, param_types,
FunctionFlags { FunctionFlags {
@ -1144,12 +1144,8 @@ impl mir::Expression {
TypeKind::CustomType(type_key), TypeKind::CustomType(type_key),
)) ))
} }
mir::ExprKind::Borrow(varref, mutable) => { mir::ExprKind::Borrow(expr, mutable) => {
varref.0.known().expect("variable type unknown"); let v = expr.codegen(scope, &state.load(false))?.unwrap();
let v = scope
.stack_values
.get(&varref.1)
.expect("Variable reference not found?!");
let TypeKind::CodegenPtr(ptr_inner) = &v.1 else { let TypeKind::CodegenPtr(ptr_inner) = &v.1 else {
panic!(); panic!();
@ -1160,12 +1156,8 @@ impl mir::Expression {
TypeKind::Borrow(Box::new(*ptr_inner.clone()), *mutable), TypeKind::Borrow(Box::new(*ptr_inner.clone()), *mutable),
)) ))
} }
mir::ExprKind::Deref(varref) => { mir::ExprKind::Deref(expr) => {
varref.0.known().expect("variable type unknown"); let v = expr.codegen(scope, &state.load(false))?.unwrap();
let v = scope
.stack_values
.get(&varref.1)
.expect("Variable reference not found?!");
let TypeKind::CodegenPtr(ptr_inner) = &v.1 else { let TypeKind::CodegenPtr(ptr_inner) = &v.1 else {
panic!(); panic!();
@ -1174,7 +1166,7 @@ impl mir::Expression {
let var_ptr_instr = scope let var_ptr_instr = scope
.block .block
.build_named( .build_named(
format!("{}.deref", varref.1), format!("{}.deref", expr.backing_var().unwrap().1),
Instr::Load(v.0.instr(), ptr_inner.get_type(scope.type_values)), Instr::Load(v.0.instr(), ptr_inner.get_type(scope.type_values)),
) )
.unwrap(); .unwrap();
@ -1187,7 +1179,7 @@ impl mir::Expression {
scope scope
.block .block
.build_named( .build_named(
format!("{}.deref.inner", varref.1), format!("{}.deref.inner", expr.backing_var().unwrap().1),
Instr::Load(var_ptr_instr, inner.get_type(scope.type_values)), Instr::Load(var_ptr_instr, inner.get_type(scope.type_values)),
) )
.unwrap(), .unwrap(),
@ -1300,6 +1292,9 @@ fn codegen_function_call<'ctx, 'a>(
}; };
let val = if let Some(ty) = associated_type { let val = if let Some(ty) = associated_type {
// Unwrap type from borrow if it is in a borrow
let ty = if let TypeKind::Borrow(inner, _) = ty { inner } else { ty };
let assoc_key = AssociatedFunctionKey(ty.clone(), call.name.clone()); let assoc_key = AssociatedFunctionKey(ty.clone(), call.name.clone());
let intrinsic_def = get_intrinsic_assoc_func(&ty, &call.name); let intrinsic_def = get_intrinsic_assoc_func(&ty, &call.name);
let intrinsic = intrinsic_def.map(|func_def| { let intrinsic = intrinsic_def.map(|func_def| {

View File

@ -208,6 +208,19 @@ impl TypeKind {
None None
} }
} }
pub fn unroll_borrows(&self) -> TypeKind {
match self {
TypeKind::Borrow(type_kind, mut1) => match *type_kind.clone() {
TypeKind::Borrow(type_kind, mut2) => match (mut1, mut2) {
(false, false) => TypeKind::Borrow(Box::new(*type_kind.clone()), false),
_ => TypeKind::Borrow(Box::new(*type_kind.clone()), true),
},
_ => self.clone(),
},
_ => self.clone(),
}
}
} }
impl BinaryOperator { impl BinaryOperator {
@ -425,15 +438,15 @@ impl Expression {
ReturnKind::Soft, ReturnKind::Soft,
TypeKind::CustomType(CustomTypeKey(name.clone(), mod_id)), TypeKind::CustomType(CustomTypeKey(name.clone(), mod_id)),
)), )),
Borrow(var, mutable) => { Borrow(expr, mutable) => {
let ret_type = var.return_type()?; let ret_type = expr.return_type(refs, mod_id)?;
Ok((ret_type.0, TypeKind::Borrow(Box::new(ret_type.1), *mutable))) Ok((ret_type.0, TypeKind::Borrow(Box::new(ret_type.1), *mutable)))
} }
Deref(var) => { Deref(expr) => {
let (kind, ret_type) = var.return_type()?; let (kind, ret_type) = expr.return_type(refs, mod_id)?;
match ret_type.resolve_weak(refs) { match ret_type.resolve_weak(refs) {
TypeKind::Borrow(type_kind, _) => Ok((kind, *type_kind)), TypeKind::Borrow(type_kind, _) => Ok((kind, *type_kind)),
_ => Err(ReturnTypeOther::DerefNonBorrow(var.2)), _ => Err(ReturnTypeOther::DerefNonBorrow(expr.1)),
} }
} }
CastTo(expr, type_kind) => match expr.return_type(refs, mod_id) { CastTo(expr, type_kind) => match expr.return_type(refs, mod_id) {
@ -452,8 +465,8 @@ impl Expression {
ExprKind::Variable(var_ref) => Some(var_ref), ExprKind::Variable(var_ref) => Some(var_ref),
ExprKind::Indexed(lhs, _, _) => lhs.backing_var(), ExprKind::Indexed(lhs, _, _) => lhs.backing_var(),
ExprKind::Accessed(lhs, _, _) => lhs.backing_var(), ExprKind::Accessed(lhs, _, _) => lhs.backing_var(),
ExprKind::Borrow(var, _) => Some(var), ExprKind::Borrow(expr, _) => expr.backing_var(),
ExprKind::Deref(var) => Some(var), ExprKind::Deref(expr) => expr.backing_var(),
ExprKind::Block(block) => block.backing_var(), ExprKind::Block(block) => block.backing_var(),
ExprKind::Array(_) => None, ExprKind::Array(_) => None,
ExprKind::Struct(_, _) => None, ExprKind::Struct(_, _) => None,

View File

@ -227,7 +227,8 @@ impl<'map> Pass for LinkerPass<'map> {
} }
importer_module.functions.push(FunctionDefinition { importer_module.functions.push(FunctionDefinition {
name: func_name, name: func_name.clone(),
linkage_name: None,
is_pub: false, is_pub: false,
is_imported: false, is_imported: false,
return_type, return_type,
@ -268,6 +269,66 @@ impl<'map> Pass for LinkerPass<'map> {
FunctionDefinitionKind::Intrinsic(_) => {} FunctionDefinitionKind::Intrinsic(_) => {}
} }
} }
for (ty, func) in &mut imported.associated_functions {
if *ty != imported_ty {
continue;
}
let func_name = func.name.clone();
dbg!(&func_name);
if !func.is_pub {
state.ok::<_, Infallible>(
Err(ErrorKind::FunctionIsPrivate(module_name.clone(), func_name.clone())),
import.1,
);
continue;
}
func.is_imported = true;
if let Some((_, existing)) = importer_module
.associated_functions
.iter()
.find(|(ty, f)| *ty == imported_ty && f.name == *func_name)
{
if let Err(e) = existing.equals_as_imported(func) {
state.ok::<_, Infallible>(
Err(ErrorKind::FunctionImportIssue(
module_name.clone(),
func_name.clone(),
e,
)),
import.1,
);
}
}
let types = import_type(&func.return_type, false);
let return_type = func.return_type.clone();
imported_types.extend(types);
let mut param_tys = Vec::new();
for (param_name, param_ty) in &func.parameters {
let types = import_type(&param_ty, false);
imported_types.extend(types);
param_tys.push((param_name.clone(), param_ty.clone()));
}
importer_module.associated_functions.push((
ty.clone(),
FunctionDefinition {
name: func_name.clone(),
linkage_name: Some(format!("{}::{}", ty, func_name)),
is_pub: false,
is_imported: false,
return_type,
parameters: param_tys,
kind: super::FunctionDefinitionKind::Extern(true),
},
));
}
} else { } else {
state.ok::<_, Infallible>( state.ok::<_, Infallible>(
Err(ErrorKind::ImportDoesNotExist(module_name.clone(), import_name.clone())), Err(ErrorKind::ImportDoesNotExist(module_name.clone(), import_name.clone())),
@ -401,13 +462,12 @@ impl<'map> Pass for LinkerPass<'map> {
} }
super::ExprKind::BinOp(.., type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id), super::ExprKind::BinOp(.., type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id),
super::ExprKind::Borrow(var_ref, _) => { super::ExprKind::Borrow(..) => {}
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id); super::ExprKind::Deref(..) => {}
}
super::ExprKind::Deref(var_ref) => {
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
}
super::ExprKind::CastTo(_, type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id), super::ExprKind::CastTo(_, type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id),
super::ExprKind::AssociatedFunctionCall(type_kind, _) => {
*type_kind = type_kind.update_imported(extern_types, mod_id)
}
_ => {} _ => {}
} }
} }

View File

@ -248,7 +248,7 @@ pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Import(pub Vec<String>, pub Metadata); pub struct Import(pub Vec<String>, pub Metadata);
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum ExprKind { pub enum ExprKind {
Variable(NamedVariableRef), Variable(NamedVariableRef),
Indexed(Box<Expression>, TypeKind, Box<Expression>), Indexed(Box<Expression>, TypeKind, Box<Expression>),
@ -261,19 +261,19 @@ pub enum ExprKind {
AssociatedFunctionCall(TypeKind, FunctionCall), AssociatedFunctionCall(TypeKind, FunctionCall),
If(IfExpression), If(IfExpression),
Block(Block), Block(Block),
Borrow(NamedVariableRef, bool), Borrow(Box<Expression>, bool),
Deref(NamedVariableRef), Deref(Box<Expression>),
CastTo(Box<Expression>, TypeKind), CastTo(Box<Expression>, TypeKind),
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Expression(pub ExprKind, pub Metadata); pub struct Expression(pub ExprKind, pub Metadata);
/// Condition, Then, Else /// Condition, Then, Else
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct IfExpression(pub Box<Expression>, pub Box<Expression>, pub Box<Option<Expression>>); pub struct IfExpression(pub Box<Expression>, pub Box<Expression>, pub Box<Option<Expression>>);
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct FunctionCall { pub struct FunctionCall {
pub name: String, pub name: String,
pub return_type: TypeKind, pub return_type: TypeKind,
@ -284,6 +284,7 @@ pub struct FunctionCall {
#[derive(Debug)] #[derive(Debug)]
pub struct FunctionDefinition { pub struct FunctionDefinition {
pub name: String, pub name: String,
pub linkage_name: Option<String>,
/// Whether this function is visible to outside modules /// Whether this function is visible to outside modules
pub is_pub: bool, pub is_pub: bool,
/// Whether this module is from an external module, and has been imported /// Whether this module is from an external module, and has been imported
@ -327,7 +328,7 @@ impl FunctionDefinition {
} }
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Block { pub struct Block {
/// List of non-returning statements /// List of non-returning statements
pub statements: Vec<Statement>, pub statements: Vec<Statement>,
@ -335,10 +336,10 @@ pub struct Block {
pub meta: Metadata, pub meta: Metadata,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Statement(pub StmtKind, pub Metadata); pub struct Statement(pub StmtKind, pub Metadata);
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum StmtKind { pub enum StmtKind {
/// Variable name++mutability+type, evaluation /// Variable name++mutability+type, evaluation
Let(NamedVariableRef, bool, Expression), Let(NamedVariableRef, bool, Expression),
@ -348,7 +349,7 @@ pub enum StmtKind {
While(WhileStatement), While(WhileStatement),
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct WhileStatement { pub struct WhileStatement {
pub condition: Expression, pub condition: Expression,
pub block: Block, pub block: Block,

View File

@ -171,18 +171,27 @@ impl<Data: Clone + Default> Scope<Data> {
} }
pub fn get_associated_function(&mut self, key: &AssociatedFunctionKey) -> Option<ScopeFunction> { pub fn get_associated_function(&mut self, key: &AssociatedFunctionKey) -> Option<ScopeFunction> {
let func = self.associated_functions.get(key); let ty = if let TypeKind::Borrow(inner, _) = &key.0 {
*inner.clone()
} else {
key.0.clone()
};
let key = AssociatedFunctionKey(ty, key.1.clone());
let func = self.associated_functions.get(&key);
if let Some(func) = func { if let Some(func) = func {
Some(func.clone()) Some(func.clone())
} else if let Some(func) = get_intrinsic_assoc_func(&key.0, &key.1) { } else if let Some(func) = get_intrinsic_assoc_func(&key.0, &key.1) {
self.associated_functions.set( self.associated_functions
key.clone(), .set(
ScopeFunction { key.clone(),
ret: func.return_type, ScopeFunction {
params: func.parameters.iter().map(|(_, p)| p.clone()).collect(), ret: func.return_type,
}, params: func.parameters.iter().map(|(_, p)| p.clone()).collect(),
); },
self.associated_functions.get(key).cloned() )
.unwrap();
self.associated_functions.get(&key).cloned()
} else { } else {
None None
} }
@ -510,7 +519,8 @@ impl Statement {
StmtKind::Let(_, _, expression) => { StmtKind::Let(_, _, expression) => {
expression.pass(pass, state, scope, mod_id)?; expression.pass(pass, state, scope, mod_id)?;
} }
StmtKind::Set(_, expression) => { StmtKind::Set(set_expr, expression) => {
set_expr.pass(pass, state, scope, mod_id)?;
expression.pass(pass, state, scope, mod_id)?; expression.pass(pass, state, scope, mod_id)?;
} }
StmtKind::Import(_) => {} StmtKind::Import(_) => {}
@ -556,6 +566,52 @@ impl Expression {
mod_id: SourceModuleId, mod_id: SourceModuleId,
) -> PassResult { ) -> PassResult {
pass.expr(self, PassState::from(state, scope, Some(mod_id)))?; pass.expr(self, PassState::from(state, scope, Some(mod_id)))?;
match &mut self.0 {
ExprKind::Variable(_) => {}
ExprKind::Indexed(value_expr, _, index_expr) => {
pass.expr(value_expr.as_mut(), PassState::from(state, scope, Some(mod_id)))?;
pass.expr(index_expr.as_mut(), PassState::from(state, scope, Some(mod_id)))?;
}
ExprKind::Accessed(value_expr, ..) => {
pass.expr(value_expr.as_mut(), PassState::from(state, scope, Some(mod_id)))?;
}
ExprKind::Array(expressions) => {
for expr in expressions {
pass.expr(expr, PassState::from(state, scope, Some(mod_id)))?;
}
}
ExprKind::Struct(_, items) => {
for (_, expr) in items {
pass.expr(expr, PassState::from(state, scope, Some(mod_id)))?;
}
}
ExprKind::Literal(_) => {}
ExprKind::BinOp(_, lhs, rhs, _) => {
pass.expr(lhs.as_mut(), PassState::from(state, scope, Some(mod_id)))?;
pass.expr(rhs.as_mut(), PassState::from(state, scope, Some(mod_id)))?;
}
ExprKind::FunctionCall(FunctionCall { parameters, .. }) => {
for expr in parameters {
pass.expr(expr, PassState::from(state, scope, Some(mod_id)))?;
}
}
ExprKind::AssociatedFunctionCall(_, FunctionCall { parameters, .. }) => {
for expr in parameters {
pass.expr(expr, PassState::from(state, scope, Some(mod_id)))?;
}
}
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
pass.expr(cond.as_mut(), PassState::from(state, scope, Some(mod_id)))?;
pass.expr(lhs.as_mut(), PassState::from(state, scope, Some(mod_id)))?;
if let Some(rhs) = rhs.as_mut() {
pass.expr(rhs, PassState::from(state, scope, Some(mod_id)))?;
}
}
ExprKind::Block(block) => pass.block(block, PassState::from(state, scope, Some(mod_id)))?,
ExprKind::Borrow(expression, _) => pass.expr(expression, PassState::from(state, scope, Some(mod_id)))?,
ExprKind::Deref(expression) => pass.expr(expression, PassState::from(state, scope, Some(mod_id)))?,
ExprKind::CastTo(expression, _) => pass.expr(expression, PassState::from(state, scope, Some(mod_id)))?,
}
Ok(()) Ok(())
} }
} }

View File

@ -65,7 +65,9 @@ pub enum ErrorKind {
#[error("This type of expression can not be used for assignment")] #[error("This type of expression can not be used for assignment")]
InvalidSetExpression, InvalidSetExpression,
#[error("Can not deref {0}, as it is not a borrow")] #[error("Can not deref {0}, as it is not a borrow")]
AttemptedDerefNonBorrow(String), AttemptedDerefNonBorrow(TypeKind),
#[error("Can not borrow this kind of expression")]
ImpossibleBorrow,
#[error("Types {0} and {1} differ in mutability")] #[error("Types {0} and {1} differ in mutability")]
TypesDifferMutability(TypeKind, TypeKind), TypesDifferMutability(TypeKind, TypeKind),
#[error("Cannot mutably borrow variable {0}, which is not declared as mutable")] #[error("Cannot mutably borrow variable {0}, which is not declared as mutable")]
@ -152,7 +154,7 @@ impl TypeKind {
(TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => { (TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => {
// Extracted to give priority for other collapse-error // Extracted to give priority for other collapse-error
let collapsed = val1.narrow_into(val2)?; let collapsed = val1.narrow_into(val2)?;
if mut1 == mut2 { if mut1 == mut2 || (*mut1 && !mut2) {
Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2)) Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2))
} else { } else {
Err(ErrorKind::TypesDifferMutability(self.clone(), other.clone())) Err(ErrorKind::TypesDifferMutability(self.clone(), other.clone()))

View File

@ -1,6 +1,6 @@
//! This module contains code relevant to doing a type checking pass on the MIR. //! This module contains code relevant to doing a type checking pass on the MIR.
//! During typechecking relevant types are also coerced if possible. //! During typechecking relevant types are also coerced if possible.
use std::{collections::HashSet, convert::Infallible, iter}; use std::{collections::HashSet, convert::Infallible, hint, iter};
use crate::{mir::*, util::try_all}; use crate::{mir::*, util::try_all};
use VagueType as Vague; use VagueType as Vague;
@ -668,60 +668,49 @@ impl Expression {
Ok(TypeKind::CustomType(type_key)) Ok(TypeKind::CustomType(type_key))
} }
ExprKind::Borrow(var_ref, mutable) => { ExprKind::Borrow(expr, mutable) => {
let scope_var = state.scope.variables.get(&var_ref.1).cloned(); let hint_t = if let HintKind::Coerce(hint_t) = hint_t {
if let TypeKind::Borrow(inner, _) = hint_t {
let existing = state HintKind::Coerce(*inner)
.or_else( } else {
scope_var return Err(ErrorKind::TypesIncompatible(
.clone() hint_t,
.map(|var| var.ty) TypeKind::Borrow(Box::new(TypeKind::Vague(VagueType::Unknown)), *mutable),
.ok_or(ErrorKind::VariableNotDefined(var_ref.1.clone())), ));
TypeKind::Vague(Vague::Unknown),
var_ref.2,
)
.resolve_ref(typerefs);
if let Some(scope_var) = scope_var {
if !scope_var.mutable && *mutable {
return Err(ErrorKind::ImpossibleMutableBorrow(var_ref.1.clone()));
} }
} } else {
hint_t
// Update typing to be more accurate
var_ref.0 = state.or_else(
var_ref.0.resolve_ref(typerefs).narrow_into(&existing),
TypeKind::Vague(Vague::Unknown),
var_ref.2,
);
Ok(TypeKind::Borrow(Box::new(var_ref.0.clone()), *mutable))
}
ExprKind::Deref(var_ref) => {
let existing = state
.or_else(
state
.scope
.variables
.get(&var_ref.1)
.map(|var| &var.ty)
.cloned()
.ok_or(ErrorKind::VariableNotDefined(var_ref.1.clone())),
TypeKind::Vague(Vague::Unknown),
var_ref.2,
)
.resolve_ref(typerefs);
// Update typing to be more accurate
let TypeKind::Borrow(inner, mutable) = state.or_else(
var_ref.0.resolve_ref(typerefs).narrow_into(&existing),
TypeKind::Vague(Vague::Unknown),
var_ref.2,
) else {
return Err(ErrorKind::AttemptedDerefNonBorrow(var_ref.1.clone()));
}; };
var_ref.0 = TypeKind::Borrow(inner.clone(), mutable); let expr_ty = expr.typecheck(state, typerefs, hint_t)?.resolve_ref(typerefs);
if let Some(backing_var) = expr.backing_var() {
if let Some(scope_var) = state.scope.variables.get(&backing_var.1) {
if !scope_var.mutable && *mutable {
return Err(ErrorKind::ImpossibleMutableBorrow(backing_var.1.clone()));
}
} else {
return Err(ErrorKind::VariableNotDefined(backing_var.1.clone()));
}
} else {
return Err(ErrorKind::ImpossibleBorrow);
}
Ok(TypeKind::Borrow(Box::new(expr_ty.clone()), *mutable))
}
ExprKind::Deref(expr) => {
let hint_t = if let HintKind::Coerce(hint_t) = hint_t {
HintKind::Coerce(TypeKind::Borrow(Box::new(hint_t), false))
} else {
hint_t
};
let expr_ty = expr.typecheck(state, typerefs, hint_t)?.resolve_ref(typerefs);
// Update typing to be more accurate
let TypeKind::Borrow(inner, _) = expr_ty else {
return Err(ErrorKind::AttemptedDerefNonBorrow(expr_ty.clone()));
};
Ok(*inner) Ok(*inner)
} }
@ -760,7 +749,9 @@ impl Expression {
.into_iter() .into_iter()
.chain(iter::repeat(TypeKind::Vague(Vague::Unknown))); .chain(iter::repeat(TypeKind::Vague(Vague::Unknown)));
for (param, true_param_t) in function_call.parameters.iter_mut().zip(true_params_iter) { for (i, (param, true_param_t)) in
function_call.parameters.iter_mut().zip(true_params_iter).enumerate()
{
// Typecheck every param separately // Typecheck every param separately
let param_res = param.typecheck(state, &typerefs, HintKind::Coerce(true_param_t.clone())); let param_res = param.typecheck(state, &typerefs, HintKind::Coerce(true_param_t.clone()));
let param_t = state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1); let param_t = state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1);

View File

@ -12,8 +12,9 @@ use std::{
use crate::{ use crate::{
mir::{ mir::{
pass::AssociatedFunctionKey, BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, pass::{AssociatedFunctionKey, ScopeVariable},
FunctionDefinitionKind, IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement, BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
}, },
util::try_all, util::try_all,
}; };
@ -249,6 +250,18 @@ impl Block {
var.0 = var_ref.as_type(); var.0 = var_ref.as_type();
} }
state
.scope
.variables
.set(
var.1.clone(),
ScopeVariable {
ty: var.0.clone(),
mutable: *mutable,
},
)
.ok();
// Infer hints for the expression itself // Infer hints for the expression itself
let inferred = expr.infer_types(&mut state, &inner_refs); let inferred = expr.infer_types(&mut state, &inner_refs);
let mut expr_ty_ref = state.ok(inferred, expr.1); let mut expr_ty_ref = state.ok(inferred, expr.1);
@ -557,37 +570,23 @@ impl Expression {
} }
Ok(type_refs.from_type(&TypeKind::CustomType(type_key.clone())).unwrap()) Ok(type_refs.from_type(&TypeKind::CustomType(type_key.clone())).unwrap())
} }
ExprKind::Borrow(var, mutable) => { ExprKind::Borrow(expr, mutable) => {
// Find variable type // Find variable type
let type_ref = type_refs let type_ref = expr.infer_types(state, type_refs)?;
.find_var(&var.1)
.map(|(_, hint)| hint)
.ok_or(ErrorKind::VariableNotDefined(var.1.clone()));
// Update MIR type to TypeRef if found
if let Ok(hint) = &type_ref {
var.0 = hint.as_type();
}
Ok(type_refs Ok(type_refs
.from_type(&TypeKind::Borrow(Box::new(var.0.clone()), *mutable)) .from_type(&TypeKind::Borrow(Box::new(type_ref.as_type()), *mutable))
.unwrap()) .unwrap())
} }
ExprKind::Deref(var) => { ExprKind::Deref(expr) => {
// Find variable type // Find variable type
let type_ref = type_refs let type_ref = expr.infer_types(state, type_refs)?;
.find_var(&var.1)
.map(|(_, hint)| hint)
.ok_or(ErrorKind::VariableNotDefined(var.1.clone()));
// Update MIR type to TypeRef if found // Update typing to be more accurate
if let Ok(hint) = &type_ref {
var.0 = hint.as_type();
}
match &var.0.resolve_weak(type_refs.types) { match type_ref.resolve_weak().unwrap() {
Borrow(type_kind, _) => Ok(type_refs.from_type(&type_kind).unwrap()), Borrow(inner, _) => Ok(type_refs.from_type(&inner).unwrap()),
_ => Err(ErrorKind::AttemptedDerefNonBorrow(var.1.clone())), _ => Err(ErrorKind::AttemptedDerefNonBorrow(type_ref.resolve_deep().unwrap())),
} }
} }
ExprKind::CastTo(expression, type_kind) => { ExprKind::CastTo(expression, type_kind) => {
@ -595,17 +594,42 @@ impl Expression {
Ok(type_refs.from_type(type_kind).unwrap()) Ok(type_refs.from_type(type_kind).unwrap())
} }
ExprKind::AssociatedFunctionCall(type_kind, function_call) => { ExprKind::AssociatedFunctionCall(type_kind, function_call) => {
if type_kind.is_known(state).is_err() { match type_kind.is_known(state) {
let first_param = function_call Ok(_) => {}
.parameters Err(ErrorKind::NoSuchType(name, mod_id)) => return Err(ErrorKind::NoSuchType(name, mod_id)),
.get_mut(0) Err(_) => {
.expect("Unknown-type associated function NEEDS to always have at least one parameter!"); let first_param = function_call
let param_ty = first_param.infer_types(state, type_refs).unwrap().resolve_deep(); .parameters
*type_kind = state.or_else( .get_mut(0)
param_ty.ok_or(ErrorKind::CouldNotInferType(format!("{}", first_param))), .expect("Unknown-type associated function NEEDS to always have at least one parameter!");
Void, let param_ty = first_param.infer_types(state, type_refs).unwrap().resolve_deep();
first_param.1, *type_kind = state
); .or_else(
param_ty.ok_or(ErrorKind::CouldNotInferType(format!("{}", first_param))),
Void,
first_param.1,
)
.unroll_borrows()
.resolve_ref(type_refs.types);
let backing_var = first_param.backing_var().expect("todo").1.clone();
*first_param = if backing_var == "self" {
let ExprKind::Borrow(val, _) = &first_param.0 else {
panic!()
};
*val.clone()
} else {
first_param.clone()
};
if let Some((mutable, _)) = type_refs.find_var(&backing_var) {
if !mutable {
first_param.remove_borrow_mutability();
}
} else {
return Err(ErrorKind::VariableNotDefined(backing_var));
}
}
} }
// Get function definition and types // Get function definition and types
@ -635,4 +659,21 @@ impl Expression {
} }
} }
} }
fn remove_borrow_mutability(&mut self) {
match &mut self.0 {
ExprKind::Variable(_) => {}
ExprKind::Indexed(value_expr, ..) => value_expr.remove_borrow_mutability(),
ExprKind::Accessed(value_expr, ..) => value_expr.remove_borrow_mutability(),
ExprKind::Block(block) => {
if let Some((_, Some(ret_expr))) = &mut block.return_expression {
ret_expr.remove_borrow_mutability();
}
}
ExprKind::Borrow(_, mutable) => {
*mutable = false;
}
_ => {}
}
}
} }

View File

@ -27,6 +27,10 @@ impl<'scope> TypeRef<'scope> {
let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_weak()?; let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_weak()?;
Some(TypeKind::Array(Box::new(resolved_elem_ty), len)) Some(TypeKind::Array(Box::new(resolved_elem_ty), len))
} }
TypeKind::Borrow(inner_ty, mutable) => {
let resolved_elem_ty = self.1.from_type(&inner_ty).unwrap().resolve_weak()?;
Some(TypeKind::Borrow(Box::new(resolved_elem_ty), mutable))
}
_ => Some(resolved), _ => Some(resolved),
} }
} }