Compare commits
11 Commits
1c83ca44ab
...
4844cebd56
Author | SHA1 | Date | |
---|---|---|---|
4844cebd56 | |||
195d3d3af8 | |||
00c91fff60 | |||
8838223a7d | |||
1f56fa5dc3 | |||
dc360ef196 | |||
5104555890 | |||
9d5a20e76a | |||
a6a903a45d | |||
676554b6a0 | |||
cc367a38e7 |
@ -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
|
||||
by simplicity.
|
||||
|
||||
Specifications and documentation for the language can be found
|
||||
[here](./documentation/).
|
||||
Specifications and a bunch of [documentation for the language can be found
|
||||
here](./documentation/).
|
||||
|
||||
Reid is currently able to (non-exhaustively):
|
||||
- Do basic algebra binary and unary-operations (e.g. Add, Sub, Div, Mult, And,
|
||||
|
@ -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
|
||||
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 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
|
||||
- **Associated function calls**, to invoke a predefined function on a certain
|
||||
*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
|
||||
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
|
||||
@ -263,7 +271,7 @@ In formal grammar:
|
||||
<array> | <struct> |
|
||||
<indexing> | <accessing> |
|
||||
<binary-exp> | <unary-exp> |
|
||||
<function-call> | <assoc-function-call>
|
||||
<function-call> | <accessing-function-call> | <assoc-function-call>
|
||||
<block> | <if-expr> | <cast> |
|
||||
( "(" <expression> ")" )
|
||||
|
||||
@ -278,6 +286,7 @@ In formal grammar:
|
||||
<binary-exp> :: <expression> <binop> <expression>
|
||||
<unary-exp> :: <unary> <expression>
|
||||
<function-call> :: <expression> "(" [ <expression> ( "," <expression> )* ] ")"
|
||||
<accessing-function-call> :: <accessing> "(" [ <expression> ( "," <expression> )* ] ")"
|
||||
<assoc-function-call> :: <type> "::" <function-call>
|
||||
<if-expr> :: "if" <expression> <expression> [ "else" <expression> ]
|
||||
<cast> :: <expression> "as" <type>
|
||||
@ -296,6 +305,7 @@ test.first // Accessing
|
||||
!bool_value // Unary
|
||||
func(value, 14) // 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
|
||||
value as u32 // cast
|
||||
(value + 2) // Binop within parenthesis
|
||||
|
@ -22,6 +22,7 @@ or simply casting the value (e.g. `5 as u32`).
|
||||
## Table of Contents:
|
||||
- [Hello World](#hello-world)
|
||||
- [Borrowing and Pointers](#borrowing-and-pointers)
|
||||
- [Harder Hello World](#harder-hello-world)
|
||||
|
||||
### Hello World
|
||||
|
||||
@ -120,3 +121,73 @@ 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,
|
||||
this example would not work without the `mut`-keyword. Try it out for yourself
|
||||
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!
|
28
documentation/intrinsics.md
Normal file
28
documentation/intrinsics.md
Normal 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
|
||||
```
|
@ -10,30 +10,58 @@ Has the following binops defined:
|
||||
- `String` + `*char` = `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`
|
||||
|
||||
Returns a new empty `String`-object, which must later be manually freed.
|
||||
|
||||
_deprecated: Use `String::new()`_
|
||||
|
||||
#### `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.
|
||||
|
||||
_deprecated: Use `String::from()`_
|
||||
|
||||
#### `pub fn set_char(string: &mut String, c: char, position: u64)`
|
||||
|
||||
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)`
|
||||
|
||||
Formats the given number into the end of the string.
|
||||
|
||||
_deprecated: Use `String::push_num()`_
|
||||
|
||||
#### `pub fn concat_strings(destination: &mut String, source: String)`
|
||||
|
||||
Concatenates `source` to the end of `destination`.
|
||||
|
||||
_deprecated: Use `String::concat()`_
|
||||
|
||||
## General
|
||||
|
||||
#### `pub fn allocate(size: u64) -> *u8`
|
||||
|
@ -7,8 +7,8 @@ struct Otus {
|
||||
}
|
||||
|
||||
impl Otus {
|
||||
fn test(self) -> u32 {
|
||||
self.field
|
||||
fn test(&self) -> u32 {
|
||||
*self.field
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,16 @@
|
||||
import std::print;
|
||||
import std::from_str;
|
||||
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;
|
||||
import std::String;
|
||||
|
||||
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, '!');
|
||||
add_char(&mut test, '\n');
|
||||
|
||||
add_num_to_str(&mut test, 175);
|
||||
test.push_num(175);
|
||||
|
||||
print(test);
|
||||
|
||||
free_string(&test);
|
||||
test.free();
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -11,6 +11,88 @@ struct String {
|
||||
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 {
|
||||
let mut new = lhs;
|
||||
let added = from_str(rhs);
|
||||
|
@ -80,8 +80,8 @@ pub struct Expression(pub ExpressionKind, pub TokenRange);
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExpressionKind {
|
||||
VariableName(String),
|
||||
Borrow(String, bool),
|
||||
Deref(String),
|
||||
Borrow(Box<Expression>, bool),
|
||||
Deref(Box<Expression>),
|
||||
Literal(Literal),
|
||||
Array(Vec<Expression>),
|
||||
ArrayShort(Box<Expression>, u64),
|
||||
|
@ -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)]
|
||||
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()) {
|
||||
stream.next(); // Consume Et
|
||||
stream.next(); // Consume mut
|
||||
let Some(Token::Identifier(name)) = stream.next() else {
|
||||
return Err(stream.expected_err("identifier")?);
|
||||
};
|
||||
Expression(Kind::Borrow(name, true), stream.get_range().unwrap())
|
||||
} else if let (Some(Token::Et), Some(Token::Identifier(name))) = (stream.peek(), stream.peek2()) {
|
||||
Expression(
|
||||
Kind::Borrow(Box::new(stream.parse()?), true),
|
||||
stream.get_range().unwrap(),
|
||||
)
|
||||
} else if let Some(Token::Et) = stream.peek() {
|
||||
stream.next(); // Consume Et
|
||||
stream.next(); // Consume identifier
|
||||
Expression(Kind::Borrow(name, false), stream.get_range().unwrap())
|
||||
} else if let (Some(Token::Star), Some(Token::Identifier(name))) = (stream.peek(), stream.peek2()) {
|
||||
Expression(
|
||||
Kind::Borrow(Box::new(stream.parse()?), false),
|
||||
stream.get_range().unwrap(),
|
||||
)
|
||||
} else if let Some(Token::Star) = stream.peek() {
|
||||
stream.next(); // Consume Et
|
||||
stream.next(); // Consume identifier
|
||||
Expression(Kind::Deref(name), stream.get_range().unwrap())
|
||||
apply_inner(stream.parse()?, |e| {
|
||||
Expression(Kind::Deref(Box::new(e.0)), stream.get_range().unwrap())
|
||||
})
|
||||
} else if let Ok(unary) = stream.parse() {
|
||||
Expression(
|
||||
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);
|
||||
|
||||
if let Ok(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));
|
||||
match &self_kind {
|
||||
SelfKind::None => {
|
||||
if let Ok(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));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
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>()?;
|
||||
stream.expect(Token::BraceOpen)?;
|
||||
let mut functions = Vec::new();
|
||||
while let Some(Token::FnKeyword) = stream.peek() {
|
||||
let mut fun: FunctionDefinition = stream.parse()?;
|
||||
fun.0.self_kind = match fun.0.self_kind {
|
||||
SelfKind::Owned(_) => SelfKind::Owned(ty.0.clone()),
|
||||
SelfKind::Borrow(_) => SelfKind::Borrow(ty.0.clone()),
|
||||
SelfKind::MutBorrow(_) => SelfKind::MutBorrow(ty.0.clone()),
|
||||
SelfKind::None => SelfKind::None,
|
||||
};
|
||||
functions.push(fun);
|
||||
loop {
|
||||
match stream.peek() {
|
||||
Some(Token::FnKeyword) | Some(Token::PubKeyword) => {
|
||||
let mut fun: FunctionDefinition = stream.parse()?;
|
||||
fun.0.self_kind = match fun.0.self_kind {
|
||||
SelfKind::Owned(_) => SelfKind::Owned(ty.0.clone()),
|
||||
SelfKind::Borrow(_) => SelfKind::Borrow(ty.0.clone()),
|
||||
SelfKind::MutBorrow(_) => SelfKind::MutBorrow(ty.0.clone()),
|
||||
SelfKind::None => SelfKind::None,
|
||||
};
|
||||
functions.push(fun);
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
stream.expect(Token::BraceClose)?;
|
||||
|
@ -36,6 +36,7 @@ impl ast::Module {
|
||||
ExternFunction(signature) => {
|
||||
let def = mir::FunctionDefinition {
|
||||
name: signature.name.clone(),
|
||||
linkage_name: None,
|
||||
is_pub: false,
|
||||
is_imported: false,
|
||||
return_type: signature
|
||||
@ -149,6 +150,7 @@ impl ast::FunctionDefinition {
|
||||
);
|
||||
mir::FunctionDefinition {
|
||||
name: signature.name.clone(),
|
||||
linkage_name: None,
|
||||
is_pub: *is_pub,
|
||||
is_imported: false,
|
||||
return_type: signature
|
||||
@ -361,19 +363,10 @@ impl ast::Expression {
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
name.clone(),
|
||||
),
|
||||
ast::ExpressionKind::Borrow(name, mutable) => mir::ExprKind::Borrow(
|
||||
NamedVariableRef(
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
name.clone(),
|
||||
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::Borrow(expr, mutable) => {
|
||||
mir::ExprKind::Borrow(Box::new(expr.process(module_id)), *mutable)
|
||||
}
|
||||
ast::ExpressionKind::Deref(expr) => mir::ExprKind::Deref(Box::new(expr.process(module_id))),
|
||||
ast::ExpressionKind::UnaryOperation(unary_operator, expr) => match unary_operator {
|
||||
ast::UnaryOperator::Plus => mir::ExprKind::BinOp(
|
||||
mir::BinaryOperator::Add,
|
||||
@ -424,7 +417,13 @@ impl ast::Expression {
|
||||
),
|
||||
ast::ExpressionKind::AccessCall(expression, fn_call_expr) => {
|
||||
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::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
mir::FunctionCall {
|
||||
|
@ -40,6 +40,7 @@ pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDef
|
||||
match name {
|
||||
"sizeof" => Some(FunctionDefinition {
|
||||
name: "sizeof".to_owned(),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
is_imported: false,
|
||||
return_type: TypeKind::U64,
|
||||
@ -48,6 +49,7 @@ pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDef
|
||||
}),
|
||||
"alloca" => Some(FunctionDefinition {
|
||||
name: "alloca".to_owned(),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
is_imported: false,
|
||||
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 {
|
||||
name: "null".to_owned(),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
is_imported: false,
|
||||
return_type: TypeKind::UserPtr(Box::new(ty.clone())),
|
||||
|
@ -187,7 +187,7 @@ impl mir::Module {
|
||||
let is_main = self.is_main && function.name == "main";
|
||||
let func = match &function.kind {
|
||||
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
|
||||
&function.name,
|
||||
&function.linkage_name.clone().unwrap_or(function.name.clone()),
|
||||
function.return_type.get_type(&type_values),
|
||||
param_types,
|
||||
FunctionFlags {
|
||||
@ -198,7 +198,7 @@ impl mir::Module {
|
||||
},
|
||||
)),
|
||||
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),
|
||||
param_types,
|
||||
FunctionFlags {
|
||||
@ -238,7 +238,7 @@ impl mir::Module {
|
||||
},
|
||||
)),
|
||||
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),
|
||||
param_types,
|
||||
FunctionFlags {
|
||||
@ -1144,12 +1144,8 @@ impl mir::Expression {
|
||||
TypeKind::CustomType(type_key),
|
||||
))
|
||||
}
|
||||
mir::ExprKind::Borrow(varref, mutable) => {
|
||||
varref.0.known().expect("variable type unknown");
|
||||
let v = scope
|
||||
.stack_values
|
||||
.get(&varref.1)
|
||||
.expect("Variable reference not found?!");
|
||||
mir::ExprKind::Borrow(expr, mutable) => {
|
||||
let v = expr.codegen(scope, &state.load(false))?.unwrap();
|
||||
|
||||
let TypeKind::CodegenPtr(ptr_inner) = &v.1 else {
|
||||
panic!();
|
||||
@ -1160,12 +1156,8 @@ impl mir::Expression {
|
||||
TypeKind::Borrow(Box::new(*ptr_inner.clone()), *mutable),
|
||||
))
|
||||
}
|
||||
mir::ExprKind::Deref(varref) => {
|
||||
varref.0.known().expect("variable type unknown");
|
||||
let v = scope
|
||||
.stack_values
|
||||
.get(&varref.1)
|
||||
.expect("Variable reference not found?!");
|
||||
mir::ExprKind::Deref(expr) => {
|
||||
let v = expr.codegen(scope, &state.load(false))?.unwrap();
|
||||
|
||||
let TypeKind::CodegenPtr(ptr_inner) = &v.1 else {
|
||||
panic!();
|
||||
@ -1174,7 +1166,7 @@ impl mir::Expression {
|
||||
let var_ptr_instr = scope
|
||||
.block
|
||||
.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)),
|
||||
)
|
||||
.unwrap();
|
||||
@ -1187,7 +1179,7 @@ impl mir::Expression {
|
||||
scope
|
||||
.block
|
||||
.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)),
|
||||
)
|
||||
.unwrap(),
|
||||
@ -1300,6 +1292,9 @@ fn codegen_function_call<'ctx, 'a>(
|
||||
};
|
||||
|
||||
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 intrinsic_def = get_intrinsic_assoc_func(&ty, &call.name);
|
||||
let intrinsic = intrinsic_def.map(|func_def| {
|
||||
|
@ -208,6 +208,19 @@ impl TypeKind {
|
||||
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 {
|
||||
@ -425,15 +438,15 @@ impl Expression {
|
||||
ReturnKind::Soft,
|
||||
TypeKind::CustomType(CustomTypeKey(name.clone(), mod_id)),
|
||||
)),
|
||||
Borrow(var, mutable) => {
|
||||
let ret_type = var.return_type()?;
|
||||
Borrow(expr, mutable) => {
|
||||
let ret_type = expr.return_type(refs, mod_id)?;
|
||||
Ok((ret_type.0, TypeKind::Borrow(Box::new(ret_type.1), *mutable)))
|
||||
}
|
||||
Deref(var) => {
|
||||
let (kind, ret_type) = var.return_type()?;
|
||||
Deref(expr) => {
|
||||
let (kind, ret_type) = expr.return_type(refs, mod_id)?;
|
||||
match ret_type.resolve_weak(refs) {
|
||||
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) {
|
||||
@ -452,8 +465,8 @@ impl Expression {
|
||||
ExprKind::Variable(var_ref) => Some(var_ref),
|
||||
ExprKind::Indexed(lhs, _, _) => lhs.backing_var(),
|
||||
ExprKind::Accessed(lhs, _, _) => lhs.backing_var(),
|
||||
ExprKind::Borrow(var, _) => Some(var),
|
||||
ExprKind::Deref(var) => Some(var),
|
||||
ExprKind::Borrow(expr, _) => expr.backing_var(),
|
||||
ExprKind::Deref(expr) => expr.backing_var(),
|
||||
ExprKind::Block(block) => block.backing_var(),
|
||||
ExprKind::Array(_) => None,
|
||||
ExprKind::Struct(_, _) => None,
|
||||
|
@ -227,7 +227,8 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
}
|
||||
|
||||
importer_module.functions.push(FunctionDefinition {
|
||||
name: func_name,
|
||||
name: func_name.clone(),
|
||||
linkage_name: None,
|
||||
is_pub: false,
|
||||
is_imported: false,
|
||||
return_type,
|
||||
@ -268,6 +269,66 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
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(¶m_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 {
|
||||
state.ok::<_, Infallible>(
|
||||
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::Borrow(var_ref, _) => {
|
||||
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
|
||||
}
|
||||
super::ExprKind::Deref(var_ref) => {
|
||||
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
|
||||
}
|
||||
super::ExprKind::Borrow(..) => {}
|
||||
super::ExprKind::Deref(..) => {}
|
||||
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)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Import(pub Vec<String>, pub Metadata);
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExprKind {
|
||||
Variable(NamedVariableRef),
|
||||
Indexed(Box<Expression>, TypeKind, Box<Expression>),
|
||||
@ -261,19 +261,19 @@ pub enum ExprKind {
|
||||
AssociatedFunctionCall(TypeKind, FunctionCall),
|
||||
If(IfExpression),
|
||||
Block(Block),
|
||||
Borrow(NamedVariableRef, bool),
|
||||
Deref(NamedVariableRef),
|
||||
Borrow(Box<Expression>, bool),
|
||||
Deref(Box<Expression>),
|
||||
CastTo(Box<Expression>, TypeKind),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Expression(pub ExprKind, pub Metadata);
|
||||
|
||||
/// Condition, Then, Else
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IfExpression(pub Box<Expression>, pub Box<Expression>, pub Box<Option<Expression>>);
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionCall {
|
||||
pub name: String,
|
||||
pub return_type: TypeKind,
|
||||
@ -284,6 +284,7 @@ pub struct FunctionCall {
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionDefinition {
|
||||
pub name: String,
|
||||
pub linkage_name: Option<String>,
|
||||
/// Whether this function is visible to outside modules
|
||||
pub is_pub: bool,
|
||||
/// 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 {
|
||||
/// List of non-returning statements
|
||||
pub statements: Vec<Statement>,
|
||||
@ -335,10 +336,10 @@ pub struct Block {
|
||||
pub meta: Metadata,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Statement(pub StmtKind, pub Metadata);
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum StmtKind {
|
||||
/// Variable name++mutability+type, evaluation
|
||||
Let(NamedVariableRef, bool, Expression),
|
||||
@ -348,7 +349,7 @@ pub enum StmtKind {
|
||||
While(WhileStatement),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WhileStatement {
|
||||
pub condition: Expression,
|
||||
pub block: Block,
|
||||
|
@ -171,18 +171,27 @@ impl<Data: Clone + Default> Scope<Data> {
|
||||
}
|
||||
|
||||
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 {
|
||||
Some(func.clone())
|
||||
} else if let Some(func) = get_intrinsic_assoc_func(&key.0, &key.1) {
|
||||
self.associated_functions.set(
|
||||
key.clone(),
|
||||
ScopeFunction {
|
||||
ret: func.return_type,
|
||||
params: func.parameters.iter().map(|(_, p)| p.clone()).collect(),
|
||||
},
|
||||
);
|
||||
self.associated_functions.get(key).cloned()
|
||||
self.associated_functions
|
||||
.set(
|
||||
key.clone(),
|
||||
ScopeFunction {
|
||||
ret: func.return_type,
|
||||
params: func.parameters.iter().map(|(_, p)| p.clone()).collect(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
self.associated_functions.get(&key).cloned()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -510,7 +519,8 @@ impl Statement {
|
||||
StmtKind::Let(_, _, expression) => {
|
||||
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)?;
|
||||
}
|
||||
StmtKind::Import(_) => {}
|
||||
@ -556,6 +566,52 @@ impl Expression {
|
||||
mod_id: SourceModuleId,
|
||||
) -> PassResult {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,9 @@ pub enum ErrorKind {
|
||||
#[error("This type of expression can not be used for assignment")]
|
||||
InvalidSetExpression,
|
||||
#[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")]
|
||||
TypesDifferMutability(TypeKind, TypeKind),
|
||||
#[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)) => {
|
||||
// Extracted to give priority for other collapse-error
|
||||
let collapsed = val1.narrow_into(val2)?;
|
||||
if mut1 == mut2 {
|
||||
if mut1 == mut2 || (*mut1 && !mut2) {
|
||||
Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2))
|
||||
} else {
|
||||
Err(ErrorKind::TypesDifferMutability(self.clone(), other.clone()))
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! This module contains code relevant to doing a type checking pass on the MIR.
|
||||
//! 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 VagueType as Vague;
|
||||
@ -668,60 +668,49 @@ impl Expression {
|
||||
|
||||
Ok(TypeKind::CustomType(type_key))
|
||||
}
|
||||
ExprKind::Borrow(var_ref, mutable) => {
|
||||
let scope_var = state.scope.variables.get(&var_ref.1).cloned();
|
||||
|
||||
let existing = state
|
||||
.or_else(
|
||||
scope_var
|
||||
.clone()
|
||||
.map(|var| var.ty)
|
||||
.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()));
|
||||
ExprKind::Borrow(expr, mutable) => {
|
||||
let hint_t = if let HintKind::Coerce(hint_t) = hint_t {
|
||||
if let TypeKind::Borrow(inner, _) = hint_t {
|
||||
HintKind::Coerce(*inner)
|
||||
} else {
|
||||
return Err(ErrorKind::TypesIncompatible(
|
||||
hint_t,
|
||||
TypeKind::Borrow(Box::new(TypeKind::Vague(VagueType::Unknown)), *mutable),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// 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()));
|
||||
} else {
|
||||
hint_t
|
||||
};
|
||||
|
||||
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)
|
||||
}
|
||||
@ -760,7 +749,9 @@ impl Expression {
|
||||
.into_iter()
|
||||
.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
|
||||
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);
|
||||
|
@ -12,8 +12,9 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
mir::{
|
||||
pass::AssociatedFunctionKey, BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition,
|
||||
FunctionDefinitionKind, IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
|
||||
pass::{AssociatedFunctionKey, ScopeVariable},
|
||||
BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
|
||||
IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
|
||||
},
|
||||
util::try_all,
|
||||
};
|
||||
@ -249,6 +250,18 @@ impl Block {
|
||||
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
|
||||
let inferred = expr.infer_types(&mut state, &inner_refs);
|
||||
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())
|
||||
}
|
||||
ExprKind::Borrow(var, mutable) => {
|
||||
ExprKind::Borrow(expr, mutable) => {
|
||||
// Find variable type
|
||||
let type_ref = 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();
|
||||
}
|
||||
let type_ref = expr.infer_types(state, 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())
|
||||
}
|
||||
ExprKind::Deref(var) => {
|
||||
ExprKind::Deref(expr) => {
|
||||
// Find variable type
|
||||
let type_ref = type_refs
|
||||
.find_var(&var.1)
|
||||
.map(|(_, hint)| hint)
|
||||
.ok_or(ErrorKind::VariableNotDefined(var.1.clone()));
|
||||
let type_ref = expr.infer_types(state, type_refs)?;
|
||||
|
||||
// Update MIR type to TypeRef if found
|
||||
if let Ok(hint) = &type_ref {
|
||||
var.0 = hint.as_type();
|
||||
}
|
||||
// Update typing to be more accurate
|
||||
|
||||
match &var.0.resolve_weak(type_refs.types) {
|
||||
Borrow(type_kind, _) => Ok(type_refs.from_type(&type_kind).unwrap()),
|
||||
_ => Err(ErrorKind::AttemptedDerefNonBorrow(var.1.clone())),
|
||||
match type_ref.resolve_weak().unwrap() {
|
||||
Borrow(inner, _) => Ok(type_refs.from_type(&inner).unwrap()),
|
||||
_ => Err(ErrorKind::AttemptedDerefNonBorrow(type_ref.resolve_deep().unwrap())),
|
||||
}
|
||||
}
|
||||
ExprKind::CastTo(expression, type_kind) => {
|
||||
@ -595,17 +594,42 @@ impl Expression {
|
||||
Ok(type_refs.from_type(type_kind).unwrap())
|
||||
}
|
||||
ExprKind::AssociatedFunctionCall(type_kind, function_call) => {
|
||||
if type_kind.is_known(state).is_err() {
|
||||
let first_param = function_call
|
||||
.parameters
|
||||
.get_mut(0)
|
||||
.expect("Unknown-type associated function NEEDS to always have at least one parameter!");
|
||||
let param_ty = first_param.infer_types(state, type_refs).unwrap().resolve_deep();
|
||||
*type_kind = state.or_else(
|
||||
param_ty.ok_or(ErrorKind::CouldNotInferType(format!("{}", first_param))),
|
||||
Void,
|
||||
first_param.1,
|
||||
);
|
||||
match type_kind.is_known(state) {
|
||||
Ok(_) => {}
|
||||
Err(ErrorKind::NoSuchType(name, mod_id)) => return Err(ErrorKind::NoSuchType(name, mod_id)),
|
||||
Err(_) => {
|
||||
let first_param = function_call
|
||||
.parameters
|
||||
.get_mut(0)
|
||||
.expect("Unknown-type associated function NEEDS to always have at least one parameter!");
|
||||
let param_ty = first_param.infer_types(state, type_refs).unwrap().resolve_deep();
|
||||
*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
|
||||
@ -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;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,10 @@ impl<'scope> TypeRef<'scope> {
|
||||
let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_weak()?;
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user