Compare commits
No commits in common. "main" and "lexical-scopes" have entirely different histories.
main
...
lexical-sc
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
|||||||
[submodule "reid-llvm-lib"]
|
|
||||||
path = reid-llvm-lib
|
|
||||||
url = gitea@git.teascade.net:teascade/reid-llvm-lib.git
|
|
||||||
1267
Cargo.lock
generated
1267
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"reid",
|
"reid",
|
||||||
"reid-llvm-lib",
|
"reid-llvm-lib"
|
||||||
"reid-lsp"
|
|
||||||
]
|
]
|
||||||
35
README.md
35
README.md
@ -12,9 +12,6 @@ by simplicity.
|
|||||||
Specifications and a bunch of [documentation for the language can be found
|
Specifications and a bunch of [documentation for the language can be found
|
||||||
here](./documentation/).
|
here](./documentation/).
|
||||||
|
|
||||||
An example of a real whole program (a CPU pathtracer) can be found [in
|
|
||||||
examples/cpu_raytracer.reid](./examples/cpu_raytracer.reid), go have a look!
|
|
||||||
|
|
||||||
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,
|
||||||
Not)
|
Not)
|
||||||
@ -71,22 +68,17 @@ Currently missing big features (TODOs) are:
|
|||||||
Big features that I want later but are not necessary:
|
Big features that I want later but are not necessary:
|
||||||
- ~~User-defined binary operations~~ (DONE)
|
- ~~User-defined binary operations~~ (DONE)
|
||||||
- ~~Asymmetric binary operations (e.g. string + u32)~~ (DONE)
|
- ~~Asymmetric binary operations (e.g. string + u32)~~ (DONE)
|
||||||
- ~~Error handling~~ (Not Doing It)
|
- Error handling
|
||||||
- ~~Lexing & parsing of whitespace and comments as well~~ (DONE)
|
- Lexing & parsing of whitespace and comments as well
|
||||||
- ~~LSP implementation~~ (DONE)
|
- LSP implementation
|
||||||
- ~~Syntax Highlighting~~ (DONE)
|
|
||||||
- ~~Semantic Highlighting~~ (DONE)
|
|
||||||
- ~~Go-To-Definition~~ (DONE)
|
|
||||||
- ~~Find-All-References~~ (DONE)
|
|
||||||
- ~~Refactoring~~ (DONE)
|
|
||||||
|
|
||||||
Smaller features:
|
Smaller features:
|
||||||
- ~~Hex-numbers~~ (DONE)
|
- ~~Hex-numbers~~
|
||||||
- ~~Bitwise operations~~ (DONE)
|
- ~~Bitwise operations~~
|
||||||
- ~~Easier way to initialize arrays with a single value~~ (DONE)
|
- ~~Easier way to initialize arrays with a single value~~
|
||||||
- ~~Void-returns (`return;` for void-returning functions)~~ (DONE)
|
- ~~Void-returns (`return;` for void-returning functions)~~
|
||||||
- ~~Only include standard library at all if it is imported~~ (DONE)
|
- ~~Only include standard library at all if it is imported~~
|
||||||
- ~~Lexical scopes for Debug Information~~ (DONE)
|
- Lexical scopes for Debug Information
|
||||||
|
|
||||||
### Why "Reid"
|
### Why "Reid"
|
||||||
|
|
||||||
@ -162,6 +154,10 @@ cmake llvm -B build -DCMAKE_BUILD_TYPE=MinSizeRel -DLLVM_ENABLE_ASSERTIONS=ON -D
|
|||||||
ninja -j23
|
ninja -j23
|
||||||
```
|
```
|
||||||
|
|
||||||
|
*Also Note:* Building LLVM with `Ninja` was not successful for me, but this
|
||||||
|
method was. Ninja may be successful with you, to try it, add `-G Ninja` to the
|
||||||
|
`cmake`-command, and instead of `make` run `ninja install`.
|
||||||
|
|
||||||
### Building this crate itself
|
### Building this crate itself
|
||||||
|
|
||||||
Assuming `llvm-project` from the previous step was at
|
Assuming `llvm-project` from the previous step was at
|
||||||
@ -171,5 +167,6 @@ Assuming `llvm-project` from the previous step was at
|
|||||||
LLVM_SYS_201_PREFIX=/path/llvm-project/build cargo build
|
LLVM_SYS_201_PREFIX=/path/llvm-project/build cargo build
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively assuming you have LLVM 20.1 or newer installed you may use omit
|
## In conclusion
|
||||||
the environment variable entirely and use dynamic linking instead
|
Good luck! It took me a good 10 hours to figure this out for myself, I sure hope
|
||||||
|
these instructions help both myself and someone else in the future!
|
||||||
@ -27,9 +27,7 @@ in-depth, but when you're feeling up to it, you can read about them
|
|||||||
## 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
|
||||||
be found in the [examples](../examples/)-folder. A larger example of a whole
|
be found in the [examples](../examples/)-folder.
|
||||||
program written in Reid (a CPU Pathtracer) can be found [in
|
|
||||||
examples/cpu_raytracer.reid](../examples/cpu_raytracer.reid).
|
|
||||||
|
|
||||||
In Reid **modules** (or files) on the top-level are comprised of imports, type
|
In Reid **modules** (or files) on the top-level are comprised of imports, type
|
||||||
definitions, binop-definitions, functions and type-associated function blocks.
|
definitions, binop-definitions, functions and type-associated function blocks.
|
||||||
@ -83,11 +81,7 @@ Common token used throughout this document to express parts of grammar include:
|
|||||||
"i8" | "i16" | "i32" | "i64" | "i128" |
|
"i8" | "i16" | "i32" | "i64" | "i128" |
|
||||||
"f16" | "f32" | "f32b" | "f64" | "f80" | "f128" | "f128ppc"
|
"f16" | "f32" | "f32b" | "f64" | "f80" | "f128" | "f128ppc"
|
||||||
|
|
||||||
<binop> :: "+" | "-" | "*"
|
<binop> :: "+" | "-" | "*" | "/" | "%" | "&&" | <cmp>
|
||||||
| "/" | "%" | "&&" | "||"
|
|
||||||
| "&" | "|" | "^" | ">>"
|
|
||||||
| "<<" | <cmp>
|
|
||||||
|
|
||||||
<cmp> :: "<" | "<=" | "==" | "!=" | ">=" | >"
|
<cmp> :: "<" | "<=" | "==" | "!=" | ">=" | >"
|
||||||
<unary> :: "+" | "-" | "!"
|
<unary> :: "+" | "-" | "!"
|
||||||
```
|
```
|
||||||
@ -261,9 +255,6 @@ calls, literals, or if-expressions. Types of supported expressions include:
|
|||||||
*associated type* with given parameters.
|
*associated type* with given parameters.
|
||||||
- **Accessing function calls**, a shorthand to call associated function calls
|
- **Accessing function calls**, a shorthand to call associated function calls
|
||||||
which have `&self` or `&mut self` as their first parameter.
|
which have `&self` or `&mut self` as their first parameter.
|
||||||
- **Macro invocations** for invoking **macros** which are evaluated at
|
|
||||||
compile-time rather than runtime. Currently it is not possible to define
|
|
||||||
your own macros, but there are some pre-defined in the intrinsics.
|
|
||||||
- **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
|
||||||
@ -281,7 +272,7 @@ In formal grammar:
|
|||||||
<indexing> | <accessing> |
|
<indexing> | <accessing> |
|
||||||
<binary-exp> | <unary-exp> |
|
<binary-exp> | <unary-exp> |
|
||||||
<function-call> | <accessing-function-call> | <assoc-function-call>
|
<function-call> | <accessing-function-call> | <assoc-function-call>
|
||||||
<macro-invocation> | <block> | <if-expr> | <cast> |
|
<block> | <if-expr> | <cast> |
|
||||||
( "(" <expression> ")" )
|
( "(" <expression> ")" )
|
||||||
|
|
||||||
<variable> :: <ident>
|
<variable> :: <ident>
|
||||||
@ -297,7 +288,6 @@ In formal grammar:
|
|||||||
<function-call> :: <expression> "(" [ <expression> ( "," <expression> )* ] ")"
|
<function-call> :: <expression> "(" [ <expression> ( "," <expression> )* ] ")"
|
||||||
<accessing-function-call> :: <accessing> "(" [ <expression> ( "," <expression> )* ] ")"
|
<accessing-function-call> :: <accessing> "(" [ <expression> ( "," <expression> )* ] ")"
|
||||||
<assoc-function-call> :: <type> "::" <function-call>
|
<assoc-function-call> :: <type> "::" <function-call>
|
||||||
<macro-invocation> :: <expression> "!(" [ <expression> ( "," <expression> )* ] ")"
|
|
||||||
<if-expr> :: "if" <expression> <expression> [ "else" <expression> ]
|
<if-expr> :: "if" <expression> <expression> [ "else" <expression> ]
|
||||||
<cast> :: <expression> "as" <type>
|
<cast> :: <expression> "as" <type>
|
||||||
```
|
```
|
||||||
@ -316,7 +306,6 @@ test.first // Accessing
|
|||||||
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
|
test.get_field(); // Same, but using a the dot-form shorthand
|
||||||
include_bytes!("./test"); // Macro invocation
|
|
||||||
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
|
||||||
|
|||||||
@ -7,22 +7,14 @@ pre-existing binary-operators, but also some regular functions and associated
|
|||||||
functions (that every type has by-default). This document lists them all (except
|
functions (that every type has by-default). This document lists them all (except
|
||||||
for the binary operators, because there are hundreds of those).
|
for the binary operators, because there are hundreds of those).
|
||||||
|
|
||||||
### Macro Intrinsics
|
|
||||||
|
|
||||||
#### `include_bytes!(path: *char) -> &[u8; _]`
|
|
||||||
|
|
||||||
Attempts to load file from `path` (relative to module) into memory and includes
|
|
||||||
it into the compiled binary directly. Returns a borrow to an array containing
|
|
||||||
bytes from the file. Array length varies depending on the file contents.
|
|
||||||
|
|
||||||
### Associated Intrinsics
|
### Associated Intrinsics
|
||||||
|
|
||||||
#### `<T>::sizeof() -> u64`
|
#### `<T>::sizeof() -> u64`
|
||||||
|
|
||||||
Simply returns the size of type `T` in bytes.
|
Simply returns the size of type `T` in bits.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
i32::sizeof(); // Returns 4
|
i32::sizeof(); // Returns 32
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `<T>::null() -> *T`
|
#### `<T>::null() -> *T`
|
||||||
@ -33,155 +25,12 @@ Returns a null-pointer of type `T`.
|
|||||||
i32::null(); // Returns *i32 (null-ptr)
|
i32::null(); // Returns *i32 (null-ptr)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `<T>::is_null(val: T) -> bool`
|
#### `<T>::alloca(size: u64) -> *T`
|
||||||
|
|
||||||
Returns a boolean representing if `val` is a nullptr or not.
|
Allocates `T::sizeof() * size` bits and returns a pointer to `T`.
|
||||||
|
|
||||||
|
**Note:** This does not seem to work correctly currently.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
i32::is_null(i32::null()); // Returns true
|
i32::alloca(30); // Returns *i32
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `<T>::malloc(size: u64) -> *T`
|
|
||||||
|
|
||||||
Allocates `T::sizeof() * size` bytes and returns a pointer to `T`.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
i32::malloc(30); // Returns *i32
|
|
||||||
|
|
||||||
// Equivalent to
|
|
||||||
malloc(i32::sizeof() * 30) as *i32
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `<T>::memcpy(destination: *T, source: *T, size: u64)`
|
|
||||||
|
|
||||||
Copies `T::sizeof() * size` bytes from pointer `source` to pointer
|
|
||||||
`destination`.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
let a = i32::malloc(30);
|
|
||||||
let b = i32::malloc(30);
|
|
||||||
|
|
||||||
// Copies the contents from b to a
|
|
||||||
i32::memcpy(a, b, 30);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### `<T>::min(a: T, b: T) -> T`
|
|
||||||
*Note: (only on integer- and floating-point values)*
|
|
||||||
|
|
||||||
Returns the smaller of `a` and `b`.
|
|
||||||
|
|
||||||
#### `<T>::max(a: T, b: T) -> T`
|
|
||||||
*Note: (only on integer- and floating-point values)*
|
|
||||||
|
|
||||||
Returns the larger of `a` and `b`.
|
|
||||||
|
|
||||||
#### `<T>::abs(value: T) -> T`
|
|
||||||
*Note: (only on signed integer and floating-point values)*
|
|
||||||
|
|
||||||
Returns the absolute value of `value`.
|
|
||||||
|
|
||||||
#### `<T>::sqrt(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates the square-root of `value`
|
|
||||||
|
|
||||||
#### `<T>::pow(value: T, exponent: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Returns `value` raised to the exponent of `exponent`.
|
|
||||||
|
|
||||||
#### `<T>::powi(value: T, exponent: u64) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Returns `value` raised to the exponent of `exponent`.
|
|
||||||
|
|
||||||
#### `<T>::sin(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates sine of `value`
|
|
||||||
|
|
||||||
#### `<T>::cos(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates cosine of `value`
|
|
||||||
|
|
||||||
#### `<T>::tan(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates tangent of `value`
|
|
||||||
|
|
||||||
#### `<T>::asin(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates arcsine of `value`
|
|
||||||
|
|
||||||
#### `<T>::acos(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates arccosine of `value`
|
|
||||||
|
|
||||||
#### `<T>::atan(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates arctangent of `value`
|
|
||||||
|
|
||||||
#### `<T>::atan2(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates 2-argument arctangent of `value`
|
|
||||||
|
|
||||||
#### `<T>::sinh(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates hyperbolic sine of `value`
|
|
||||||
|
|
||||||
#### `<T>::cosh(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates hyperbolic cosine of `value`
|
|
||||||
|
|
||||||
#### `<T>::tanh(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Calculates hyperbolic tangent of `value`
|
|
||||||
|
|
||||||
#### `<T>::log(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Returns logₑ of `value`
|
|
||||||
|
|
||||||
#### `<T>::log2(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Returns log₂ of `value`
|
|
||||||
|
|
||||||
#### `<T>::log10(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Returns log₁₀ of `value`
|
|
||||||
|
|
||||||
#### `<T>::round(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Rounds `value` to the nearest integer
|
|
||||||
|
|
||||||
#### `<T>::trunc(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Truncates `value` to the integer nearest to `0`.
|
|
||||||
|
|
||||||
#### `<T>::ceil(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Rounds `value` towards positive infinity.
|
|
||||||
|
|
||||||
#### `<T>::floor(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Rounds `value` towards negative infinity.
|
|
||||||
|
|
||||||
#### `<T>::even(value: T) -> T`
|
|
||||||
*Note: (only on floating-point numbers)*
|
|
||||||
|
|
||||||
Rounds `value` to the closest even integer.
|
|
||||||
@ -64,6 +64,10 @@ _deprecated: Use `String::concat()`_
|
|||||||
|
|
||||||
## General
|
## General
|
||||||
|
|
||||||
|
#### `pub fn allocate(size: u64) -> *u8`
|
||||||
|
|
||||||
|
Unsafely allocates `size` bytes of memory from the stack, and returns a pointer to it, which must be manually freed.
|
||||||
|
|
||||||
## Maths
|
## Maths
|
||||||
|
|
||||||
#### `pub fn clamp(min: f32, max: f32, value: f32) -> f32`
|
#### `pub fn clamp(min: f32, max: f32, value: f32) -> f32`
|
||||||
|
|||||||
6
examples/a.reid
Normal file
6
examples/a.reid
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
pub fn main() -> u32 {
|
||||||
|
let b = 4;
|
||||||
|
let c = b + 4;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
@ -2,14 +2,11 @@ import std::print;
|
|||||||
import std::from_str;
|
import std::from_str;
|
||||||
import std::String;
|
import std::String;
|
||||||
|
|
||||||
/// Asd
|
|
||||||
struct Otus {
|
struct Otus {
|
||||||
field: u32,
|
field: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Otus {
|
impl Otus {
|
||||||
/// Some test documentation here.
|
|
||||||
/// On a second line
|
|
||||||
fn test(&self) -> u32 {
|
fn test(&self) -> u32 {
|
||||||
*self.field
|
*self.field
|
||||||
}
|
}
|
||||||
@ -21,20 +18,14 @@ impl i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hello there!
|
|
||||||
fn test() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> u32 {
|
fn main() -> u32 {
|
||||||
let otus = Otus { field: 17 };
|
let otus = Otus { field: 17 };
|
||||||
print(from_str("otus: ") + Otus::test(&otus) as u64);
|
print(from_str("otus: ") + Otus::test(&otus) as u64);
|
||||||
print(from_str("i32: ") + i32::test(54) as u64);
|
print(from_str("i32: ") + i32::test(54) as u64);
|
||||||
print(from_str("sizeof i32: ") + i32::sizeof());
|
print(from_str("sizeof i32: ") + i32::sizeof());
|
||||||
|
|
||||||
|
|
||||||
let nullptr = i32::null();
|
let nullptr = i32::null();
|
||||||
let mut list = u64::malloc(15);
|
let mut list = u64::alloca(15);
|
||||||
list[4] = 17;
|
list[4] = 17;
|
||||||
|
|
||||||
print(from_str("value: ") + list[4]);
|
print(from_str("value: ") + list[4]);
|
||||||
|
|||||||
@ -22,8 +22,6 @@ fn main() -> u32 {
|
|||||||
let otus = Otus { field: 17 };
|
let otus = Otus { field: 17 };
|
||||||
print(from_str("otus: ") + otus.test() as u64);
|
print(from_str("otus: ") + otus.test() as u64);
|
||||||
|
|
||||||
otus.field;
|
|
||||||
|
|
||||||
|
|
||||||
return otus.test();
|
return otus.test();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
// Arithmetic, function calls and imports!
|
// Arithmetic, function calls and imports!
|
||||||
|
|
||||||
/// Test stuff
|
|
||||||
fn changer(param: &mut u32) {
|
fn changer(param: &mut u32) {
|
||||||
*param = 17;
|
*param = 17;
|
||||||
}
|
}
|
||||||
|
|||||||
6
examples/breaking.reid
Normal file
6
examples/breaking.reid
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import std::String;
|
||||||
|
import std::print;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
print(String::new() + "hello")
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
// Arithmetic, function calls and imports!
|
// Arithmetic, function calls and imports!
|
||||||
|
|
||||||
|
import std::allocate;
|
||||||
import std::print;
|
import std::print;
|
||||||
|
|
||||||
fn other() -> i16 {
|
fn other() -> i16 {
|
||||||
@ -8,7 +9,7 @@ fn other() -> i16 {
|
|||||||
|
|
||||||
fn main() -> u32 {
|
fn main() -> u32 {
|
||||||
|
|
||||||
let mut v = (malloc(4) as *u32);
|
let mut v = (allocate(4) as *u32);
|
||||||
v[0] = other() as u32;
|
v[0] = other() as u32;
|
||||||
|
|
||||||
return v[0];
|
return v[0];
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
import complicated_imported::Foo;
|
|
||||||
import complicated_imported::A;
|
|
||||||
import complicated_imported::AResult;
|
|
||||||
|
|
||||||
fn main() -> i32 {
|
|
||||||
let foo = Foo {};
|
|
||||||
let a = A::new();
|
|
||||||
foo.foo(&a.a);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
struct A {}
|
|
||||||
struct AResult { a: A }
|
|
||||||
impl A {
|
|
||||||
pub fn new() -> AResult {
|
|
||||||
AResult { a: A {} }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Foo {}
|
|
||||||
impl Foo {
|
|
||||||
pub fn foo(&self, a: &A) {}
|
|
||||||
}
|
|
||||||
@ -1,466 +0,0 @@
|
|||||||
// First half of Ray Tracing in One Weekend, rendered to a SDL3 window rather
|
|
||||||
// than an image file. Needs to be linked against SDL3, i.e.
|
|
||||||
// `./cli cpu_raytracer.reid SDL3`
|
|
||||||
|
|
||||||
import std::print;
|
|
||||||
import std::String;
|
|
||||||
|
|
||||||
///////////////////
|
|
||||||
/// SDL externs ///
|
|
||||||
///////////////////
|
|
||||||
|
|
||||||
// Helper struct for stack allocated const sized strings, because structs are
|
|
||||||
// easier to create uninit than arrays.
|
|
||||||
struct SDL_Window {}
|
|
||||||
struct SDL_Renderer {}
|
|
||||||
struct SDL_Texture {}
|
|
||||||
struct SDL_Event { type: u32, reserved: [u8; 124] }
|
|
||||||
struct SDL_FRect { x: f32, y: f32, w: f32, h: f32 }
|
|
||||||
struct SDL_Rect { x: i32, y: i32, w: i32, h: i32 }
|
|
||||||
extern fn SDL_malloc(size: u64) -> *u8;
|
|
||||||
extern fn SDL_Init(flags: u32) -> bool;
|
|
||||||
extern fn SDL_Quit();
|
|
||||||
extern fn SDL_CreateWindowAndRenderer(title: *char, width: i32, height: i32, flags: i32,
|
|
||||||
window_out: &mut *SDL_Window, renderer_out: &mut *SDL_Renderer) -> bool;
|
|
||||||
extern fn SDL_Delay(ms: u32);
|
|
||||||
extern fn SDL_SetRenderDrawColor(renderer: *SDL_Renderer, r: u8, g: u8, b: u8, a: u8);
|
|
||||||
extern fn SDL_RenderClear(renderer: *SDL_Renderer);
|
|
||||||
extern fn SDL_RenderPresent(renderer: *SDL_Renderer);
|
|
||||||
extern fn SDL_HasEvent(event_type: u32) -> bool;
|
|
||||||
extern fn SDL_PollEvent(event: &mut SDL_Event) -> bool;
|
|
||||||
extern fn SDL_PumpEvents();
|
|
||||||
extern fn SDL_FlushEvents(min_type: u32, max_type: u32);
|
|
||||||
extern fn SDL_GetTicks() -> u64;
|
|
||||||
extern fn SDL_SetWindowTitle(window: *SDL_Window, title: *char) -> bool;
|
|
||||||
extern fn SDL_CreateTexture(renderer: *SDL_Renderer,
|
|
||||||
pixel_format: u32, texture_access: u32, width: u32, height: u32) -> *SDL_Texture;
|
|
||||||
extern fn SDL_RenderTexture(renderer: *SDL_Renderer,
|
|
||||||
texture: *SDL_Texture, srcfrect: &SDL_FRect, dstfrect: &SDL_FRect) -> bool;
|
|
||||||
extern fn SDL_UpdateTexture(texture: *SDL_Texture, rect: &SDL_Rect, pixels: *u8, pitch: u32) -> bool;
|
|
||||||
extern fn SDL_GetError() -> *char;
|
|
||||||
extern fn SDL_GetWindowSize(window: *SDL_Window, w: &mut i32, h: &mut i32) -> bool;
|
|
||||||
extern fn SDL_rand(max_exclusive: u32) -> u32;
|
|
||||||
extern fn SDL_SetTextureScaleMode(texture: *SDL_Texture, scale_mode: i32) -> bool;
|
|
||||||
extern fn SDL_sqrtf(value: f32) -> f32;
|
|
||||||
extern fn SDL_randf() -> f32;
|
|
||||||
extern fn SDL_powf(value: f32, power: f32) -> f32;
|
|
||||||
|
|
||||||
// SDL error reporting helper
|
|
||||||
fn print_sdl_error(context: *char) {
|
|
||||||
let mut message = String::new();
|
|
||||||
message = message + context + ": " + SDL_GetError();
|
|
||||||
print(message);
|
|
||||||
message.free();
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////
|
|
||||||
/// Main setup and frame loop ///
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
struct GameState {
|
|
||||||
renderer: *SDL_Renderer,
|
|
||||||
window: *SDL_Window,
|
|
||||||
render_texture: *SDL_Texture,
|
|
||||||
frame_counter: u32,
|
|
||||||
last_fps_reset: u64,
|
|
||||||
pixels: *u8,
|
|
||||||
pixels_w: u32,
|
|
||||||
pixels_h: u32,
|
|
||||||
pixels_bpp: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> i32 {
|
|
||||||
let SDL_INIT_VIDEO = 32;
|
|
||||||
let SDL_WINDOW_RESIZABLE = 32;
|
|
||||||
let SDL_PIXELFORMAT_RGBA8888 = 373694468;
|
|
||||||
let SDL_PIXELFORMAT_ABGR8888 = 376840196;
|
|
||||||
let SDL_PIXELFORMAT_RGB24 = 386930691;
|
|
||||||
let SDL_PIXELFORMAT_BGR24 = 390076419;
|
|
||||||
let SDL_PIXELFORMAT_RGB96_FLOAT = 454057996;
|
|
||||||
let SDL_PIXELFORMAT_BGR96_FLOAT = 457203724;
|
|
||||||
let SDL_TEXTUREACCESS_STREAMING = 1;
|
|
||||||
let SDL_SCALEMODE_NEAREST = 0;
|
|
||||||
let SDL_SCALEMODE_LINEAR = 1;
|
|
||||||
let SDL_SCALEMODE_PIXELART = 2;
|
|
||||||
|
|
||||||
let init_success = SDL_Init(SDL_INIT_VIDEO);
|
|
||||||
if init_success == false {
|
|
||||||
print_sdl_error("SDL init failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut window = SDL_Window::null();
|
|
||||||
let mut renderer = SDL_Renderer::null();
|
|
||||||
let gfx_init_success = SDL_CreateWindowAndRenderer(
|
|
||||||
"cpu raytracer", 640, 480, SDL_WINDOW_RESIZABLE,
|
|
||||||
&mut window, &mut renderer
|
|
||||||
);
|
|
||||||
if gfx_init_success == false {
|
|
||||||
print_sdl_error("SDL renderer and window creation failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let width = 128;
|
|
||||||
let height = 64;
|
|
||||||
let bpp = 4;
|
|
||||||
let render_texture = SDL_CreateTexture(renderer,
|
|
||||||
SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
|
||||||
SDL_SetTextureScaleMode(render_texture, SDL_SCALEMODE_NEAREST);
|
|
||||||
|
|
||||||
let pixels_len = (width * height * bpp) as u64;
|
|
||||||
let pixels = SDL_malloc(pixels_len);
|
|
||||||
let mut game_state = GameState {
|
|
||||||
renderer: renderer,
|
|
||||||
window: window,
|
|
||||||
render_texture: render_texture,
|
|
||||||
frame_counter: 0,
|
|
||||||
last_fps_reset: 0,
|
|
||||||
pixels: pixels,
|
|
||||||
pixels_w: width,
|
|
||||||
pixels_h: height,
|
|
||||||
pixels_bpp: bpp,
|
|
||||||
};
|
|
||||||
|
|
||||||
while frame_loop(&mut game_state) {}
|
|
||||||
|
|
||||||
SDL_Quit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn frame_loop(game_state: &mut GameState) -> bool {
|
|
||||||
let mut event = SDL_Event { type: 0, reserved: [0; 124] };
|
|
||||||
while (SDL_PollEvent(&mut event)) {
|
|
||||||
if event.type == 256 { // SDL_EVENT_QUIT
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut screen_width = 0;
|
|
||||||
let mut screen_height = 0;
|
|
||||||
SDL_GetWindowSize(*game_state.window, &mut screen_width, &mut screen_height);
|
|
||||||
|
|
||||||
let renderer = *game_state.renderer;
|
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 50, 90, 255);
|
|
||||||
SDL_RenderClear(renderer);
|
|
||||||
|
|
||||||
let w = *game_state.pixels_w;
|
|
||||||
let h = *game_state.pixels_h;
|
|
||||||
let bpp = *game_state.pixels_bpp;
|
|
||||||
for y in 0..h {
|
|
||||||
for x in 0..w {
|
|
||||||
render_pixel(x, y, game_state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let texture_area = SDL_Rect { x: 0, y: 0, w: w as i32, h: h as i32 };
|
|
||||||
if SDL_UpdateTexture(*game_state.render_texture, &texture_area, *game_state.pixels as *u8, bpp * w) == false {
|
|
||||||
print_sdl_error("UpdateTexture error");
|
|
||||||
}
|
|
||||||
let src = SDL_FRect { x: 0.0, y: 0.0, w: w as f32, h: h as f32 };
|
|
||||||
let aspect_ratio = src.w / src.h;
|
|
||||||
let scaled_width = screen_height as f32 * aspect_ratio;
|
|
||||||
let dst = SDL_FRect { x: (screen_width as f32 - scaled_width) / 2.0, y: 0.0, w: scaled_width, h: screen_height as f32 };
|
|
||||||
if SDL_RenderTexture(renderer, *game_state.render_texture, &src, &dst) == false {
|
|
||||||
print_sdl_error("RenderTexture error");
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
SDL_Delay(1);
|
|
||||||
|
|
||||||
*game_state.frame_counter = *game_state.frame_counter + 1;
|
|
||||||
let t = SDL_GetTicks();
|
|
||||||
if (t - *game_state.last_fps_reset) >= 1000 {
|
|
||||||
let mut title = String::new();
|
|
||||||
title = title + "cpu raytracer (" + *game_state.frame_counter as u64 + " fps)";
|
|
||||||
SDL_SetWindowTitle(*game_state.window, title.inner);
|
|
||||||
title.free();
|
|
||||||
*game_state.frame_counter = 0;
|
|
||||||
*game_state.last_fps_reset = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_pixel(x: u32, y: u32, game_state: &mut GameState) {
|
|
||||||
let w = *game_state.pixels_w;
|
|
||||||
let h = *game_state.pixels_h;
|
|
||||||
let bpp = *game_state.pixels_bpp;
|
|
||||||
|
|
||||||
let samples = 8;
|
|
||||||
let old_sample_weight = 0.9;
|
|
||||||
let new_sample_weight = 0.1 / samples as f32;
|
|
||||||
let mut rgb = vec_mul_scalar(old_sample_weight, [
|
|
||||||
srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 0]),
|
|
||||||
srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 1]),
|
|
||||||
srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 2])
|
|
||||||
]);
|
|
||||||
for sample in 0..samples {
|
|
||||||
rgb = vec_add(rgb, vec_mul_scalar(new_sample_weight, shade(x, y, *game_state.frame_counter, w, h)));
|
|
||||||
}
|
|
||||||
*game_state.pixels[(x + y * w) * bpp + 0] = linear_to_srgb(rgb[0]);
|
|
||||||
*game_state.pixels[(x + y * w) * bpp + 1] = linear_to_srgb(rgb[1]);
|
|
||||||
*game_state.pixels[(x + y * w) * bpp + 2] = linear_to_srgb(rgb[2]);
|
|
||||||
*game_state.pixels[(x + y * w) * bpp + 3] = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////
|
|
||||||
/// Rendering ///
|
|
||||||
/////////////////
|
|
||||||
|
|
||||||
struct Ray {
|
|
||||||
origin: [f32; 3],
|
|
||||||
direction: [f32; 3],
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Material {
|
|
||||||
// 0 = lambertian diffuse
|
|
||||||
// 1 = mirror
|
|
||||||
type: u32,
|
|
||||||
// Generally the "color" of the surface (linear factors of how much of each
|
|
||||||
// color channel this surface does not absorb), but the idea is that the
|
|
||||||
// type governs what this means.
|
|
||||||
linear_color: [f32; 3],
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Hit {
|
|
||||||
hit: bool,
|
|
||||||
front_face: bool,
|
|
||||||
distance: f32,
|
|
||||||
normal: [f32; 3],
|
|
||||||
position: [f32; 3],
|
|
||||||
material: Material,
|
|
||||||
}
|
|
||||||
impl Hit {
|
|
||||||
fn none() -> Hit {
|
|
||||||
Hit {
|
|
||||||
hit: false, front_face: true, distance: 0.0, normal: [0.0; 3], position: [0.0; 3],
|
|
||||||
material: Material { type: 0, linear_color: [0.0; 3] },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Sphere {
|
|
||||||
center: [f32; 3],
|
|
||||||
radius: f32,
|
|
||||||
material: Material,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shade(x: u32, y: u32, t: u32, w: u32, h: u32) -> [f32; 3] {
|
|
||||||
let jitter_x = SDL_randf() - 0.5;
|
|
||||||
let jitter_y = SDL_randf() - 0.5;
|
|
||||||
|
|
||||||
let pixel_scale = 1.0 / h as f32;
|
|
||||||
let pixel_pos = [
|
|
||||||
(x as f32 + jitter_x) * pixel_scale,
|
|
||||||
1.0 - (y as f32 + jitter_y) * pixel_scale,
|
|
||||||
-1.0
|
|
||||||
];
|
|
||||||
let camera_pos = [w as f32 * 0.5f32 * pixel_scale, h as f32 * 0.5f32 * pixel_scale, 0.0f32];
|
|
||||||
let dir = vec_normalize(vec_sub(pixel_pos, camera_pos));
|
|
||||||
let ray = Ray { origin: camera_pos, direction: dir };
|
|
||||||
let beige_lambertian = Material { type: 0, linear_color: [0.3, 0.2, 0.1] };
|
|
||||||
let green_lambertian = Material { type: 0, linear_color: [0.1, 0.5, 0.06] };
|
|
||||||
let greenish_mirror = Material { type: 1, linear_color: [0.9, 1.0, 0.95] };
|
|
||||||
let spheres = [
|
|
||||||
// Ground
|
|
||||||
Sphere { center: vec_sub(camera_pos, [0.0, 100001.0, 0.0]), radius: 100000.0, material: beige_lambertian },
|
|
||||||
// Centered unit sphere
|
|
||||||
Sphere { center: vec_add(camera_pos, [0.0, 0.0, 0.0 - 5.0]), radius: 1.0, material: green_lambertian },
|
|
||||||
// The unit sphere on the right
|
|
||||||
Sphere { center: vec_add(camera_pos, [2.0, 0.0, 0.0 - 6.0]), radius: 1.0, material: greenish_mirror }
|
|
||||||
];
|
|
||||||
return shade_world(ray, &spheres, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shade_world(ray: Ray, spheres: &[Sphere; 3], bounces_left: u8) -> [f32; 3] {
|
|
||||||
if bounces_left == 0 {
|
|
||||||
return [0.0, 0.0, 0.0];
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut closest_hit = Hit::none();
|
|
||||||
closest_hit.distance = 100.0;
|
|
||||||
for i in 0..3 {
|
|
||||||
let sphere_hit = ray_sphere_closest_hit(ray, *spheres[i], [0.001, closest_hit.distance]);
|
|
||||||
if sphere_hit.hit {
|
|
||||||
closest_hit = sphere_hit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if closest_hit.hit {
|
|
||||||
//return vec_mul_scalar(0.5, vec_add(closest_hit.normal, [1.0, 1.0, 1.0])); // normal
|
|
||||||
//return vec_mul_scalar(closest_hit.distance / 10.0, [1.0, 1.0, 1.0]); // depth
|
|
||||||
if closest_hit.material.type == 0 {
|
|
||||||
let bounce_dir = vec_normalize(vec_add(closest_hit.normal, random_unit_vec()));
|
|
||||||
let bounce_ray = Ray { origin: closest_hit.position, direction: bounce_dir };
|
|
||||||
return vec_mul_componentwise(
|
|
||||||
closest_hit.material.linear_color,
|
|
||||||
shade_world(bounce_ray, spheres, bounces_left - 1)
|
|
||||||
);
|
|
||||||
} else if closest_hit.material.type == 1 {
|
|
||||||
let bounce_dir = vec_reflect(ray.direction, closest_hit.normal);
|
|
||||||
let bounce_ray = Ray { origin: closest_hit.position, direction: bounce_dir };
|
|
||||||
return vec_mul_componentwise(
|
|
||||||
closest_hit.material.linear_color,
|
|
||||||
shade_world(bounce_ray, spheres, bounces_left - 1)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return [1.0, 0.0, 1.0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return shade_sky(ray);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shade_sky(ray: Ray) -> [f32; 3] {
|
|
||||||
let a = 0.5 * (ray.direction[1] + 1.0);
|
|
||||||
return vec_add(
|
|
||||||
vec_mul_scalar(1.0 - a, [1.0, 1.0, 1.0]),
|
|
||||||
vec_mul_scalar(a, [0.5, 0.7, 1.0])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the distance from the ray origin to the sphere, or -1.0 if the ray doesn't hit.
|
|
||||||
fn ray_sphere_closest_hit(ray: Ray, sphere: Sphere, interval: [f32; 2]) -> Hit {
|
|
||||||
let to_sphere = vec_sub(sphere.center, ray.origin);
|
|
||||||
let h = vec_dot(ray.direction, to_sphere);
|
|
||||||
let c = vec_length_squared(to_sphere) - sphere.radius * sphere.radius;
|
|
||||||
let discriminant = h * h - c;
|
|
||||||
if discriminant < 0.0 {
|
|
||||||
return Hit::none();
|
|
||||||
}
|
|
||||||
|
|
||||||
let discriminant_sqrt = SDL_sqrtf(discriminant);
|
|
||||||
let mut distance = h - discriminant_sqrt;
|
|
||||||
if interval_surrounds(interval, distance) == false {
|
|
||||||
distance = h + discriminant_sqrt;
|
|
||||||
if interval_surrounds(interval, distance) == false {
|
|
||||||
return Hit::none();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let hit_position = vec_add(ray.origin, vec_mul_scalar(distance, ray.direction));
|
|
||||||
let mut front_face = true;
|
|
||||||
let mut normal = vec_normalize(vec_sub(hit_position, sphere.center));
|
|
||||||
if vec_dot(normal, ray.direction) > 0.0 {
|
|
||||||
normal = vec_mul_scalar(-1.0, normal);
|
|
||||||
front_face = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Hit {
|
|
||||||
hit: true,
|
|
||||||
front_face: front_face,
|
|
||||||
distance: distance,
|
|
||||||
normal: normal,
|
|
||||||
position: hit_position,
|
|
||||||
material: sphere.material,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////
|
|
||||||
/// Other math ///
|
|
||||||
//////////////////
|
|
||||||
|
|
||||||
fn clamp(min: f32, max: f32, value: f32) -> f32 {
|
|
||||||
if value > max {
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
if value < min {
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn abs(f: f32) -> f32 {
|
|
||||||
if f < 0.0 {
|
|
||||||
return f * -1.0;
|
|
||||||
}
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec_add(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] {
|
|
||||||
return [lhs[0] + rhs[0], lhs[1] + rhs[1], lhs[2] + rhs[2]];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec_sub(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] {
|
|
||||||
return [lhs[0] - rhs[0], lhs[1] - rhs[1], lhs[2] - rhs[2]];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec_dot(lhs: [f32; 3], rhs: [f32; 3]) -> f32 {
|
|
||||||
return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec_mul_componentwise(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] {
|
|
||||||
return [lhs[0] * rhs[0], lhs[1] * rhs[1], lhs[2] * rhs[2]];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec_mul_scalar(lhs: f32, rhs: [f32; 3]) -> [f32; 3] {
|
|
||||||
return [lhs * rhs[0], lhs * rhs[1], lhs * rhs[2]];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec_normalize(v: [f32; 3]) -> [f32; 3] {
|
|
||||||
let len_reciprocal = 1.0f32 / SDL_sqrtf(vec_length_squared(v));
|
|
||||||
return vec_mul_scalar(len_reciprocal, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec_length_squared(v: [f32; 3]) -> f32 {
|
|
||||||
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec_abs(v: [f32; 3]) -> [f32; 3] {
|
|
||||||
return [abs(v[0]), abs(v[1]), abs(v[2])];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec_reflect(direction: [f32; 3], normal: [f32; 3]) -> [f32; 3] {
|
|
||||||
return vec_sub(direction, vec_mul_scalar(2.0f32 * vec_dot(direction, normal), normal));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn interval_surrounds(interval: [f32; 2], value: f32) -> bool {
|
|
||||||
return (interval[0] < value) && (value < interval[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn random_unit_vec() -> [f32; 3] {
|
|
||||||
let mut point = [
|
|
||||||
SDL_randf() * 2.0f32 - 1.0f32,
|
|
||||||
SDL_randf() * 2.0f32 - 1.0f32,
|
|
||||||
SDL_randf() * 2.0f32 - 1.0f32
|
|
||||||
];
|
|
||||||
let mut lensq = vec_length_squared(point);
|
|
||||||
while lensq > 1.0 {
|
|
||||||
point = [
|
|
||||||
SDL_randf() * 2.0f32 - 1.0f32,
|
|
||||||
SDL_randf() * 2.0f32 - 1.0f32,
|
|
||||||
SDL_randf() * 2.0f32 - 1.0f32
|
|
||||||
];
|
|
||||||
lensq = vec_length_squared(point);
|
|
||||||
}
|
|
||||||
let len_reciprocal = 1.0f32 / SDL_sqrtf(lensq);
|
|
||||||
return vec_mul_scalar(len_reciprocal, point);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn random_unit_vec_on_hemi(normal: [f32; 3]) -> [f32; 3] {
|
|
||||||
let rand_vec = random_unit_vec();
|
|
||||||
if vec_dot(rand_vec, normal) < 0.0f32 {
|
|
||||||
return vec_mul_scalar(0.0f32 - 1.0f32, rand_vec);
|
|
||||||
}
|
|
||||||
return rand_vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn linear_to_srgb(linear: f32) -> u8 {
|
|
||||||
let mut floating_srgb = 0.0;
|
|
||||||
if linear <= 0.0031308f32 {
|
|
||||||
floating_srgb = 12.92f32 * linear;
|
|
||||||
} else {
|
|
||||||
floating_srgb = SDL_powf(linear as f32, 1.0 / 2.4) * 1.055f32 - 0.055f32;
|
|
||||||
}
|
|
||||||
let clamped = clamp(0.0, 1.0, floating_srgb);
|
|
||||||
return (clamped * 255.999) as u8;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn srgb_to_linear(srgb: u8) -> f32 {
|
|
||||||
let floating_srgb = srgb as f32 / 255.0;
|
|
||||||
if floating_srgb <= 0.04045f32 {
|
|
||||||
return floating_srgb / 12.92f32;
|
|
||||||
}
|
|
||||||
return SDL_powf((floating_srgb as f32 + 0.055) / 1.055, 2.4);
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
import foreign_struct::Vec2;
|
|
||||||
|
|
||||||
fn main() -> u32 {
|
|
||||||
let a = Vec2 {x: 16, y: 32};
|
|
||||||
return a.x;
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
struct Vec2 { x: u32, y: u32 }
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
fn main() -> i32 {
|
|
||||||
for i in 0..1 {
|
|
||||||
let j = i;
|
|
||||||
if i != j {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
import std::String;
|
|
||||||
import std::print;
|
|
||||||
|
|
||||||
fn main() -> u8 {
|
|
||||||
let bytes = include_bytes!("./macro_easy_file.txt");
|
|
||||||
print(String::new() + bytes.length());
|
|
||||||
print(String::new() + (include_bytes!("./macro_easy_file.txt") as *u8)[1] as u64);
|
|
||||||
return (include_bytes!("./macro_easy_file.txt") as *u8)[0];
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
hello
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
|
|
||||||
extern fn printf(message: *char, num: f64);
|
|
||||||
|
|
||||||
fn main() -> i32 {
|
|
||||||
let b = 5;
|
|
||||||
let mut otus = i32::malloc(1);
|
|
||||||
otus[0] = 10500300;
|
|
||||||
let potus = i32::malloc(1);
|
|
||||||
i32::memcpy(potus, otus, 1);
|
|
||||||
|
|
||||||
printf("log10 %f\n", f64::round(123.3) as f64);
|
|
||||||
printf("sqrt %f\n", f64::sqrt(2) as f64);
|
|
||||||
printf("log10 %f\n", potus[0] as f64);
|
|
||||||
return potus[0];
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
struct Otus {
|
|
||||||
field: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test() -> Otus {
|
|
||||||
Otus {field: 4}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
// Arithmetic, function calls and imports!
|
|
||||||
|
|
||||||
import module_importee::Otus;
|
|
||||||
import module_importee::test;
|
|
||||||
|
|
||||||
fn main() -> u32 {
|
|
||||||
let value = 0b110;
|
|
||||||
let other = 0o17;
|
|
||||||
|
|
||||||
return value * other + test().field * -value;
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
struct Game {}
|
|
||||||
|
|
||||||
impl Game {
|
|
||||||
pub fn run_frame(&mut self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Platform {
|
|
||||||
game: Game,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Platform {
|
|
||||||
pub fn new() -> Platform {
|
|
||||||
return Platform { game: Game {} };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_frame(&mut self) {
|
|
||||||
*self.game.run_frame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> i32 {
|
|
||||||
let mut platform = Platform::new();
|
|
||||||
platform.run_frame();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
fn main() -> bool {
|
|
||||||
let ptr = i32::null();
|
|
||||||
return i32::is_null(ptr);
|
|
||||||
}
|
|
||||||
@ -1,7 +1,9 @@
|
|||||||
// Arithmetic, function calls and imports!
|
// Arithmetic, function calls and imports!
|
||||||
|
|
||||||
|
import std::allocate;
|
||||||
|
|
||||||
fn main() -> u8 {
|
fn main() -> u8 {
|
||||||
let mut ptr = u8::malloc(4);
|
let mut ptr = allocate(4);
|
||||||
|
|
||||||
ptr[0] = 5;
|
ptr[0] = 5;
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ BINARY="$(echo $1 | cut -d'.' -f1)"".out"
|
|||||||
|
|
||||||
echo $1
|
echo $1
|
||||||
|
|
||||||
cargo run -p reid -- $@ && \
|
cargo run --example cli $@ && \
|
||||||
./$BINARY ; echo "Return value: ""$?"
|
./$BINARY ; echo "Return value: ""$?"
|
||||||
|
|
||||||
## Command from: clang -v hello.o -o test
|
## Command from: clang -v hello.o -o test
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
Subproject commit 100cd96a6dc3bb882ce60e78c4eab47e77fdd8c4
|
|
||||||
12
reid-llvm-lib/Cargo.toml
Normal file
12
reid-llvm-lib/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "reid-lib"
|
||||||
|
version = "1.0.0-beta.2"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
## LLVM Bindings
|
||||||
|
llvm-sys = {version ="201.0.1" }
|
||||||
|
## Make it easier to generate errors
|
||||||
|
thiserror = "1.0.44"
|
||||||
65
reid-llvm-lib/examples/libtest.rs
Normal file
65
reid-llvm-lib/examples/libtest.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use reid_lib::{CmpPredicate, ConstValue, Context, FunctionFlags, Instr, TerminatorKind, Type};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
use ConstValue::*;
|
||||||
|
use Instr::*;
|
||||||
|
|
||||||
|
let context = Context::new("libtest");
|
||||||
|
|
||||||
|
let module = context.module("test", true);
|
||||||
|
|
||||||
|
let main = module.function("main", Type::I32, Vec::new(), FunctionFlags::default());
|
||||||
|
let mut m_entry = main.block("entry");
|
||||||
|
|
||||||
|
let fibonacci = module.function(
|
||||||
|
"fibonacci",
|
||||||
|
Type::I32,
|
||||||
|
vec![Type::I32],
|
||||||
|
FunctionFlags::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let arg = m_entry.build_named("const", Constant(I32(5))).unwrap();
|
||||||
|
let fibonacci_call = m_entry
|
||||||
|
.build_named("const", FunctionCall(fibonacci.value(), vec![arg]))
|
||||||
|
.unwrap();
|
||||||
|
m_entry
|
||||||
|
.terminate(TerminatorKind::Ret(fibonacci_call))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut f_entry = fibonacci.block("entry");
|
||||||
|
|
||||||
|
let num_3 = f_entry.build_named("const", Constant(I32(3))).unwrap();
|
||||||
|
let param_n = f_entry.build_named("param", Param(0)).unwrap();
|
||||||
|
let cond = f_entry
|
||||||
|
.build_named("cmp", ICmp(CmpPredicate::LT, param_n, num_3))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut then_b = fibonacci.block("then");
|
||||||
|
let mut else_b = fibonacci.block("else");
|
||||||
|
|
||||||
|
f_entry
|
||||||
|
.terminate(TerminatorKind::CondBr(cond, then_b.value(), else_b.value()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let ret_const = then_b.build_named("const", Constant(I32(1))).unwrap();
|
||||||
|
then_b.terminate(TerminatorKind::Ret(ret_const)).unwrap();
|
||||||
|
|
||||||
|
let const_1 = else_b.build_named("const", Constant(I32(1))).unwrap();
|
||||||
|
let const_2 = else_b.build_named("const", Constant(I32(2))).unwrap();
|
||||||
|
let param_1 = else_b.build_named("sub", Sub(param_n, const_1)).unwrap();
|
||||||
|
let param_2 = else_b.build_named("sub", Sub(param_n, const_2)).unwrap();
|
||||||
|
let call_1 = else_b
|
||||||
|
.build_named("fibonacci", FunctionCall(fibonacci.value(), vec![param_1]))
|
||||||
|
.unwrap();
|
||||||
|
let call_2 = else_b
|
||||||
|
.build_named("fibonacci", FunctionCall(fibonacci.value(), vec![param_2]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let add = else_b.build_named("add", Add(call_1, call_2)).unwrap();
|
||||||
|
|
||||||
|
else_b.terminate(TerminatorKind::Ret(add)).unwrap();
|
||||||
|
|
||||||
|
dbg!(&context);
|
||||||
|
|
||||||
|
context.compile(None, Vec::new());
|
||||||
|
}
|
||||||
720
reid-llvm-lib/src/builder.rs
Normal file
720
reid-llvm-lib/src/builder.rs
Normal file
@ -0,0 +1,720 @@
|
|||||||
|
//! This module contains simply [`Builder`] and it's related utility Values.
|
||||||
|
//! Builder is the actual struct being modified when building the LLIR.
|
||||||
|
|
||||||
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Block, BlockData, CompileResult, CustomTypeKind, ErrorKind, FunctionData, Instr, InstructionData, ModuleData,
|
||||||
|
NamedStruct, TerminatorKind, Type, TypeCategory, TypeData,
|
||||||
|
debug_information::{
|
||||||
|
DebugInformation, DebugLocationValue, DebugMetadataValue, DebugScopeValue, InstructionDebugRecordData,
|
||||||
|
},
|
||||||
|
util::match_types,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
|
||||||
|
pub struct ModuleValue(pub(crate) usize);
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
|
||||||
|
pub struct TypeValue(pub(crate) ModuleValue, pub(crate) usize);
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
|
||||||
|
pub struct FunctionValue(pub(crate) ModuleValue, pub(crate) usize);
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
|
||||||
|
pub struct BlockValue(pub(crate) FunctionValue, pub(crate) usize);
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
|
||||||
|
pub struct InstructionValue(pub(crate) BlockValue, pub(crate) usize);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ModuleHolder {
|
||||||
|
pub(crate) value: ModuleValue,
|
||||||
|
pub(crate) data: ModuleData,
|
||||||
|
pub(crate) functions: Vec<FunctionHolder>,
|
||||||
|
pub(crate) types: Vec<TypeHolder>,
|
||||||
|
pub(crate) debug_information: Option<DebugInformation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TypeHolder {
|
||||||
|
pub(crate) value: TypeValue,
|
||||||
|
pub(crate) data: TypeData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct FunctionHolder {
|
||||||
|
pub(crate) value: FunctionValue,
|
||||||
|
pub(crate) data: FunctionData,
|
||||||
|
pub(crate) blocks: Vec<BlockHolder>,
|
||||||
|
/// Debug scope value of this current function
|
||||||
|
pub(crate) debug_info: Option<DebugScopeValue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct BlockHolder {
|
||||||
|
pub(crate) value: BlockValue,
|
||||||
|
pub(crate) data: BlockData,
|
||||||
|
pub(crate) instructions: Vec<InstructionHolder>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct InstructionHolder {
|
||||||
|
pub(crate) value: InstructionValue,
|
||||||
|
pub(crate) data: InstructionData,
|
||||||
|
pub(crate) name: String,
|
||||||
|
pub(crate) record: Option<InstructionDebugRecordData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct Builder {
|
||||||
|
pub(crate) modules: Rc<RefCell<Vec<ModuleHolder>>>,
|
||||||
|
pub(crate) producer: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Builder {
|
||||||
|
pub fn new(producer: String) -> Builder {
|
||||||
|
Builder {
|
||||||
|
modules: Rc::new(RefCell::new(Vec::new())),
|
||||||
|
producer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_module(&self, data: ModuleData) -> ModuleValue {
|
||||||
|
let value = ModuleValue(self.modules.borrow().len());
|
||||||
|
self.modules.borrow_mut().push(ModuleHolder {
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
functions: Vec::new(),
|
||||||
|
types: Vec::new(),
|
||||||
|
debug_information: None,
|
||||||
|
});
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_debug_information(&self, mod_val: &ModuleValue, debug_info: DebugInformation) {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(mod_val.0);
|
||||||
|
module.debug_information = Some(debug_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn add_type(&self, mod_val: &ModuleValue, data: TypeData) -> TypeValue {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(mod_val.0);
|
||||||
|
let value = TypeValue(module.value, module.types.len());
|
||||||
|
module.types.push(TypeHolder { value, data });
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn add_function(&self, mod_val: &ModuleValue, data: FunctionData) -> FunctionValue {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(mod_val.0);
|
||||||
|
let value = FunctionValue(module.value, module.functions.len());
|
||||||
|
module.functions.push(FunctionHolder {
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
blocks: Vec::new(),
|
||||||
|
debug_info: None,
|
||||||
|
});
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn add_block(&self, fun_val: &FunctionValue, data: BlockData) -> BlockValue {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(fun_val.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(fun_val.1);
|
||||||
|
let value = BlockValue(function.value, function.blocks.len());
|
||||||
|
function.blocks.push(BlockHolder {
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
instructions: Vec::new(),
|
||||||
|
});
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn add_instruction(
|
||||||
|
&self,
|
||||||
|
block_val: &BlockValue,
|
||||||
|
data: InstructionData,
|
||||||
|
name: String,
|
||||||
|
) -> CompileResult<InstructionValue> {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(block_val.0.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(block_val.0.1);
|
||||||
|
let block = function.blocks.get_unchecked_mut(block_val.1);
|
||||||
|
let value = InstructionValue(block.value, block.instructions.len());
|
||||||
|
block.instructions.push(InstructionHolder {
|
||||||
|
value,
|
||||||
|
data,
|
||||||
|
name,
|
||||||
|
record: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Drop modules so that it is no longer mutable borrowed
|
||||||
|
// (check_instruction requires an immutable borrow).
|
||||||
|
drop(modules);
|
||||||
|
|
||||||
|
self.check_instruction(&value)?;
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn add_instruction_location(&self, value: &InstructionValue, location: DebugLocationValue) {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(value.0.0.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(value.0.0.1);
|
||||||
|
let block = function.blocks.get_unchecked_mut(value.0.1);
|
||||||
|
let instr = block.instructions.get_unchecked_mut(value.1);
|
||||||
|
instr.data.location = Some(location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn add_instruction_metadata(&self, value: &InstructionValue, metadata: DebugMetadataValue) {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(value.0.0.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(value.0.0.1);
|
||||||
|
let block = function.blocks.get_unchecked_mut(value.0.1);
|
||||||
|
let instr = block.instructions.get_unchecked_mut(value.1);
|
||||||
|
instr.data.meta = Some(metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn add_instruction_record(&self, value: &InstructionValue, record: InstructionDebugRecordData) {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(value.0.0.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(value.0.0.1);
|
||||||
|
let block = function.blocks.get_unchecked_mut(value.0.1);
|
||||||
|
let instr = block.instructions.get_unchecked_mut(value.1);
|
||||||
|
instr.record = Some(record)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn set_debug_subprogram(&self, value: &FunctionValue, subprogram: DebugScopeValue) {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(value.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(value.1);
|
||||||
|
function.debug_info = Some(subprogram)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn terminate(&self, block: &BlockValue, value: TerminatorKind) -> CompileResult<()> {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(block.0.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(block.0.1);
|
||||||
|
let block = function.blocks.get_unchecked_mut(block.1);
|
||||||
|
if let Some(_) = &block.data.terminator {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
} else {
|
||||||
|
block.data.terminator = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn set_terminator_location(
|
||||||
|
&self,
|
||||||
|
block: &BlockValue,
|
||||||
|
location: DebugLocationValue,
|
||||||
|
) -> CompileResult<()> {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(block.0.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(block.0.1);
|
||||||
|
let block = function.blocks.get_unchecked_mut(block.1);
|
||||||
|
if let Some(_) = &block.data.terminator_location {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
} else {
|
||||||
|
block.data.terminator_location = Some(location);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn delete_block(&self, block: &BlockValue) -> CompileResult<()> {
|
||||||
|
unsafe {
|
||||||
|
let mut modules = self.modules.borrow_mut();
|
||||||
|
let module = modules.get_unchecked_mut(block.0.0.0);
|
||||||
|
let function = module.functions.get_unchecked_mut(block.0.1);
|
||||||
|
let block = function.blocks.get_unchecked_mut(block.1);
|
||||||
|
block.data.deleted = true;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) unsafe fn module_data(&self, value: &ModuleValue) -> ModuleData {
|
||||||
|
unsafe { self.modules.borrow().get_unchecked(value.0).data.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn function_data(&self, value: &FunctionValue) -> FunctionData {
|
||||||
|
unsafe {
|
||||||
|
self.modules
|
||||||
|
.borrow()
|
||||||
|
.get_unchecked(value.0.0)
|
||||||
|
.functions
|
||||||
|
.get_unchecked(value.1)
|
||||||
|
.data
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) unsafe fn block_data(&self, value: &BlockValue) -> BlockData {
|
||||||
|
unsafe {
|
||||||
|
self.modules
|
||||||
|
.borrow()
|
||||||
|
.get_unchecked(value.0.0.0)
|
||||||
|
.functions
|
||||||
|
.get_unchecked(value.0.1)
|
||||||
|
.blocks
|
||||||
|
.get_unchecked(value.1)
|
||||||
|
.data
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn instr_data(&self, value: &InstructionValue) -> InstructionData {
|
||||||
|
unsafe {
|
||||||
|
self.modules
|
||||||
|
.borrow()
|
||||||
|
.get_unchecked(value.0.0.0.0)
|
||||||
|
.functions
|
||||||
|
.get_unchecked(value.0.0.1)
|
||||||
|
.blocks
|
||||||
|
.get_unchecked(value.0.1)
|
||||||
|
.instructions
|
||||||
|
.get_unchecked(value.1)
|
||||||
|
.data
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn type_data(&self, value: &TypeValue) -> TypeData {
|
||||||
|
unsafe {
|
||||||
|
self.modules
|
||||||
|
.borrow()
|
||||||
|
.get_unchecked(value.0.0)
|
||||||
|
.types
|
||||||
|
.get_unchecked(value.1)
|
||||||
|
.data
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn find_module<'ctx>(&'ctx self, value: ModuleValue) -> ModuleHolder {
|
||||||
|
unsafe { self.modules.borrow().get_unchecked(value.0).clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_modules(&self) -> Rc<RefCell<Vec<ModuleHolder>>> {
|
||||||
|
self.modules.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_instruction(&self, instruction: &InstructionValue) -> CompileResult<()> {
|
||||||
|
unsafe {
|
||||||
|
match self.instr_data(&instruction).kind {
|
||||||
|
Instr::Param(_) => Ok(()),
|
||||||
|
Instr::Constant(_) => Ok(()),
|
||||||
|
Instr::Add(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category().integer() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::FAdd(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::Sub(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category().integer() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::FSub(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::Mul(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category().integer() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::FMul(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::UDiv(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::UnsignedInteger {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::SDiv(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::SignedInteger {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::FDiv(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::URem(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::UnsignedInteger {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::SRem(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::SignedInteger {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::FRem(lhs, rhs) => {
|
||||||
|
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::And(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()),
|
||||||
|
Instr::Or(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()),
|
||||||
|
Instr::XOr(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()),
|
||||||
|
Instr::ICmp(_, lhs, rhs) => {
|
||||||
|
let t = match_types(&lhs, &rhs, self)?;
|
||||||
|
if t.category().comparable() || !t.category().integer() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null) // TODO error: Types not comparable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::FCmp(_, lhs, rhs) => {
|
||||||
|
let t = match_types(&lhs, &rhs, self)?;
|
||||||
|
if t.category().comparable() || t.category() != TypeCategory::Real {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null) // TODO error: Types not comparable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::FunctionCall(fun, params) => {
|
||||||
|
let param_types = self.function_data(&fun).params;
|
||||||
|
if param_types.len() != params.len() {
|
||||||
|
return Err(ErrorKind::Null); // TODO error: invalid amount of params
|
||||||
|
}
|
||||||
|
for (a, b) in param_types.iter().zip(params) {
|
||||||
|
if *a != b.get_type(&self)? {
|
||||||
|
return Err(ErrorKind::Null); // TODO error: params do not match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Instr::Phi(vals) => {
|
||||||
|
let mut iter = vals.iter();
|
||||||
|
// TODO error: Phi must contain at least one item
|
||||||
|
|
||||||
|
// TODO error: compile can actually crash here if any of the
|
||||||
|
// incoming values come from blocks that are added later
|
||||||
|
// than the one where this one exists.
|
||||||
|
|
||||||
|
let first = iter.next().ok_or(ErrorKind::Null)?;
|
||||||
|
for item in iter {
|
||||||
|
match_types(first, item, &self)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Instr::Alloca(_) => Ok(()),
|
||||||
|
Instr::Load(ptr, load_ty) => {
|
||||||
|
let ptr_ty = ptr.get_type(&self)?;
|
||||||
|
if let Type::Ptr(ptr_ty_inner) = ptr_ty {
|
||||||
|
if *ptr_ty_inner == load_ty {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null) // TODO error: inner type mismatch
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null) // TODO error: not a pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::Store(ptr, _) => {
|
||||||
|
let ty = ptr.get_type(&self)?;
|
||||||
|
if let Type::Ptr(_) = ty {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null) // TODO error: not a pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::ArrayAlloca(_, val) => {
|
||||||
|
if val.get_type(self)?.category() == TypeCategory::UnsignedInteger {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null) // TODO error: not a pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::GetElemPtr(ptr_val, _) => {
|
||||||
|
let ptr_ty = ptr_val.get_type(&self)?;
|
||||||
|
match ptr_ty {
|
||||||
|
Type::Ptr(_) => Ok(()),
|
||||||
|
_ => Err(ErrorKind::Null),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::GetStructElemPtr(ptr_val, idx) => {
|
||||||
|
let ptr_ty = ptr_val.get_type(&self)?;
|
||||||
|
if let Type::Ptr(ty) = ptr_ty {
|
||||||
|
if let Type::CustomType(val) = *ty {
|
||||||
|
match self.type_data(&val).kind {
|
||||||
|
CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => {
|
||||||
|
if fields.len() <= idx as usize {
|
||||||
|
return Err(ErrorKind::Null); // TODO error: no such field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null) // TODO error: not a struct
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null) // TODO error: not a pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::ExtractValue(val, _) => {
|
||||||
|
let val_ty = val.get_type(&self)?;
|
||||||
|
match val_ty {
|
||||||
|
Type::CustomType(custom) => match self.type_data(&custom).kind {
|
||||||
|
CustomTypeKind::NamedStruct(_) => Ok(()),
|
||||||
|
},
|
||||||
|
Type::Array(_, _) => Ok(()),
|
||||||
|
_ => Err(ErrorKind::Null),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::Trunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::ZExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::SExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::FPTrunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::FPExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::FPToUI(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::FPToSI(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::UIToFP(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::SIToFP(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::PtrToInt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::IntToPtr(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
|
Instr::BitCast(..) => Ok(()),
|
||||||
|
Instr::ShiftRightLogical(_, rhs) => {
|
||||||
|
let rhs_ty = rhs.get_type(&self)?;
|
||||||
|
if rhs_ty.category() == TypeCategory::UnsignedInteger {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::ShiftRightArithmetic(_, rhs) => {
|
||||||
|
let rhs_ty = rhs.get_type(&self)?;
|
||||||
|
if rhs_ty.category() == TypeCategory::UnsignedInteger {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instr::ShiftLeft(_, rhs) => {
|
||||||
|
let rhs_ty = rhs.get_type(&self)?;
|
||||||
|
if rhs_ty.category() == TypeCategory::UnsignedInteger {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_block_used(&self, block_v: BlockValue) -> bool {
|
||||||
|
unsafe {
|
||||||
|
let modules = self.modules.borrow();
|
||||||
|
let module = modules.get_unchecked(block_v.0.0.0);
|
||||||
|
let function = module.functions.get_unchecked(block_v.0.1);
|
||||||
|
let block = function.blocks.get_unchecked(block_v.1);
|
||||||
|
|
||||||
|
if block.instructions.len() > 0 || block.data.terminator.is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for other in &function.blocks {
|
||||||
|
if let Some(term) = &other.data.terminator {
|
||||||
|
match term {
|
||||||
|
TerminatorKind::Ret(_) => {}
|
||||||
|
TerminatorKind::RetVoid => {}
|
||||||
|
TerminatorKind::Br(other_val) => {
|
||||||
|
if other_val == &block_v {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TerminatorKind::CondBr(_, then_other_v, else_other_v) => {
|
||||||
|
if then_other_v == &block_v || else_other_v == &block_v {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstructionValue {
|
||||||
|
pub fn with_location(self, block: &Block, location: DebugLocationValue) -> InstructionValue {
|
||||||
|
unsafe {
|
||||||
|
block.builder.add_instruction_location(&self, location);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maybe_location(self, block: &mut Block, location: Option<DebugLocationValue>) -> InstructionValue {
|
||||||
|
unsafe {
|
||||||
|
if let Some(location) = location {
|
||||||
|
block.builder.add_instruction_location(&self, location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_record(&self, block: &mut Block, record: InstructionDebugRecordData) {
|
||||||
|
unsafe {
|
||||||
|
block.builder.add_instruction_record(self, record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_type(&self, builder: &Builder) -> CompileResult<Type> {
|
||||||
|
use Instr::*;
|
||||||
|
unsafe {
|
||||||
|
match &builder.instr_data(self).kind {
|
||||||
|
Param(nth) => builder
|
||||||
|
.function_data(&self.0.0)
|
||||||
|
.params
|
||||||
|
.get(*nth)
|
||||||
|
.cloned()
|
||||||
|
.ok_or(ErrorKind::Null),
|
||||||
|
Constant(c) => Ok(c.get_type()),
|
||||||
|
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
FAdd(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
Sub(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
FSub(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
Mul(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
FMul(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
UDiv(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
SDiv(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
FDiv(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
URem(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
SRem(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
FRem(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
And(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
Or(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
XOr(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
|
ICmp(_, _, _) => Ok(Type::Bool),
|
||||||
|
FCmp(_, _, _) => Ok(Type::Bool),
|
||||||
|
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
|
||||||
|
Phi(values) => values.first().ok_or(ErrorKind::Null).and_then(|v| v.get_type(&builder)),
|
||||||
|
Alloca(ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
|
||||||
|
Load(_, ty) => Ok(ty.clone()),
|
||||||
|
Store(_, value) => value.get_type(builder),
|
||||||
|
ArrayAlloca(ty, _) => Ok(Type::Ptr(Box::new(ty.clone()))),
|
||||||
|
GetElemPtr(instr, _) => {
|
||||||
|
let instr_ty = instr.get_type(builder)?;
|
||||||
|
let Type::Ptr(inner_ty) = &instr_ty else {
|
||||||
|
panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty)
|
||||||
|
};
|
||||||
|
match *inner_ty.clone() {
|
||||||
|
Type::Array(elem_ty, _) => Ok(Type::Ptr(Box::new(*elem_ty.clone()))),
|
||||||
|
_ => Ok(instr_ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GetStructElemPtr(instr, idx) => {
|
||||||
|
let instr_ty = instr.get_type(builder)?;
|
||||||
|
let Type::Ptr(inner_ty) = instr_ty else {
|
||||||
|
panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty)
|
||||||
|
};
|
||||||
|
let Type::CustomType(ty_value) = *inner_ty else {
|
||||||
|
panic!("GetStructElemPtr on non-struct! ({:?})", &inner_ty)
|
||||||
|
};
|
||||||
|
let field_ty = match builder.type_data(&ty_value).kind {
|
||||||
|
CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => {
|
||||||
|
fields.get_unchecked(*idx as usize).clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(Type::Ptr(Box::new(field_ty)))
|
||||||
|
}
|
||||||
|
ExtractValue(instr, idx) => {
|
||||||
|
let instr_ty = instr.get_type(builder)?;
|
||||||
|
Ok(match instr_ty {
|
||||||
|
Type::CustomType(struct_ty) => {
|
||||||
|
let data = builder.type_data(&struct_ty);
|
||||||
|
match data.kind {
|
||||||
|
CustomTypeKind::NamedStruct(named_struct) => {
|
||||||
|
named_struct.1.get(*idx as usize).unwrap().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Array(elem_ty, _) => *elem_ty.clone(),
|
||||||
|
_ => return Err(ErrorKind::Null),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Trunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
ZExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
SExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
FPTrunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
FPExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
FPToUI(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
FPToSI(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
UIToFP(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
SIToFP(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
PtrToInt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
IntToPtr(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
|
BitCast(_, ty) => Ok(ty.clone()),
|
||||||
|
ShiftRightLogical(lhs, _) => lhs.get_type(builder),
|
||||||
|
ShiftRightArithmetic(lhs, _) => lhs.get_type(builder),
|
||||||
|
ShiftLeft(lhs, _) => lhs.get_type(builder),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cast_to(&self, builder: &Builder, ty: &Type) -> CompileResult<Instr> {
|
||||||
|
self.get_type(builder)?
|
||||||
|
.cast_instruction(*self, &ty)
|
||||||
|
.ok_or(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
1202
reid-llvm-lib/src/compile.rs
Normal file
1202
reid-llvm-lib/src/compile.rs
Normal file
File diff suppressed because it is too large
Load Diff
402
reid-llvm-lib/src/debug_information.rs
Normal file
402
reid-llvm-lib/src/debug_information.rs
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
use std::{
|
||||||
|
cell::{Ref, RefCell, RefMut},
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::builder::InstructionValue;
|
||||||
|
|
||||||
|
/// Represents 1. the compilation context, 2. subprogram or 3. a lexical scope
|
||||||
|
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct DebugScopeValue(pub Vec<usize>);
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct DebugLocationValue(pub DebugScopeValue, pub usize);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
|
pub struct DebugTypeValue(pub usize);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
|
pub struct DebugMetadataValue(pub usize);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DebugFileData {
|
||||||
|
pub name: String,
|
||||||
|
pub directory: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct DebugScopeHolder {
|
||||||
|
pub(crate) value: DebugScopeValue,
|
||||||
|
pub(crate) data: DebugScopeData,
|
||||||
|
pub(crate) inner_scopes: Vec<DebugScopeHolder>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DebugMetadataHolder {
|
||||||
|
pub(crate) location: DebugLocation,
|
||||||
|
pub(crate) value: DebugMetadataValue,
|
||||||
|
pub(crate) data: DebugMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DebugTypeHolder {
|
||||||
|
pub(crate) value: DebugTypeValue,
|
||||||
|
pub(crate) data: DebugTypeData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct DebugLocationHolder {
|
||||||
|
pub(crate) scope: DebugScopeValue,
|
||||||
|
pub(crate) value: DebugLocationValue,
|
||||||
|
pub(crate) location: DebugLocation,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DebugInformation {
|
||||||
|
pub file: DebugFileData,
|
||||||
|
scope: Rc<RefCell<DebugScopeHolder>>,
|
||||||
|
locations: Rc<RefCell<Vec<DebugLocationHolder>>>,
|
||||||
|
metadata: Rc<RefCell<Vec<DebugMetadataHolder>>>,
|
||||||
|
types: Rc<RefCell<Vec<DebugTypeHolder>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugInformation {
|
||||||
|
pub fn from_file(file: DebugFileData) -> (DebugInformation, DebugScopeValue) {
|
||||||
|
let scope_value = DebugScopeValue(Vec::new());
|
||||||
|
(
|
||||||
|
DebugInformation {
|
||||||
|
file,
|
||||||
|
scope: Rc::new(RefCell::new(DebugScopeHolder {
|
||||||
|
value: scope_value.clone(),
|
||||||
|
inner_scopes: Vec::new(),
|
||||||
|
data: DebugScopeData {
|
||||||
|
parent: None,
|
||||||
|
location: Some(DebugLocation {
|
||||||
|
scope: DebugScopeValue(Vec::new()),
|
||||||
|
pos: DebugPosition { line: 0, column: 0 },
|
||||||
|
}),
|
||||||
|
kind: DebugScopeKind::CodegenContext,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
locations: Rc::new(RefCell::new(Vec::new())),
|
||||||
|
metadata: Rc::new(RefCell::new(Vec::new())),
|
||||||
|
types: Rc::new(RefCell::new(Vec::new())),
|
||||||
|
},
|
||||||
|
scope_value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner_scope(&self, parent: &DebugScopeValue, location: DebugLocation) -> DebugScopeValue {
|
||||||
|
unsafe {
|
||||||
|
let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| {
|
||||||
|
for i in &parent.0 {
|
||||||
|
v = v.inner_scopes.get_unchecked_mut(*i);
|
||||||
|
}
|
||||||
|
v
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut arr = parent.0.clone();
|
||||||
|
arr.push(parent.0.len());
|
||||||
|
let value = DebugScopeValue(arr);
|
||||||
|
|
||||||
|
outer_scope.inner_scopes.push(DebugScopeHolder {
|
||||||
|
value: value.clone(),
|
||||||
|
inner_scopes: Vec::new(),
|
||||||
|
data: DebugScopeData {
|
||||||
|
parent: Some(parent.clone()),
|
||||||
|
location: Some(location),
|
||||||
|
kind: DebugScopeKind::LexicalScope,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn location(&self, scope_value: &DebugScopeValue, location: DebugLocation) -> DebugLocationValue {
|
||||||
|
let value = DebugLocationValue(scope_value.clone(), self.locations.borrow().len());
|
||||||
|
let location = DebugLocationHolder {
|
||||||
|
scope: scope_value.clone(),
|
||||||
|
value: value.clone(),
|
||||||
|
location,
|
||||||
|
};
|
||||||
|
self.locations.borrow_mut().push(location);
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug_type(&self, kind: DebugTypeData) -> DebugTypeValue {
|
||||||
|
let mut types = self.types.borrow_mut();
|
||||||
|
let value = DebugTypeValue(types.len());
|
||||||
|
types.push(DebugTypeHolder {
|
||||||
|
value: value.clone(),
|
||||||
|
data: kind,
|
||||||
|
});
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn metadata(&self, location: &DebugLocation, kind: DebugMetadata) -> DebugMetadataValue {
|
||||||
|
let mut metadata = self.metadata.borrow_mut();
|
||||||
|
let value = DebugMetadataValue(metadata.len());
|
||||||
|
metadata.push(DebugMetadataHolder {
|
||||||
|
location: location.clone(),
|
||||||
|
value: value.clone(),
|
||||||
|
data: kind,
|
||||||
|
});
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subprogram(&self, parent: DebugScopeValue, kind: DebugSubprogramData) -> DebugScopeValue {
|
||||||
|
unsafe {
|
||||||
|
let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| {
|
||||||
|
for i in &parent.0 {
|
||||||
|
v = v.inner_scopes.get_unchecked_mut(*i);
|
||||||
|
}
|
||||||
|
v
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut arr = parent.0.clone();
|
||||||
|
arr.push(outer_scope.inner_scopes.len());
|
||||||
|
let value = DebugScopeValue(arr);
|
||||||
|
|
||||||
|
outer_scope.inner_scopes.push(DebugScopeHolder {
|
||||||
|
value: value.clone(),
|
||||||
|
inner_scopes: Vec::new(),
|
||||||
|
data: DebugScopeData {
|
||||||
|
parent: Some(parent.clone()),
|
||||||
|
location: None,
|
||||||
|
kind: DebugScopeKind::Subprogram(kind),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_metadata(&self, value: DebugMetadataValue) -> DebugMetadata {
|
||||||
|
unsafe { self.metadata.borrow().get_unchecked(value.0).data.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_metadata_location(&self, value: DebugMetadataValue) -> DebugLocation {
|
||||||
|
unsafe { self.metadata.borrow().get_unchecked(value.0).location.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_scope_data(&self, value: &DebugScopeValue) -> Option<DebugScopeData> {
|
||||||
|
let scope = Ref::filter_map(self.scope.borrow(), |v: &DebugScopeHolder| {
|
||||||
|
let mut opt = Some(v);
|
||||||
|
for i in &value.0 {
|
||||||
|
if let Some(inner) = opt {
|
||||||
|
opt = inner.inner_scopes.get(*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opt
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Ok(scope) = scope {
|
||||||
|
Some(scope.data.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type_data(&self, value: DebugTypeValue) -> DebugTypeData {
|
||||||
|
unsafe { self.types.borrow().get_unchecked(value.0).data.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_location(&self, value: &DebugLocationValue) -> DebugLocation {
|
||||||
|
unsafe { self.locations.borrow().get_unchecked(value.1).location.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_metadatas(&self) -> Rc<RefCell<Vec<DebugMetadataHolder>>> {
|
||||||
|
self.metadata.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_scope(&self) -> Rc<RefCell<DebugScopeHolder>> {
|
||||||
|
self.scope.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_types(&self) -> Rc<RefCell<Vec<DebugTypeHolder>>> {
|
||||||
|
self.types.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_locations(&self) -> Rc<RefCell<Vec<DebugLocationHolder>>> {
|
||||||
|
self.locations.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DebugLocation {
|
||||||
|
pub scope: DebugScopeValue,
|
||||||
|
pub pos: DebugPosition,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct DebugPosition {
|
||||||
|
pub line: u32,
|
||||||
|
pub column: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum DebugMetadata {
|
||||||
|
ParamVar(DebugParamVariable),
|
||||||
|
LocalVar(DebugLocalVariable),
|
||||||
|
VarAssignment,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DebugParamVariable {
|
||||||
|
pub name: String,
|
||||||
|
/// the index (starting from 1) of this variable in the subprogram
|
||||||
|
/// parameters. arg_idx should not conflict with other parameters of the
|
||||||
|
/// same subprogram.
|
||||||
|
pub arg_idx: u32,
|
||||||
|
pub ty: DebugTypeValue,
|
||||||
|
/// If this variable will be referenced from its containing subprogram, and
|
||||||
|
/// will survive some optimizations.
|
||||||
|
pub always_preserve: bool,
|
||||||
|
pub flags: DwarfFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DebugLocalVariable {
|
||||||
|
pub name: String,
|
||||||
|
pub ty: DebugTypeValue,
|
||||||
|
pub always_preserve: bool,
|
||||||
|
pub flags: DwarfFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DebugSubprogramOptionals {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
scope_line: 0,
|
||||||
|
is_local: false,
|
||||||
|
is_definition: true,
|
||||||
|
is_optimized: false,
|
||||||
|
flags: DwarfFlags,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DwarfFlags;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum DebugTypeData {
|
||||||
|
Basic(DebugBasicType),
|
||||||
|
Subprogram(DebugSubprogramType),
|
||||||
|
Pointer(DebugPointerType),
|
||||||
|
Array(DebugArrayType),
|
||||||
|
Struct(DebugStructType),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DebugBasicType {
|
||||||
|
pub name: String,
|
||||||
|
/// Size of the type.
|
||||||
|
pub size_bits: u64,
|
||||||
|
/// DWARF encoding code, e.g., dwarf::DW_ATE_float.
|
||||||
|
pub encoding: DwarfEncoding,
|
||||||
|
/// Optional DWARF attributes, e.g., DW_AT_endianity.
|
||||||
|
pub flags: DwarfFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DebugArrayType {
|
||||||
|
pub size_bits: u64,
|
||||||
|
pub align_bits: u32,
|
||||||
|
pub element_type: DebugTypeValue,
|
||||||
|
pub length: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DebugPointerType {
|
||||||
|
pub name: String,
|
||||||
|
pub pointee: DebugTypeValue,
|
||||||
|
pub size_bits: u64,
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DebugStructType {
|
||||||
|
pub name: String,
|
||||||
|
pub scope: DebugScopeValue,
|
||||||
|
pub pos: Option<DebugPosition>,
|
||||||
|
pub size_bits: u64,
|
||||||
|
pub flags: DwarfFlags,
|
||||||
|
pub fields: Vec<DebugFieldType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DebugFieldType {
|
||||||
|
pub name: String,
|
||||||
|
pub scope: DebugScopeValue,
|
||||||
|
pub pos: Option<DebugPosition>,
|
||||||
|
pub size_bits: u64,
|
||||||
|
pub offset: u64,
|
||||||
|
pub flags: DwarfFlags,
|
||||||
|
pub ty: DebugTypeValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DebugSubprogramType {
|
||||||
|
pub parameters: Vec<DebugTypeValue>,
|
||||||
|
pub flags: DwarfFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum DwarfEncoding {
|
||||||
|
Address = 1,
|
||||||
|
Boolean = 2,
|
||||||
|
Float = 4,
|
||||||
|
Signed = 5,
|
||||||
|
SignedChar = 6,
|
||||||
|
Unsigned = 7,
|
||||||
|
UnsignedChar = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DebugScopeData {
|
||||||
|
pub parent: Option<DebugScopeValue>,
|
||||||
|
pub location: Option<DebugLocation>,
|
||||||
|
pub kind: DebugScopeKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum DebugScopeKind {
|
||||||
|
CodegenContext,
|
||||||
|
LexicalScope,
|
||||||
|
Subprogram(DebugSubprogramData),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DebugSubprogramData {
|
||||||
|
/// Function name.
|
||||||
|
pub name: String,
|
||||||
|
pub outer_scope: DebugScopeValue,
|
||||||
|
/// Used for line number.
|
||||||
|
pub location: DebugLocation,
|
||||||
|
/// Function type.
|
||||||
|
pub ty: DebugTypeValue,
|
||||||
|
pub opts: DebugSubprogramOptionals,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DebugSubprogramOptionals {
|
||||||
|
/// Set to the beginning of the scope this starts
|
||||||
|
pub scope_line: u32,
|
||||||
|
pub is_local: bool,
|
||||||
|
pub is_definition: bool,
|
||||||
|
pub is_optimized: bool,
|
||||||
|
/// These flags are used to emit dwarf attributes. e.g. is this function
|
||||||
|
/// prototyped or not.
|
||||||
|
pub flags: DwarfFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct InstructionDebugRecordData {
|
||||||
|
pub scope: DebugScopeValue,
|
||||||
|
pub variable: DebugMetadataValue,
|
||||||
|
pub location: DebugLocation,
|
||||||
|
pub kind: DebugRecordKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum DebugRecordKind {
|
||||||
|
Declare(InstructionValue),
|
||||||
|
Value(InstructionValue),
|
||||||
|
}
|
||||||
593
reid-llvm-lib/src/fmt.rs
Normal file
593
reid-llvm-lib/src/fmt.rs
Normal file
@ -0,0 +1,593 @@
|
|||||||
|
//! Debug implementations for relevant types
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fmt::{Debug, Display, Write},
|
||||||
|
marker::PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
CmpPredicate, Context, Instr, InstructionData, TerminatorKind,
|
||||||
|
builder::*,
|
||||||
|
debug_information::{
|
||||||
|
DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocalVariable, DebugLocation,
|
||||||
|
DebugLocationValue, DebugMetadata, DebugMetadataValue, DebugParamVariable, DebugPointerType, DebugPosition,
|
||||||
|
DebugRecordKind, DebugScopeValue, DebugStructType, DebugSubprogramType, DebugTypeData, DebugTypeHolder,
|
||||||
|
DebugTypeValue,
|
||||||
|
},
|
||||||
|
pad_adapter::PadAdapter,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Display for Context {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
Display::fmt(&self.builder, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Builder {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(f, "Producer: {}", self.producer)?;
|
||||||
|
for module in self.modules.borrow().iter() {
|
||||||
|
if module.data.is_main {
|
||||||
|
write!(f, "main ")?;
|
||||||
|
}
|
||||||
|
writeln!(f, "{} ({:?}) {{", module.data.name, module.value)?;
|
||||||
|
for function in &module.functions {
|
||||||
|
let mut state = Default::default();
|
||||||
|
let mut inner = PadAdapter::wrap(f, &mut state);
|
||||||
|
function.builder_fmt(&mut inner, self, &module.debug_information)?;
|
||||||
|
}
|
||||||
|
writeln!(f, "}}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionHolder {
|
||||||
|
fn builder_fmt(
|
||||||
|
&self,
|
||||||
|
f: &mut impl std::fmt::Write,
|
||||||
|
builder: &Builder,
|
||||||
|
debug: &Option<DebugInformation>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
if self.data.flags.is_imported {
|
||||||
|
write!(f, "imported ")?;
|
||||||
|
}
|
||||||
|
if self.data.flags.is_extern {
|
||||||
|
write!(f, "extern ")?;
|
||||||
|
}
|
||||||
|
if self.data.flags.is_pub {
|
||||||
|
write!(f, "pub ")?;
|
||||||
|
}
|
||||||
|
if self.data.flags.is_main {
|
||||||
|
write!(f, "main ")?;
|
||||||
|
}
|
||||||
|
let params = self
|
||||||
|
.data
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.map(|p| format!("{:?}", p))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
write!(f, "fn {}({}) -> {:?} ", self.data.name, params, self.data.ret)?;
|
||||||
|
|
||||||
|
writeln!(f, "{{")?;
|
||||||
|
let mut state = Default::default();
|
||||||
|
let mut inner = PadAdapter::wrap(f, &mut state);
|
||||||
|
writeln!(inner, "(Value = {:?}) ", self.value)?;
|
||||||
|
if let Some(debug) = &self.debug_info {
|
||||||
|
writeln!(inner, "(Debug = {:?})", debug)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for block in &self.blocks {
|
||||||
|
let mut state = Default::default();
|
||||||
|
let mut inner = PadAdapter::wrap(&mut inner, &mut state);
|
||||||
|
block.builder_fmt(&mut inner, builder, debug)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(f, "}}")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockHolder {
|
||||||
|
fn builder_fmt(
|
||||||
|
&self,
|
||||||
|
f: &mut impl std::fmt::Write,
|
||||||
|
builder: &Builder,
|
||||||
|
debug: &Option<DebugInformation>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
if self.data.deleted {
|
||||||
|
write!(f, "deleted ")?;
|
||||||
|
}
|
||||||
|
writeln!(f, "{} ({:?}):", self.data.name, self.value)?;
|
||||||
|
|
||||||
|
let mut state = Default::default();
|
||||||
|
let mut inner = PadAdapter::wrap(f, &mut state);
|
||||||
|
|
||||||
|
for instr in &self.instructions {
|
||||||
|
instr.builder_fmt(&mut inner, builder, debug)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(terminator) = &self.data.terminator {
|
||||||
|
terminator.builder_fmt(&mut inner, builder, debug)?;
|
||||||
|
}
|
||||||
|
if let Some(location) = &self.data.terminator_location {
|
||||||
|
writeln!(inner, " ^ (At {}) ", debug.as_ref().unwrap().get_location(location))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstructionHolder {
|
||||||
|
fn builder_fmt(
|
||||||
|
&self,
|
||||||
|
f: &mut impl std::fmt::Write,
|
||||||
|
_builder: &Builder,
|
||||||
|
debug: &Option<DebugInformation>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
if let Some(record) = &self.record {
|
||||||
|
let kind = match record.kind {
|
||||||
|
DebugRecordKind::Declare(instruction_value) => {
|
||||||
|
format!("= {:?} (Assign)", instruction_value)
|
||||||
|
}
|
||||||
|
DebugRecordKind::Value(instruction_value) => {
|
||||||
|
format!("= {:?} (Value)", instruction_value)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(debug) = debug {
|
||||||
|
writeln!(f, " (Debug {} {})", record.variable.hr(debug), kind)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(f, "{:?} ({}) = {:?} ", self.value, self.name, self.data.kind)?;
|
||||||
|
if let Some(debug) = debug {
|
||||||
|
if let Some(location) = &self.data.location {
|
||||||
|
writeln!(f, " ^ (At {}) ", debug.get_location(location))?;
|
||||||
|
}
|
||||||
|
if let Some(meta) = self.data.meta {
|
||||||
|
writeln!(f, " ^ (Meta {}) ", meta.hr(debug))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TerminatorKind {
|
||||||
|
fn builder_fmt(
|
||||||
|
&self,
|
||||||
|
f: &mut impl std::fmt::Write,
|
||||||
|
_builder: &Builder,
|
||||||
|
_debug: &Option<DebugInformation>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
TerminatorKind::Ret(instr) => writeln!(f, "ret {:?}", instr),
|
||||||
|
TerminatorKind::RetVoid => writeln!(f, "ret void"),
|
||||||
|
TerminatorKind::Br(block) => writeln!(f, "br {:?}", block),
|
||||||
|
TerminatorKind::CondBr(instr, lhs, rhs) => {
|
||||||
|
writeln!(f, "condbr {:?}, {:?} or {:?}", instr, lhs, rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugMetadataValue {
|
||||||
|
fn hr(&self, debug: &DebugInformation) -> String {
|
||||||
|
let kind = match debug.get_metadata(*self) {
|
||||||
|
DebugMetadata::ParamVar(DebugParamVariable { name, arg_idx, ty, .. }) => {
|
||||||
|
format!("param {} (idx {}) (type {:?}) ", name, arg_idx, ty)
|
||||||
|
}
|
||||||
|
DebugMetadata::LocalVar(DebugLocalVariable { name, ty, .. }) => {
|
||||||
|
format!("var {} (type {:?}) ", name, ty)
|
||||||
|
}
|
||||||
|
DebugMetadata::VarAssignment => todo!(),
|
||||||
|
};
|
||||||
|
format!("{} at {}", kind, debug.get_metadata_location(*self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for DebugLocation {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:?} on scope {:?}", self.pos, self.scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for DebugPosition {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "line {}, col {}", self.line, self.column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Builder {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_list().entries(self.get_modules().borrow().iter());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PrintableModule<'ctx> {
|
||||||
|
pub phantom: PhantomData<&'ctx ()>,
|
||||||
|
pub module: ModuleHolder,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> Debug for PrintableModule<'ctx> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
Debug::fmt(&self.module, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for ModuleHolder {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_tuple(&format!("{}({:#?}) ", self.data.name, self.value))
|
||||||
|
.field(&self.functions)
|
||||||
|
// .field(&self.debug_information)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for FunctionHolder {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_tuple(&format!(
|
||||||
|
"{}({:?}) -> {:?} ",
|
||||||
|
self.data.name, self.data.params, self.data.ret
|
||||||
|
))
|
||||||
|
.field(&self.blocks)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for BlockHolder {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let deleted = if self.data.deleted { " (deleted)" } else { "" };
|
||||||
|
f.debug_tuple(&format!("{}[{:?}]{} ", &self.data.name, &self.value, deleted))
|
||||||
|
.field(&self.instructions)
|
||||||
|
.field(&self.data.terminator)
|
||||||
|
.field(&self.data.terminator_location)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for InstructionHolder {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.value.fmt(f)?;
|
||||||
|
write!(f, " ({})", self.name)?;
|
||||||
|
f.write_str(" = ")?;
|
||||||
|
self.data.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for InstructionData {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.kind.fmt(f)?;
|
||||||
|
if let Some(location) = &self.location {
|
||||||
|
write!(f, " ({:?})", location)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for ModuleValue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "M[{:0>2}]", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for FunctionValue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "F[{:0>2}-{:0>2}]", &self.0.0, self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for BlockValue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "B[{:0>2}-{:0>2}-{:0>2}]", &self.0.0.0, &self.0.1, self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for InstructionValue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "%{}.{}.{}.{}", self.0.0.0.0, self.0.0.1, self.0.1, self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl Debug for InstructionValue {
|
||||||
|
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
// write!(
|
||||||
|
// f,
|
||||||
|
// "I[{:0>2}-{:0>2}-{:0>2}-{:0>2}]",
|
||||||
|
// &self.0.0.0.0, &self.0.0.1, &self.0.1, self.1
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
impl Debug for TypeValue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Ty[{:0>2}-{:0>2}]", &self.0.0, self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Instr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Instr::Param(nth) => fmt_call(f, &"Param", &nth),
|
||||||
|
Instr::Constant(c) => c.fmt(f),
|
||||||
|
Instr::Add(lhs, rhs) => fmt_binop(f, lhs, &"+", rhs),
|
||||||
|
Instr::FAdd(lhs, rhs) => fmt_binop(f, lhs, &"+", rhs),
|
||||||
|
Instr::Sub(lhs, rhs) => fmt_binop(f, lhs, &"-", rhs),
|
||||||
|
Instr::FSub(lhs, rhs) => fmt_binop(f, lhs, &"-", rhs),
|
||||||
|
Instr::Mul(lhs, rhs) => fmt_binop(f, lhs, &"*", rhs),
|
||||||
|
Instr::FMul(lhs, rhs) => fmt_binop(f, lhs, &"*", rhs),
|
||||||
|
Instr::UDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs),
|
||||||
|
Instr::SDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs),
|
||||||
|
Instr::FDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs),
|
||||||
|
Instr::URem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs),
|
||||||
|
Instr::SRem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs),
|
||||||
|
Instr::FRem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs),
|
||||||
|
Instr::And(lhs, rhs) => fmt_binop(f, lhs, &"&&", rhs),
|
||||||
|
Instr::Phi(val) => fmt_call(f, &"Phi", &val),
|
||||||
|
Instr::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs),
|
||||||
|
Instr::FCmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs),
|
||||||
|
Instr::FunctionCall(fun, params) => fmt_call(f, fun, params),
|
||||||
|
Instr::Alloca(ty) => write!(f, "alloca<{:?}>", ty),
|
||||||
|
Instr::Load(val, ty) => write!(f, "load<{:?}>({:?})", ty, val),
|
||||||
|
Instr::Store(ptr, val) => write!(f, "store({:?} = {:?})", ptr, val),
|
||||||
|
Instr::ArrayAlloca(ty, instruction_value) => {
|
||||||
|
write!(f, "array_alloca<{:?}>({:?})", ty, instruction_value)
|
||||||
|
}
|
||||||
|
Instr::GetElemPtr(instruction_value, items) => fmt_index(
|
||||||
|
f,
|
||||||
|
instruction_value,
|
||||||
|
&items
|
||||||
|
.iter()
|
||||||
|
.map(|expr| format!("{:?}", expr))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", "),
|
||||||
|
),
|
||||||
|
Instr::GetStructElemPtr(instruction_value, index) => {
|
||||||
|
write!(f, "GEP(")?;
|
||||||
|
fmt_index(f, instruction_value, &index.to_string())?;
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
Instr::ExtractValue(instruction_value, index) => fmt_index(f, instruction_value, &index.to_string()),
|
||||||
|
Instr::Trunc(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::ZExt(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::SExt(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::FPTrunc(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::FPExt(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::FPToUI(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::FPToSI(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::UIToFP(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::SIToFP(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::PtrToInt(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::IntToPtr(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::BitCast(instr_val, ty) => {
|
||||||
|
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
|
||||||
|
}
|
||||||
|
Instr::Or(lhs, rhs) => fmt_binop(f, lhs, &"||", rhs),
|
||||||
|
Instr::XOr(lhs, rhs) => fmt_binop(f, lhs, &"^", rhs),
|
||||||
|
Instr::ShiftRightLogical(lhs, rhs) => fmt_binop(f, lhs, &">>l", rhs),
|
||||||
|
Instr::ShiftRightArithmetic(lhs, rhs) => fmt_binop(f, lhs, &">>a", rhs),
|
||||||
|
Instr::ShiftLeft(lhs, rhs) => fmt_binop(f, lhs, &"<<", rhs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_binop(
|
||||||
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
|
lhs: &impl std::fmt::Debug,
|
||||||
|
op: &impl std::fmt::Debug,
|
||||||
|
rhs: &impl std::fmt::Debug,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
lhs.fmt(f)?;
|
||||||
|
f.write_char(' ')?;
|
||||||
|
op.fmt(f)?;
|
||||||
|
f.write_char(' ')?;
|
||||||
|
rhs.fmt(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_call(
|
||||||
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
|
fun: &impl std::fmt::Debug,
|
||||||
|
params: &impl std::fmt::Debug,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
fun.fmt(f)?;
|
||||||
|
f.write_char('(')?;
|
||||||
|
params.fmt(f)?;
|
||||||
|
f.write_char(')')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_index(
|
||||||
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
|
fun: &impl std::fmt::Debug,
|
||||||
|
params: &impl std::fmt::Debug,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
fun.fmt(f)?;
|
||||||
|
f.write_char('[')?;
|
||||||
|
params.fmt(f)?;
|
||||||
|
f.write_char(']')
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for CmpPredicate {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::LT => write!(f, "<"),
|
||||||
|
Self::GT => write!(f, ">"),
|
||||||
|
Self::LE => write!(f, "<="),
|
||||||
|
Self::GE => write!(f, ">="),
|
||||||
|
Self::EQ => write!(f, "=="),
|
||||||
|
Self::NE => write!(f, "!="),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for TerminatorKind {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Ret(val) => {
|
||||||
|
write!(f, "Ret ")?;
|
||||||
|
val.fmt(f)
|
||||||
|
}
|
||||||
|
Self::RetVoid => write!(f, "Void Ret"),
|
||||||
|
Self::Br(val) => {
|
||||||
|
write!(f, "Br ")?;
|
||||||
|
val.fmt(f)
|
||||||
|
}
|
||||||
|
Self::CondBr(cond, b1, b2) => {
|
||||||
|
write!(f, "CondBr ")?;
|
||||||
|
cond.fmt(f)?;
|
||||||
|
write!(f, " ? ")?;
|
||||||
|
b1.fmt(f)?;
|
||||||
|
write!(f, " : ")?;
|
||||||
|
b2.fmt(f)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugTypeHolder {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_tuple(&format!("DebugTypeHolder {:?}", self.value))
|
||||||
|
.field(&self.data)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugTypeData {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
DebugTypeData::Basic(ty) => Debug::fmt(ty, f),
|
||||||
|
DebugTypeData::Subprogram(ty) => Debug::fmt(ty, f),
|
||||||
|
DebugTypeData::Pointer(ty) => Debug::fmt(ty, f),
|
||||||
|
DebugTypeData::Array(ty) => Debug::fmt(ty, f),
|
||||||
|
DebugTypeData::Struct(ty) => Debug::fmt(ty, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugBasicType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_tuple("BasicType")
|
||||||
|
.field(&self.name)
|
||||||
|
.field(&self.size_bits)
|
||||||
|
.field(&self.encoding)
|
||||||
|
.field(&self.flags)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugStructType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Struct")
|
||||||
|
.field("name", &self.name)
|
||||||
|
.field("scope", &self.scope)
|
||||||
|
.field("pos", &self.pos)
|
||||||
|
.field("size_bit", &self.size_bits)
|
||||||
|
.field("flags", &self.flags)
|
||||||
|
.field("elements", &self.fields)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugFieldType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct(&format!("Field({})", self.name))
|
||||||
|
.field("scope", &self.scope)
|
||||||
|
.field("pos", &self.pos)
|
||||||
|
.field("size_bits", &self.size_bits)
|
||||||
|
.field("offset", &self.offset)
|
||||||
|
.field("flags", &self.flags)
|
||||||
|
.field("ty", &self.ty)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugSubprogramType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_tuple("Subprogram")
|
||||||
|
.field(&self.parameters)
|
||||||
|
.field(&self.flags)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugPointerType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_tuple(&format!("Pointer<{:?}>({})", self.pointee, self.name))
|
||||||
|
.field(&self.size_bits)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugArrayType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct(&format!("Array<{:?}>[{}]", self.element_type, self.length))
|
||||||
|
.field("size_bits", &self.size_bits)
|
||||||
|
.field("align_bits", &self.align_bits)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugMetadataValue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Meta[{}]", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugScopeValue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Scope[{}]",
|
||||||
|
self.0.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugTypeValue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Type[{}]", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugLocationValue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Value[{:?}][{}]", self.0, self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugLocation {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:?} on scope {:?}", self.pos, self.scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for DebugPosition {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "ln {}, col {}", self.line, self.column)
|
||||||
|
}
|
||||||
|
}
|
||||||
660
reid-llvm-lib/src/lib.rs
Normal file
660
reid-llvm-lib/src/lib.rs
Normal file
@ -0,0 +1,660 @@
|
|||||||
|
//! Reid LLVM Lib is an ergonomic Rust'y API which is used to produce a
|
||||||
|
//! Low-Level IR (LLIR) using [`Context`] and [`Builder`]. This Builder can then
|
||||||
|
//! be used at the end to compile said LLIR into LLVM IR.
|
||||||
|
|
||||||
|
use std::{fmt::Debug, marker::PhantomData};
|
||||||
|
|
||||||
|
use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, TypeValue};
|
||||||
|
use debug_information::{DebugFileData, DebugInformation, DebugLocationValue, DebugMetadataValue};
|
||||||
|
use fmt::PrintableModule;
|
||||||
|
|
||||||
|
use crate::debug_information::DebugScopeValue;
|
||||||
|
|
||||||
|
pub mod builder;
|
||||||
|
pub mod compile;
|
||||||
|
pub mod debug_information;
|
||||||
|
mod fmt;
|
||||||
|
mod pad_adapter;
|
||||||
|
mod util;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)]
|
||||||
|
pub enum ErrorKind {
|
||||||
|
#[error("NULL error, should never occur!")]
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CompileResult<T> = Result<T, ErrorKind>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Context {
|
||||||
|
builder: Builder,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
pub fn new<T: Into<String>>(producer: T) -> Context {
|
||||||
|
Context {
|
||||||
|
builder: Builder::new(producer.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn module<'ctx>(&'ctx self, name: &str, main: bool) -> Module<'ctx> {
|
||||||
|
let value = self.builder.add_module(ModuleData {
|
||||||
|
name: name.to_owned(),
|
||||||
|
is_main: main,
|
||||||
|
});
|
||||||
|
Module {
|
||||||
|
phantom: PhantomData,
|
||||||
|
builder: self.builder.clone(),
|
||||||
|
value,
|
||||||
|
debug_info: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct ModuleData {
|
||||||
|
name: String,
|
||||||
|
is_main: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Module<'ctx> {
|
||||||
|
phantom: PhantomData<&'ctx ()>,
|
||||||
|
builder: Builder,
|
||||||
|
value: ModuleValue,
|
||||||
|
debug_info: Option<DebugInformation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> Module<'ctx> {
|
||||||
|
pub fn function(&self, name: &str, ret: Type, params: Vec<Type>, flags: FunctionFlags) -> Function<'ctx> {
|
||||||
|
unsafe {
|
||||||
|
Function {
|
||||||
|
phantom: PhantomData,
|
||||||
|
builder: self.builder.clone(),
|
||||||
|
value: self.builder.add_function(
|
||||||
|
&self.value,
|
||||||
|
FunctionData {
|
||||||
|
name: name.to_owned(),
|
||||||
|
ret,
|
||||||
|
params,
|
||||||
|
flags,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn custom_type(&self, ty: CustomTypeKind) -> TypeValue {
|
||||||
|
unsafe {
|
||||||
|
let (name, kind) = match &ty {
|
||||||
|
CustomTypeKind::NamedStruct(NamedStruct(name, _)) => (name.clone(), ty),
|
||||||
|
};
|
||||||
|
self.builder.add_type(&self.value, TypeData { name, kind })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> ModuleValue {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_printable(&self) -> PrintableModule<'ctx> {
|
||||||
|
PrintableModule {
|
||||||
|
phantom: PhantomData,
|
||||||
|
module: self.builder.find_module(self.value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_debug_info(&mut self, file: DebugFileData) -> (DebugInformation, DebugScopeValue) {
|
||||||
|
let (debug_info, scope_value) = DebugInformation::from_file(file);
|
||||||
|
self.debug_info = Some(debug_info.clone());
|
||||||
|
(debug_info, scope_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_debug_info(&self) -> &Option<DebugInformation> {
|
||||||
|
&self.debug_info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> Drop for Module<'ctx> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(debug_info) = self.debug_info.take() {
|
||||||
|
self.builder.set_debug_information(&self.value, debug_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct FunctionData {
|
||||||
|
name: String,
|
||||||
|
ret: Type,
|
||||||
|
params: Vec<Type>,
|
||||||
|
flags: FunctionFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Hash)]
|
||||||
|
pub struct FunctionFlags {
|
||||||
|
/// True in the destination module of the import, false in the source module.
|
||||||
|
pub is_extern: bool,
|
||||||
|
/// Whether this function is the main function of the module, that should be
|
||||||
|
/// executed (and linked externally also).
|
||||||
|
pub is_main: bool,
|
||||||
|
/// Whether this function should be available externally always.
|
||||||
|
pub is_pub: bool,
|
||||||
|
/// If this function is an imported function (either in the source or
|
||||||
|
/// destination module)
|
||||||
|
pub is_imported: bool,
|
||||||
|
/// Whether this function should add "alwaysinline"-attribute.
|
||||||
|
pub inline: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FunctionFlags {
|
||||||
|
fn default() -> FunctionFlags {
|
||||||
|
FunctionFlags {
|
||||||
|
is_extern: false,
|
||||||
|
is_main: false,
|
||||||
|
is_pub: false,
|
||||||
|
is_imported: false,
|
||||||
|
inline: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Function<'ctx> {
|
||||||
|
phantom: PhantomData<&'ctx ()>,
|
||||||
|
builder: Builder,
|
||||||
|
value: FunctionValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> Function<'ctx> {
|
||||||
|
pub fn block(&self, name: &str) -> Block<'ctx> {
|
||||||
|
unsafe {
|
||||||
|
Block {
|
||||||
|
phantom: PhantomData,
|
||||||
|
builder: self.builder.clone(),
|
||||||
|
value: self.builder.add_block(
|
||||||
|
&self.value,
|
||||||
|
BlockData {
|
||||||
|
name: name.to_owned(),
|
||||||
|
terminator: None,
|
||||||
|
terminator_location: None,
|
||||||
|
deleted: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_debug(&self, subprogram: DebugScopeValue) {
|
||||||
|
unsafe {
|
||||||
|
self.builder.set_debug_subprogram(&self.value, subprogram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> FunctionValue {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct BlockData {
|
||||||
|
name: String,
|
||||||
|
terminator: Option<TerminatorKind>,
|
||||||
|
terminator_location: Option<DebugLocationValue>,
|
||||||
|
deleted: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Block<'builder> {
|
||||||
|
phantom: PhantomData<&'builder ()>,
|
||||||
|
builder: Builder,
|
||||||
|
value: BlockValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instr {
|
||||||
|
pub fn default_name(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Instr::Param(_) => "param",
|
||||||
|
Instr::Constant(_) => "const1",
|
||||||
|
Instr::Add(..) => "add",
|
||||||
|
Instr::FAdd(..) => "fadd",
|
||||||
|
Instr::Sub(..) => "sub",
|
||||||
|
Instr::FSub(..) => "fsub",
|
||||||
|
Instr::Mul(..) => "mul",
|
||||||
|
Instr::FMul(..) => "fmul",
|
||||||
|
Instr::UDiv(..) => "udiv",
|
||||||
|
Instr::SDiv(..) => "sdiv",
|
||||||
|
Instr::FDiv(..) => "fdiv",
|
||||||
|
Instr::URem(..) => "urem",
|
||||||
|
Instr::SRem(..) => "srem",
|
||||||
|
Instr::FRem(..) => "frem",
|
||||||
|
Instr::And(..) => "and",
|
||||||
|
Instr::Phi(_) => "phi",
|
||||||
|
Instr::Alloca(_) => "alloca",
|
||||||
|
Instr::Load(_, _) => "load",
|
||||||
|
Instr::Store(..) => "store",
|
||||||
|
Instr::ArrayAlloca(_, _) => "arrayalloca",
|
||||||
|
Instr::GetElemPtr(..) => "getelemptr",
|
||||||
|
Instr::GetStructElemPtr(..) => "getstructelemptr",
|
||||||
|
Instr::ExtractValue(..) => "extractvalue",
|
||||||
|
Instr::ICmp(..) => "icmp",
|
||||||
|
Instr::FunctionCall(..) => "call",
|
||||||
|
Instr::FCmp(_, _, _) => "fcmp",
|
||||||
|
Instr::Trunc(_, _) => "trunc",
|
||||||
|
Instr::ZExt(_, _) => "zext",
|
||||||
|
Instr::SExt(_, _) => "sext",
|
||||||
|
Instr::FPTrunc(_, _) => "fptrunc",
|
||||||
|
Instr::FPExt(_, _) => "pfext",
|
||||||
|
Instr::FPToUI(_, _) => "fptoui",
|
||||||
|
Instr::FPToSI(_, _) => "fptosi",
|
||||||
|
Instr::UIToFP(_, _) => "uitofp",
|
||||||
|
Instr::SIToFP(_, _) => "sitofp",
|
||||||
|
Instr::PtrToInt(_, _) => "ptrtoint",
|
||||||
|
Instr::IntToPtr(_, _) => "inttoptr",
|
||||||
|
Instr::BitCast(_, _) => "bitcast",
|
||||||
|
Instr::Or(..) => "or",
|
||||||
|
Instr::XOr(..) => "xor",
|
||||||
|
Instr::ShiftRightLogical(..) => "lshr",
|
||||||
|
Instr::ShiftRightArithmetic(..) => "ashr",
|
||||||
|
Instr::ShiftLeft(..) => "shl",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'builder> Block<'builder> {
|
||||||
|
pub fn build_named<T: Into<String>>(&mut self, name: T, instruction: Instr) -> CompileResult<InstructionValue> {
|
||||||
|
unsafe {
|
||||||
|
self.builder.add_instruction(
|
||||||
|
&self.value,
|
||||||
|
InstructionData {
|
||||||
|
kind: instruction,
|
||||||
|
location: None,
|
||||||
|
meta: None,
|
||||||
|
},
|
||||||
|
name.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(&mut self, instruction: Instr) -> CompileResult<InstructionValue> {
|
||||||
|
unsafe {
|
||||||
|
let name = instruction.default_name().to_owned();
|
||||||
|
self.builder.add_instruction(
|
||||||
|
&self.value,
|
||||||
|
InstructionData {
|
||||||
|
kind: instruction,
|
||||||
|
location: None,
|
||||||
|
meta: None,
|
||||||
|
},
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_instr_location(&self, instruction: InstructionValue, location: DebugLocationValue) {
|
||||||
|
unsafe {
|
||||||
|
self.builder.add_instruction_location(&instruction, location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_instr_metadata(&self, instruction: InstructionValue, location: DebugMetadataValue) {
|
||||||
|
unsafe {
|
||||||
|
self.builder.add_instruction_metadata(&instruction, location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn terminate(&mut self, instruction: TerminatorKind) -> CompileResult<()> {
|
||||||
|
unsafe { self.builder.terminate(&self.value, instruction) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_terminator_location(&mut self, location: DebugLocationValue) -> CompileResult<()> {
|
||||||
|
unsafe { self.builder.set_terminator_location(&self.value, location) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete block if it is unused. Return true if deleted, false if not.
|
||||||
|
pub fn delete_if_unused(&mut self) -> CompileResult<bool> {
|
||||||
|
unsafe {
|
||||||
|
if !self.builder.is_block_used(self.value()) {
|
||||||
|
self.builder.delete_block(&self.value)?;
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> BlockValue {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct InstructionData {
|
||||||
|
kind: Instr,
|
||||||
|
location: Option<DebugLocationValue>,
|
||||||
|
meta: Option<DebugMetadataValue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash)]
|
||||||
|
pub enum CmpPredicate {
|
||||||
|
LT,
|
||||||
|
LE,
|
||||||
|
GT,
|
||||||
|
GE,
|
||||||
|
EQ,
|
||||||
|
NE,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://llvm.org/docs/LangRef.html#instruction-reference
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Instr {
|
||||||
|
Param(usize),
|
||||||
|
Constant(ConstValue),
|
||||||
|
|
||||||
|
/// Add two integers
|
||||||
|
Add(InstructionValue, InstructionValue),
|
||||||
|
/// Add two floats
|
||||||
|
FAdd(InstructionValue, InstructionValue),
|
||||||
|
/// Subtract two integers
|
||||||
|
Sub(InstructionValue, InstructionValue),
|
||||||
|
/// Subtract two floats
|
||||||
|
FSub(InstructionValue, InstructionValue),
|
||||||
|
/// Multiply two integers
|
||||||
|
Mul(InstructionValue, InstructionValue),
|
||||||
|
/// Multiply two floats
|
||||||
|
FMul(InstructionValue, InstructionValue),
|
||||||
|
/// Divide two unsigned integers
|
||||||
|
UDiv(InstructionValue, InstructionValue),
|
||||||
|
/// Divide two signed integers
|
||||||
|
SDiv(InstructionValue, InstructionValue),
|
||||||
|
/// Divide two floats
|
||||||
|
FDiv(InstructionValue, InstructionValue),
|
||||||
|
/// Get the remainder from two unsigned integers
|
||||||
|
URem(InstructionValue, InstructionValue),
|
||||||
|
/// Get the remainder from two signed integers
|
||||||
|
SRem(InstructionValue, InstructionValue),
|
||||||
|
/// Get the remainder from two floats
|
||||||
|
FRem(InstructionValue, InstructionValue),
|
||||||
|
|
||||||
|
And(InstructionValue, InstructionValue),
|
||||||
|
Or(InstructionValue, InstructionValue),
|
||||||
|
XOr(InstructionValue, InstructionValue),
|
||||||
|
ShiftRightLogical(InstructionValue, InstructionValue),
|
||||||
|
ShiftRightArithmetic(InstructionValue, InstructionValue),
|
||||||
|
ShiftLeft(InstructionValue, InstructionValue),
|
||||||
|
|
||||||
|
Phi(Vec<InstructionValue>),
|
||||||
|
|
||||||
|
Alloca(Type),
|
||||||
|
Load(InstructionValue, Type),
|
||||||
|
Store(InstructionValue, InstructionValue),
|
||||||
|
ArrayAlloca(Type, InstructionValue),
|
||||||
|
GetElemPtr(InstructionValue, Vec<InstructionValue>),
|
||||||
|
GetStructElemPtr(InstructionValue, u32),
|
||||||
|
ExtractValue(InstructionValue, u32),
|
||||||
|
|
||||||
|
/// Integer Comparison
|
||||||
|
ICmp(CmpPredicate, InstructionValue, InstructionValue),
|
||||||
|
/// FLoat Comparison
|
||||||
|
FCmp(CmpPredicate, InstructionValue, InstructionValue),
|
||||||
|
|
||||||
|
/// The `trunc` instruction truncates the high order bits in value and
|
||||||
|
/// converts the remaining bits to ty2. Since the source size must be larger
|
||||||
|
/// than the destination size, `trunc` cannot be a no-op cast. It will
|
||||||
|
/// always truncate bits.
|
||||||
|
Trunc(InstructionValue, Type),
|
||||||
|
/// The `zext` fills the high order bits of the value with zero bits until
|
||||||
|
/// it reaches the size of the destination type, ty2.
|
||||||
|
ZExt(InstructionValue, Type),
|
||||||
|
/// The `sext` instruction performs a sign extension by copying the sign bit
|
||||||
|
/// (highest order bit) of the value until it reaches the bit size of the
|
||||||
|
/// type ty2.
|
||||||
|
SExt(InstructionValue, Type),
|
||||||
|
/// The `fptrunc` instruction casts a value from a larger floating-point
|
||||||
|
/// type to a smaller floating-point type.
|
||||||
|
FPTrunc(InstructionValue, Type),
|
||||||
|
/// The `fpext` instruction extends the value from a smaller floating-point
|
||||||
|
/// type to a larger floating-point type.
|
||||||
|
FPExt(InstructionValue, Type),
|
||||||
|
/// The `fptoui` instruction takes a value to cast, which must be a scalar
|
||||||
|
/// or vector floating-point value, and a type to cast it to ty2, which must
|
||||||
|
/// be an integer type.
|
||||||
|
FPToUI(InstructionValue, Type),
|
||||||
|
/// The `fptosi` instruction takes a value to cast, which must be a scalar
|
||||||
|
/// or vector floating-point value, and a type to cast it to ty2, which must
|
||||||
|
/// be an integer type.
|
||||||
|
FPToSI(InstructionValue, Type),
|
||||||
|
/// The `uitofp` instruction takes a value to cast, which must be a scalar
|
||||||
|
/// or vector integer value, and a type to cast it to ty2, which must be an
|
||||||
|
/// floating-point type.
|
||||||
|
UIToFP(InstructionValue, Type),
|
||||||
|
/// The `sitofp` instruction takes a value to cast, which must be a scalar
|
||||||
|
/// or vector integer value, and a type to cast it to ty2, which must be an
|
||||||
|
/// floating-point type
|
||||||
|
SIToFP(InstructionValue, Type),
|
||||||
|
/// The `ptrtoint` instruction converts value to integer type ty2 by
|
||||||
|
/// interpreting the all pointer representation bits as an integer
|
||||||
|
/// (equivalent to a bitcast) and either truncating or zero extending that
|
||||||
|
/// value to the size of the integer type.
|
||||||
|
PtrToInt(InstructionValue, Type),
|
||||||
|
/// The `inttoptr` instruction converts value to type ty2 by applying either
|
||||||
|
/// a zero extension or a truncation depending on the size of the integer
|
||||||
|
/// value.
|
||||||
|
IntToPtr(InstructionValue, Type),
|
||||||
|
/// The `bitcast` instruction converts value to type ty2. It is always a
|
||||||
|
/// no-op cast because no bits change with this conversion.
|
||||||
|
BitCast(InstructionValue, Type),
|
||||||
|
|
||||||
|
FunctionCall(FunctionValue, Vec<InstructionValue>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
|
pub enum Type {
|
||||||
|
I8,
|
||||||
|
I16,
|
||||||
|
I32,
|
||||||
|
I64,
|
||||||
|
I128,
|
||||||
|
U8,
|
||||||
|
U16,
|
||||||
|
U32,
|
||||||
|
U64,
|
||||||
|
U128,
|
||||||
|
F16,
|
||||||
|
F32B,
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
F80,
|
||||||
|
F128,
|
||||||
|
F128PPC,
|
||||||
|
Bool,
|
||||||
|
Void,
|
||||||
|
CustomType(TypeValue),
|
||||||
|
Array(Box<Type>, u64),
|
||||||
|
Ptr(Box<Type>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ConstValue {
|
||||||
|
I8(i8),
|
||||||
|
I16(i16),
|
||||||
|
I32(i32),
|
||||||
|
I64(i64),
|
||||||
|
I128(i128),
|
||||||
|
U8(u8),
|
||||||
|
U16(u16),
|
||||||
|
U32(u32),
|
||||||
|
U64(u64),
|
||||||
|
U128(u128),
|
||||||
|
Bool(bool),
|
||||||
|
Str(String),
|
||||||
|
F16(f32),
|
||||||
|
F32B(f32),
|
||||||
|
F32(f32),
|
||||||
|
F64(f64),
|
||||||
|
F80(f64),
|
||||||
|
F128(f64),
|
||||||
|
F128PPC(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Hash)]
|
||||||
|
pub enum TerminatorKind {
|
||||||
|
Ret(InstructionValue),
|
||||||
|
RetVoid,
|
||||||
|
Br(BlockValue),
|
||||||
|
CondBr(InstructionValue, BlockValue, BlockValue),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
|
pub struct TypeData {
|
||||||
|
name: String,
|
||||||
|
kind: CustomTypeKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
|
pub enum CustomTypeKind {
|
||||||
|
NamedStruct(NamedStruct),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
|
pub struct NamedStruct(pub String, pub Vec<Type>);
|
||||||
|
|
||||||
|
impl ConstValue {
|
||||||
|
pub fn get_type(&self) -> Type {
|
||||||
|
use Type::*;
|
||||||
|
match self {
|
||||||
|
ConstValue::I8(_) => I8,
|
||||||
|
ConstValue::I16(_) => I16,
|
||||||
|
ConstValue::I32(_) => I32,
|
||||||
|
ConstValue::I64(_) => I64,
|
||||||
|
ConstValue::I128(_) => I128,
|
||||||
|
ConstValue::U8(_) => U8,
|
||||||
|
ConstValue::U16(_) => U16,
|
||||||
|
ConstValue::U32(_) => U32,
|
||||||
|
ConstValue::U64(_) => U64,
|
||||||
|
ConstValue::U128(_) => U128,
|
||||||
|
ConstValue::Str(_) => Type::Ptr(Box::new(U8)),
|
||||||
|
ConstValue::Bool(_) => Bool,
|
||||||
|
ConstValue::F16(_) => F16,
|
||||||
|
ConstValue::F32B(_) => F32B,
|
||||||
|
ConstValue::F32(_) => F32,
|
||||||
|
ConstValue::F64(_) => F64,
|
||||||
|
ConstValue::F80(_) => F80,
|
||||||
|
ConstValue::F128(_) => F128,
|
||||||
|
ConstValue::F128PPC(_) => F128PPC,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
|
pub enum TypeCategory {
|
||||||
|
SignedInteger,
|
||||||
|
UnsignedInteger,
|
||||||
|
Void,
|
||||||
|
Real,
|
||||||
|
Ptr,
|
||||||
|
CustomType,
|
||||||
|
Array,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeCategory {
|
||||||
|
pub fn comparable(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
TypeCategory::SignedInteger => true,
|
||||||
|
TypeCategory::UnsignedInteger => true,
|
||||||
|
TypeCategory::Real => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signed(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
TypeCategory::SignedInteger => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn integer(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
TypeCategory::SignedInteger => true,
|
||||||
|
TypeCategory::UnsignedInteger => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
pub fn category(&self) -> TypeCategory {
|
||||||
|
match self {
|
||||||
|
Type::I8 | Type::I16 | Type::I32 | Type::I64 | Type::I128 => TypeCategory::SignedInteger,
|
||||||
|
Type::U8 | Type::U16 | Type::U32 | Type::U64 | Type::U128 => TypeCategory::UnsignedInteger,
|
||||||
|
Type::F16 | Type::F32B | Type::F32 | Type::F64 | Type::F80 | Type::F128 | Type::F128PPC => {
|
||||||
|
TypeCategory::Real
|
||||||
|
}
|
||||||
|
Type::Bool => TypeCategory::UnsignedInteger,
|
||||||
|
Type::Void => TypeCategory::Void,
|
||||||
|
Type::CustomType(_) => TypeCategory::CustomType,
|
||||||
|
Type::Array(_, _) => TypeCategory::Array,
|
||||||
|
Type::Ptr(_) => TypeCategory::Ptr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cast_instruction(&self, value: InstructionValue, other: &Type) -> Option<Instr> {
|
||||||
|
use Type::*;
|
||||||
|
match (self, other) {
|
||||||
|
(I8, I16 | I32 | I64 | I128) => Some(Instr::SExt(value, other.clone())),
|
||||||
|
(I16, I32 | I64 | I128) => Some(Instr::SExt(value, other.clone())),
|
||||||
|
(I32, I64 | I128) => Some(Instr::SExt(value, other.clone())),
|
||||||
|
(I64, I128) => Some(Instr::SExt(value, other.clone())),
|
||||||
|
(I128 | U128, I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())),
|
||||||
|
(I64 | U64, I32 | U32 | I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())),
|
||||||
|
(I32 | U32, I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())),
|
||||||
|
(I16 | U16, I8 | U8) => Some(Instr::Trunc(value, other.clone())),
|
||||||
|
(U8 | I8, U8 | I8 | U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => {
|
||||||
|
Some(Instr::ZExt(value, other.clone()))
|
||||||
|
}
|
||||||
|
(U16 | I16, U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())),
|
||||||
|
(U32 | I32, U32 | I32 | U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())),
|
||||||
|
(U64 | I64, U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())),
|
||||||
|
(U128 | I128, U128 | I128) => Some(Instr::ZExt(value, other.clone())),
|
||||||
|
(U8 | U16 | U32 | U64 | U128, F16 | F32 | F32B | F64 | F80 | F128 | F128PPC) => {
|
||||||
|
Some(Instr::UIToFP(value, other.clone()))
|
||||||
|
}
|
||||||
|
(I8 | I16 | I32 | I64 | I128, F16 | F32 | F32B | F64 | F80 | F128 | F128PPC) => {
|
||||||
|
Some(Instr::SIToFP(value, other.clone()))
|
||||||
|
}
|
||||||
|
(F16 | F32 | F32B | F64 | F80 | F128 | F128PPC, U8 | U16 | U32 | U64 | U128) => {
|
||||||
|
Some(Instr::FPToUI(value, other.clone()))
|
||||||
|
}
|
||||||
|
(F16 | F32 | F32B | F64 | F80 | F128 | F128PPC, I8 | I16 | I32 | I64 | I128) => {
|
||||||
|
Some(Instr::FPToSI(value, other.clone()))
|
||||||
|
}
|
||||||
|
(I128 | U128 | I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8, Ptr(_)) => {
|
||||||
|
Some(Instr::IntToPtr(value, other.clone()))
|
||||||
|
}
|
||||||
|
(Ptr(_), I128 | U128 | I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => {
|
||||||
|
Some(Instr::PtrToInt(value, other.clone()))
|
||||||
|
}
|
||||||
|
(F16, F32 | F32B | F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
||||||
|
(F32 | F32B, F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
||||||
|
(F64, F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
||||||
|
(F80, F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
||||||
|
(F128PPC | F128, F80 | F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
|
||||||
|
(F80, F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
|
||||||
|
(F64, F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
|
||||||
|
(F32B | F32, F16) => Some(Instr::FPTrunc(value, other.clone())),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TerminatorKind {
|
||||||
|
pub(crate) fn get_type(&self, builder: &Builder) -> CompileResult<Type> {
|
||||||
|
use TerminatorKind::*;
|
||||||
|
match self {
|
||||||
|
Ret(instr_val) => instr_val.get_type(builder),
|
||||||
|
RetVoid => Ok(Type::Void),
|
||||||
|
Br(_) => Ok(Type::Void),
|
||||||
|
CondBr(_, _, _) => Ok(Type::Void),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
69
reid-llvm-lib/src/pad_adapter.rs
Normal file
69
reid-llvm-lib/src/pad_adapter.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
//! Copied from
|
||||||
|
//! https://github.com/rust-lang/rust/blob/6b3ae3f6e45a33c2d95fa0362c9b2593e567fd34/library/core/src/fmt/builders.rs#L102
|
||||||
|
|
||||||
|
// Copyright (c) The Rust Project Contributors
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
pub struct PadAdapter<'buf, 'state> {
|
||||||
|
buf: &'buf mut (dyn fmt::Write + 'buf),
|
||||||
|
state: &'state mut PadAdapterState,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PadAdapterState {
|
||||||
|
on_newline: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PadAdapterState {
|
||||||
|
fn default() -> Self {
|
||||||
|
PadAdapterState { on_newline: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'buf, 'state> PadAdapter<'buf, 'state> {
|
||||||
|
pub fn wrap<'slot, 'fmt: 'buf + 'slot>(
|
||||||
|
fmt: &'buf mut (dyn fmt::Write + 'buf),
|
||||||
|
state: &'state mut PadAdapterState,
|
||||||
|
) -> Self {
|
||||||
|
PadAdapter { buf: fmt, state }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Write for PadAdapter<'_, '_> {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
for s in s.split_inclusive('\n') {
|
||||||
|
if self.state.on_newline {
|
||||||
|
self.buf.write_str(" ")?;
|
||||||
|
}
|
||||||
|
self.state.on_newline = s.ends_with('\n');
|
||||||
|
self.buf.write_str(s)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_char(&mut self, c: char) -> fmt::Result {
|
||||||
|
if self.state.on_newline {
|
||||||
|
self.buf.write_str(" ")?;
|
||||||
|
}
|
||||||
|
self.state.on_newline = c == '\n';
|
||||||
|
self.buf.write_char(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
132
reid-llvm-lib/src/util.rs
Normal file
132
reid-llvm-lib/src/util.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
use std::{
|
||||||
|
ffi::{CStr, CString, c_char},
|
||||||
|
ptr::null_mut,
|
||||||
|
string::FromUtf8Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
use llvm_sys::{
|
||||||
|
core::{
|
||||||
|
LLVMCreateMemoryBufferWithMemoryRange, LLVMDisposeMemoryBuffer, LLVMGetBufferSize,
|
||||||
|
LLVMGetBufferStart,
|
||||||
|
},
|
||||||
|
error::LLVMDisposeErrorMessage,
|
||||||
|
prelude::LLVMMemoryBufferRef,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
CompileResult, ErrorKind, Type,
|
||||||
|
builder::{Builder, InstructionValue},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn into_cstring<T: Into<String>>(value: T) -> CString {
|
||||||
|
let string = value.into();
|
||||||
|
unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_cstring(pointer: *mut c_char) -> Option<String> {
|
||||||
|
if pointer.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
unsafe { CStr::from_ptr(pointer).to_str().ok().map(|s| s.to_owned()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cstring_to_err(value: *mut c_char) -> Result<(), String> {
|
||||||
|
from_cstring(value)
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.map_or(Ok(()), |s| Err(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility struct for LLVM's Error Messages, which need to be disposed
|
||||||
|
/// manually.
|
||||||
|
pub struct ErrorMessageHolder(*mut c_char);
|
||||||
|
|
||||||
|
impl ErrorMessageHolder {
|
||||||
|
pub fn null() -> Self {
|
||||||
|
ErrorMessageHolder(null_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn borrow_mut(&mut self) -> *mut *mut c_char {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_result(&self) -> Result<(), String> {
|
||||||
|
cstring_to_err(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ErrorMessageHolder {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if !self.0.is_null() {
|
||||||
|
LLVMDisposeErrorMessage(self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility for creating and handling LLVM MemoryBuffers, needed for printing
|
||||||
|
/// out ASM and .o -files without relying on LLVM's own API.
|
||||||
|
pub struct MemoryBufferHolder {
|
||||||
|
pub buffer: LLVMMemoryBufferRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryBufferHolder {
|
||||||
|
pub fn empty(name: &str) -> MemoryBufferHolder {
|
||||||
|
let array = [0i8; 0];
|
||||||
|
unsafe {
|
||||||
|
let buffer = LLVMCreateMemoryBufferWithMemoryRange(
|
||||||
|
array.as_ptr(),
|
||||||
|
array.len(),
|
||||||
|
into_cstring(name).as_ptr(),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
MemoryBufferHolder { buffer }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_buffer(&self) -> Vec<u8> {
|
||||||
|
unsafe {
|
||||||
|
let start = LLVMGetBufferStart(self.buffer);
|
||||||
|
let size = LLVMGetBufferSize(self.buffer);
|
||||||
|
|
||||||
|
let mut buff = Vec::with_capacity(size);
|
||||||
|
for i in 0..size {
|
||||||
|
buff.push(*start.add(i) as u8);
|
||||||
|
}
|
||||||
|
buff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_string(&self) -> Result<String, FromUtf8Error> {
|
||||||
|
String::from_utf8(self.as_buffer())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for MemoryBufferHolder {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
LLVMDisposeMemoryBuffer(self.buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make sure types for given instructions match. Return Ok(type) if they do,
|
||||||
|
/// and error otherwise.
|
||||||
|
pub fn match_types(
|
||||||
|
lhs: &InstructionValue,
|
||||||
|
rhs: &InstructionValue,
|
||||||
|
builder: &Builder,
|
||||||
|
) -> CompileResult<Type> {
|
||||||
|
let lhs_type = lhs.get_type(&builder);
|
||||||
|
let rhs_type = rhs.get_type(&builder);
|
||||||
|
if let (Ok(lhs_t), Ok(rhs_t)) = (lhs_type, rhs_type) {
|
||||||
|
if lhs_t == rhs_t {
|
||||||
|
Ok(lhs_t)
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
reid-lsp/.gitignore
vendored
7
reid-lsp/.gitignore
vendored
@ -1,7 +0,0 @@
|
|||||||
.vscode
|
|
||||||
node_modules
|
|
||||||
dist
|
|
||||||
package-lock.json
|
|
||||||
pnpm-lock.yaml
|
|
||||||
tsconfig.tsbuildinfo
|
|
||||||
*.vsix
|
|
||||||
@ -1 +0,0 @@
|
|||||||
enable-pre-post-scripts = true
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { defineConfig } from '@vscode/test-cli';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
files: 'out/test/**/*.test.js',
|
|
||||||
});
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
.vscode/**
|
|
||||||
.vscode-test/**
|
|
||||||
out/**
|
|
||||||
node_modules/**
|
|
||||||
src/**
|
|
||||||
client/**
|
|
||||||
.gitignore
|
|
||||||
.yarnrc
|
|
||||||
webpack.config.js
|
|
||||||
vsc-extension-quickstart.md
|
|
||||||
**/tsconfig.json
|
|
||||||
**/eslint.config.mjs
|
|
||||||
**/*.map
|
|
||||||
**/*.ts
|
|
||||||
**/.vscode-test.*
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
# Change Log
|
|
||||||
|
|
||||||
All notable changes to the "reid-language-server" extension will be documented in this file.
|
|
||||||
|
|
||||||
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
|
||||||
|
|
||||||
## [Unreleased]
|
|
||||||
|
|
||||||
- Initial release
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "reid-language-server"
|
|
||||||
version = "1.0.0"
|
|
||||||
edition = "2024"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
socket = "0.0.7"
|
|
||||||
tokio = { version = "1.47.0", features = ["full"] }
|
|
||||||
tower-lsp = "0.20.0"
|
|
||||||
reid = { path = "../reid", version = "1.0.0", registry="gitea-teascade", features=[] }
|
|
||||||
dashmap = "6.1.0"
|
|
||||||
serde = "*"
|
|
||||||
serde_json = "*"
|
|
||||||
@ -1 +0,0 @@
|
|||||||
# Reid Language Server
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "reid-lsp",
|
|
||||||
"displayName": "Reid Language Server",
|
|
||||||
"description": "Language Server Extension for Reid",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"engines": {
|
|
||||||
"vscode": "^1.102.0"
|
|
||||||
},
|
|
||||||
"main": "../out/extension.js",
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/mocha": "^10.0.10",
|
|
||||||
"@types/node": "20.x",
|
|
||||||
"@types/vscode": "^1.102.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^8.31.1",
|
|
||||||
"@typescript-eslint/parser": "^8.31.1",
|
|
||||||
"@vscode/test-cli": "^0.0.11",
|
|
||||||
"@vscode/test-electron": "^2.5.2",
|
|
||||||
"eslint": "^9.25.1",
|
|
||||||
"ts-loader": "^9.5.2",
|
|
||||||
"typescript": "^5.8.3",
|
|
||||||
"webpack": "^5.99.7",
|
|
||||||
"webpack-cli": "^6.0.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"vscode-languageclient": "^9.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
/* --------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
* ------------------------------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
import * as path from 'path';
|
|
||||||
import { workspace, ExtensionContext, window, languages, SemanticTokensBuilder } from 'vscode';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Executable,
|
|
||||||
LanguageClient,
|
|
||||||
LanguageClientOptions,
|
|
||||||
ServerOptions,
|
|
||||||
TransportKind
|
|
||||||
} from 'vscode-languageclient/node';
|
|
||||||
|
|
||||||
|
|
||||||
let client: LanguageClient;
|
|
||||||
|
|
||||||
export function activate(context: ExtensionContext) {
|
|
||||||
const configuration = workspace.getConfiguration('reid-language-server');
|
|
||||||
let server_path: string = process.env.SERVER_PATH ?? configuration.get("language-server-path") ?? 'reid-language-server';
|
|
||||||
const regex = /\$(\w+)/;
|
|
||||||
while (regex.test(server_path)) {
|
|
||||||
let envVar = regex.exec(server_path)?.[1];
|
|
||||||
const envVal = envVar ? process.env[envVar] : undefined;
|
|
||||||
if (envVar === undefined || envVal === undefined) {
|
|
||||||
console.error(`No such environment variables as ${envVar}`);
|
|
||||||
}
|
|
||||||
server_path = server_path.replaceAll(`$${envVar}`, envVal ?? '');
|
|
||||||
}
|
|
||||||
|
|
||||||
const run: Executable = {
|
|
||||||
command: server_path,
|
|
||||||
options: {
|
|
||||||
env: {
|
|
||||||
...process.env,
|
|
||||||
RUST_LOG: "debug",
|
|
||||||
RUST_BACKTRACE: 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const serverOptions: ServerOptions = {
|
|
||||||
run,
|
|
||||||
debug: run,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Options to control the language client
|
|
||||||
const clientOptions: LanguageClientOptions = {
|
|
||||||
// Register the server for plain text documents
|
|
||||||
documentSelector: [{ scheme: 'file', language: 'reid' }],
|
|
||||||
synchronize: {
|
|
||||||
// Notify the server about file changes to '.clientrc files contained in the workspace
|
|
||||||
fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the language client and start the client.
|
|
||||||
client = new LanguageClient(
|
|
||||||
'reid-language-server',
|
|
||||||
'Reid Language Server',
|
|
||||||
serverOptions,
|
|
||||||
clientOptions
|
|
||||||
);
|
|
||||||
client.info(JSON.stringify(server_path));
|
|
||||||
|
|
||||||
client.info(`Loaded Reid Language Server from ${server_path}`);
|
|
||||||
|
|
||||||
|
|
||||||
workspace.onDidOpenTextDocument((e) => { });
|
|
||||||
|
|
||||||
client.info("Registering semantic tokens provide");
|
|
||||||
context.subscriptions.push(languages.registerDocumentSemanticTokensProvider({
|
|
||||||
language: 'reid',
|
|
||||||
scheme: 'file'
|
|
||||||
}, {
|
|
||||||
provideDocumentSemanticTokens: () => {
|
|
||||||
const builder = new SemanticTokensBuilder();
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
tokenTypes: [],
|
|
||||||
tokenModifiers: [],
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Start the client. This will also launch the server
|
|
||||||
client.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deactivate(): Thenable<void> | undefined {
|
|
||||||
if (!client) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return client.stop();
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
import * as assert from 'assert';
|
|
||||||
|
|
||||||
// You can import and use all API from the 'vscode' module
|
|
||||||
// as well as import your extension to test it
|
|
||||||
import * as vscode from 'vscode';
|
|
||||||
// import * as myExtension from '../../extension';
|
|
||||||
|
|
||||||
suite('Extension Test Suite', () => {
|
|
||||||
vscode.window.showInformationMessage('Start all tests.');
|
|
||||||
|
|
||||||
test('Sample test', () => {
|
|
||||||
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
|
|
||||||
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "Node16",
|
|
||||||
"target": "ES2022",
|
|
||||||
"lib": [
|
|
||||||
"ES2022"
|
|
||||||
],
|
|
||||||
"sourceMap": true,
|
|
||||||
"rootDir": "src",
|
|
||||||
"outDir": "../dist",
|
|
||||||
"strict": true /* enable all strict type-checking options */
|
|
||||||
/* Additional Checks */
|
|
||||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
|
||||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
|
||||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
".vscode-test"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
import typescriptEslint from "@typescript-eslint/eslint-plugin";
|
|
||||||
import tsParser from "@typescript-eslint/parser";
|
|
||||||
|
|
||||||
export default [{
|
|
||||||
files: ["**/*.ts"],
|
|
||||||
}, {
|
|
||||||
plugins: {
|
|
||||||
"@typescript-eslint": typescriptEslint,
|
|
||||||
},
|
|
||||||
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsParser,
|
|
||||||
ecmaVersion: 2022,
|
|
||||||
sourceType: "module",
|
|
||||||
},
|
|
||||||
|
|
||||||
rules: {
|
|
||||||
"@typescript-eslint/naming-convention": ["warn", {
|
|
||||||
selector: "import",
|
|
||||||
format: ["camelCase", "PascalCase"],
|
|
||||||
}],
|
|
||||||
|
|
||||||
curly: "warn",
|
|
||||||
eqeqeq: "warn",
|
|
||||||
"no-throw-literal": "warn",
|
|
||||||
semi: "warn",
|
|
||||||
},
|
|
||||||
}];
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
{
|
|
||||||
"comments": {
|
|
||||||
"lineComment": "//",
|
|
||||||
},
|
|
||||||
"brackets": [
|
|
||||||
[
|
|
||||||
"{",
|
|
||||||
"}"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"[",
|
|
||||||
"]"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"(",
|
|
||||||
")"
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"autoClosingPairs": [
|
|
||||||
{
|
|
||||||
"open": "{",
|
|
||||||
"close": "}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"open": "[",
|
|
||||||
"close": "]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"open": "(",
|
|
||||||
"close": ")"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"open": "'",
|
|
||||||
"close": "'",
|
|
||||||
"notIn": [
|
|
||||||
"string",
|
|
||||||
"comment"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"open": "\"",
|
|
||||||
"close": "\"",
|
|
||||||
"notIn": [
|
|
||||||
"string"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"autoCloseBefore": ";:.,=}])>` \n\t",
|
|
||||||
"surroundingPairs": [
|
|
||||||
[
|
|
||||||
"{",
|
|
||||||
"}"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"[",
|
|
||||||
"]"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"(",
|
|
||||||
")"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"\"",
|
|
||||||
"\""
|
|
||||||
],
|
|
||||||
],
|
|
||||||
"folding": {
|
|
||||||
"markers": {
|
|
||||||
"start": "^\\s*//\\s*#?region\\b",
|
|
||||||
"end": "^\\s*//\\s*#?endregion\\b"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wordPattern": "[a-Z](\\w*)",
|
|
||||||
"indentationRules": {
|
|
||||||
"increaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$",
|
|
||||||
"decreaseIndentPattern": "^((?!.*?\\/\\*).*\\*/)?\\s*[\\)\\}\\]].*$"
|
|
||||||
},
|
|
||||||
"colorizedBracketPairs": [
|
|
||||||
[
|
|
||||||
"(",
|
|
||||||
")"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"[",
|
|
||||||
"]"
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"{",
|
|
||||||
"}"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "reid-language-server",
|
|
||||||
"displayName": "Reid Language Server",
|
|
||||||
"description": "Language Server Extension for Reid",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"repository": {
|
|
||||||
"url": "https://git.teascade.net/teascade"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"vscode": "^1.102.0"
|
|
||||||
},
|
|
||||||
"categories": [
|
|
||||||
"Other"
|
|
||||||
],
|
|
||||||
"main": "./dist/extension.js",
|
|
||||||
"icon": "./reid.png",
|
|
||||||
"publisher": "Teascade",
|
|
||||||
"author": {
|
|
||||||
"email": "teascade@teascade.net",
|
|
||||||
"name": "Teascade",
|
|
||||||
"url": "https://teascade.net"
|
|
||||||
},
|
|
||||||
"contributes": {
|
|
||||||
"languages": [
|
|
||||||
{
|
|
||||||
"id": "reid",
|
|
||||||
"extensions": [
|
|
||||||
".reid"
|
|
||||||
],
|
|
||||||
"aliases": [
|
|
||||||
"Reid"
|
|
||||||
],
|
|
||||||
"configuration": "./language-configuration.json",
|
|
||||||
"icon": {
|
|
||||||
"dark": "./reid.png",
|
|
||||||
"light": "./reid.png"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"breakpoints": [
|
|
||||||
{
|
|
||||||
"language": "reid"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"configuration": {
|
|
||||||
"type": "object",
|
|
||||||
"title": "reid-language-server",
|
|
||||||
"properties": {
|
|
||||||
"reid-language-server.language-server-path": {
|
|
||||||
"type": "string",
|
|
||||||
"scope": "window",
|
|
||||||
"default": "$HOME/.cargo/bin/reid-language-server",
|
|
||||||
"description": "Path to the Reid Language Server executable"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"grammars": [
|
|
||||||
{
|
|
||||||
"language": "reid",
|
|
||||||
"scopeName": "source.reid",
|
|
||||||
"path": "./syntaxes/grammar.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"vscode:prepublish": "pnpm run package",
|
|
||||||
"compile": "npx js-yaml syntaxes/grammar.yaml > syntaxes/grammar.json && webpack",
|
|
||||||
"watch": "webpack --watch",
|
|
||||||
"package": "webpack --mode production --devtool hidden-source-map",
|
|
||||||
"compile-tests": "tsc -p . --outDir out",
|
|
||||||
"watch-tests": "tsc -p . -w --outDir out",
|
|
||||||
"pretest": "pnpm run compile-tests && pnpm run compile && pnpm run lint",
|
|
||||||
"lint": "eslint src",
|
|
||||||
"test": "vscode-test"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/mocha": "^10.0.10",
|
|
||||||
"@types/node": "20.x",
|
|
||||||
"@types/vscode": "^1.102.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^8.31.1",
|
|
||||||
"@typescript-eslint/parser": "^8.31.1",
|
|
||||||
"@vscode/test-cli": "^0.0.11",
|
|
||||||
"@vscode/test-electron": "^2.5.2",
|
|
||||||
"eslint": "^9.25.1",
|
|
||||||
"js-yaml": "^4.1.0",
|
|
||||||
"ts-loader": "^9.5.2",
|
|
||||||
"typescript": "^5.8.3",
|
|
||||||
"webpack": "^5.99.7",
|
|
||||||
"webpack-cli": "^6.0.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"vscode-languageclient": "^9.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 KiB |
File diff suppressed because it is too large
Load Diff
@ -1,605 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use dashmap::DashMap;
|
|
||||||
use reid::ast::lexer::{FullToken, Position};
|
|
||||||
use reid::error_raporting::{self, ErrorModules, ReidError};
|
|
||||||
use reid::mir::SourceModuleId;
|
|
||||||
use reid::parse_module;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use tokio::sync::Mutex;
|
|
||||||
use tower_lsp::lsp_types::{
|
|
||||||
self, CompletionItem, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic, DiagnosticSeverity,
|
|
||||||
DidChangeTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentFilter,
|
|
||||||
GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverContents, HoverParams, HoverProviderCapability,
|
|
||||||
InitializeParams, InitializeResult, InitializedParams, Location, MarkedString, MarkupContent, MarkupKind,
|
|
||||||
MessageType, OneOf, Range, ReferenceParams, RenameParams, SemanticToken, SemanticTokensLegend,
|
|
||||||
SemanticTokensOptions, SemanticTokensParams, SemanticTokensResult, SemanticTokensServerCapabilities,
|
|
||||||
ServerCapabilities, TextDocumentItem, TextDocumentRegistrationOptions, TextDocumentSyncCapability,
|
|
||||||
TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions, TextEdit, Url, WorkspaceEdit,
|
|
||||||
WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
|
|
||||||
};
|
|
||||||
use tower_lsp::{Client, LanguageServer, LspService, Server, jsonrpc};
|
|
||||||
|
|
||||||
use crate::analysis::{MODIFIER_LEGEND, StateMap, StaticAnalysis, TOKEN_LEGEND, analyze};
|
|
||||||
|
|
||||||
mod analysis;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Backend {
|
|
||||||
client: Client,
|
|
||||||
analysis: DashMap<PathBuf, StaticAnalysis>,
|
|
||||||
module_to_path: DashMap<SourceModuleId, PathBuf>,
|
|
||||||
path_to_module: DashMap<PathBuf, SourceModuleId>,
|
|
||||||
module_id_counter: Mutex<SourceModuleId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
struct CompletionData {
|
|
||||||
token_idx: usize,
|
|
||||||
path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tower_lsp::async_trait]
|
|
||||||
impl LanguageServer for Backend {
|
|
||||||
async fn initialize(&self, _: InitializeParams) -> jsonrpc::Result<InitializeResult> {
|
|
||||||
self.client
|
|
||||||
.log_message(MessageType::INFO, "Initializing Reid Language Server")
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let sync = TextDocumentSyncOptions {
|
|
||||||
open_close: Some(true),
|
|
||||||
change: Some(TextDocumentSyncKind::FULL),
|
|
||||||
will_save: None,
|
|
||||||
will_save_wait_until: None,
|
|
||||||
save: Some(TextDocumentSyncSaveOptions::SaveOptions(lsp_types::SaveOptions {
|
|
||||||
include_text: Some(true),
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
|
|
||||||
let capabilities = ServerCapabilities {
|
|
||||||
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
|
||||||
completion_provider: Some(CompletionOptions {
|
|
||||||
trigger_characters: None,
|
|
||||||
all_commit_characters: None,
|
|
||||||
completion_item: Some(lsp_types::CompletionOptionsCompletionItem {
|
|
||||||
label_details_support: Some(true),
|
|
||||||
}),
|
|
||||||
resolve_provider: Some(false),
|
|
||||||
work_done_progress_options: lsp_types::WorkDoneProgressOptions {
|
|
||||||
work_done_progress: Some(true),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
text_document_sync: Some(TextDocumentSyncCapability::Options(sync)),
|
|
||||||
workspace: Some(WorkspaceServerCapabilities {
|
|
||||||
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
|
|
||||||
supported: Some(true),
|
|
||||||
change_notifications: Some(OneOf::Left(true)),
|
|
||||||
}),
|
|
||||||
file_operations: None,
|
|
||||||
}),
|
|
||||||
semantic_tokens_provider: Some(SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(
|
|
||||||
lsp_types::SemanticTokensRegistrationOptions {
|
|
||||||
text_document_registration_options: TextDocumentRegistrationOptions {
|
|
||||||
document_selector: Some(vec![DocumentFilter {
|
|
||||||
language: Some("reid".to_owned()),
|
|
||||||
scheme: Some("file".to_owned()),
|
|
||||||
pattern: None,
|
|
||||||
}]),
|
|
||||||
},
|
|
||||||
semantic_tokens_options: SemanticTokensOptions {
|
|
||||||
work_done_progress_options: Default::default(),
|
|
||||||
legend: SemanticTokensLegend {
|
|
||||||
token_types: TOKEN_LEGEND.into(),
|
|
||||||
token_modifiers: MODIFIER_LEGEND.into(),
|
|
||||||
},
|
|
||||||
range: None,
|
|
||||||
full: Some(lsp_types::SemanticTokensFullOptions::Bool(true)),
|
|
||||||
},
|
|
||||||
static_registration_options: Default::default(),
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
references_provider: Some(OneOf::Left(true)),
|
|
||||||
definition_provider: Some(OneOf::Left(true)),
|
|
||||||
rename_provider: Some(OneOf::Left(true)),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
Ok(InitializeResult {
|
|
||||||
capabilities,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn initialized(&self, _: InitializedParams) {
|
|
||||||
self.client
|
|
||||||
.log_message(MessageType::INFO, "Reid Language Server initialized!")
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn shutdown(&self) -> jsonrpc::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn completion(&self, params: CompletionParams) -> jsonrpc::Result<Option<CompletionResponse>> {
|
|
||||||
let path = PathBuf::from(params.text_document_position.text_document.uri.path());
|
|
||||||
let analysis = self.analysis.get(&path);
|
|
||||||
let position = params.text_document_position.position;
|
|
||||||
|
|
||||||
let token = if let Some(analysis) = &analysis {
|
|
||||||
analysis.tokens.iter().enumerate().find(|(_, tok)| {
|
|
||||||
tok.position.1 == position.line + 1
|
|
||||||
&& (tok.position.0 <= position.character
|
|
||||||
&& (tok.position.0 + tok.token.len() as u32) > position.character)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// dbg!(position, token);
|
|
||||||
|
|
||||||
let list = if let Some((idx, _)) = token {
|
|
||||||
if let Some(token_analysis) = self.analysis.get(&path).unwrap().state.map.get(&idx) {
|
|
||||||
token_analysis
|
|
||||||
.autocomplete
|
|
||||||
.iter()
|
|
||||||
.map(|autocomplete| {
|
|
||||||
let mut item =
|
|
||||||
CompletionItem::new_simple(autocomplete.text.to_string(), autocomplete.kind.to_string());
|
|
||||||
item.data = Some(
|
|
||||||
serde_json::to_value(CompletionData {
|
|
||||||
token_idx: idx,
|
|
||||||
path: path.clone(),
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
item.documentation = autocomplete.documentation.as_ref().and_then(|d| {
|
|
||||||
Some(lsp_types::Documentation::MarkupContent(MarkupContent {
|
|
||||||
kind: MarkupKind::Markdown,
|
|
||||||
value: d.clone(),
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
item
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
// dbg!(&list);
|
|
||||||
Ok(Some(CompletionResponse::Array(list)))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn hover(&self, params: HoverParams) -> jsonrpc::Result<Option<Hover>> {
|
|
||||||
let path = PathBuf::from(params.text_document_position_params.text_document.uri.path());
|
|
||||||
let analysis = self.analysis.get(&path);
|
|
||||||
let position = params.text_document_position_params.position;
|
|
||||||
|
|
||||||
let token = if let Some(analysis) = &analysis {
|
|
||||||
analysis.tokens.iter().enumerate().find(|(_, tok)| {
|
|
||||||
tok.position.1 == position.line + 1
|
|
||||||
&& (tok.position.0 <= position.character + 1
|
|
||||||
&& (tok.position.0 + tok.token.len() as u32) > position.character + 1)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let (range, ty, documentation) = if let Some((idx, token)) = token {
|
|
||||||
if let Some(analysis) = self.analysis.get(&path).unwrap().state.map.get(&idx) {
|
|
||||||
let start = token.position;
|
|
||||||
let end = token.position.add(token.token.len() as u32);
|
|
||||||
let range = Range {
|
|
||||||
start: lsp_types::Position {
|
|
||||||
line: (start.1 as i32 - 1).max(0) as u32,
|
|
||||||
character: (start.0 as i32 - 1).max(0) as u32,
|
|
||||||
},
|
|
||||||
end: lsp_types::Position {
|
|
||||||
line: (end.1 as i32 - 1).max(0) as u32,
|
|
||||||
character: (end.0 as i32 - 1).max(0) as u32,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if let Some(kind) = &analysis.hover.kind {
|
|
||||||
match kind {
|
|
||||||
analysis::HoverKind::Type(type_kind) => (
|
|
||||||
Some(range),
|
|
||||||
format!("{}", type_kind),
|
|
||||||
analysis.hover.documentation.clone(),
|
|
||||||
),
|
|
||||||
analysis::HoverKind::Function(name, function_params, return_type) => (
|
|
||||||
Some(range),
|
|
||||||
format!(
|
|
||||||
"{}({}) -> {}",
|
|
||||||
name,
|
|
||||||
function_params
|
|
||||||
.iter()
|
|
||||||
.map(|p| format!("{}: {}", p.name, p.ty))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", "),
|
|
||||||
return_type
|
|
||||||
),
|
|
||||||
analysis.hover.documentation.clone(),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
Some(range),
|
|
||||||
String::from("No type"),
|
|
||||||
analysis.hover.documentation.clone(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(None, String::from("no type"), None)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(None, String::from("no token"), None)
|
|
||||||
};
|
|
||||||
|
|
||||||
let contents = if let Some(doc) = documentation {
|
|
||||||
HoverContents::Array(vec![MarkedString::String(doc), MarkedString::String(format!("`{ty}`"))])
|
|
||||||
} else {
|
|
||||||
HoverContents::Markup(MarkupContent {
|
|
||||||
kind: MarkupKind::Markdown,
|
|
||||||
value: format!("`{ty}`"),
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Some(Hover { contents, range }))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn did_open(&self, params: DidOpenTextDocumentParams) {
|
|
||||||
self.recompile(TextDocumentItem {
|
|
||||||
uri: params.text_document.uri,
|
|
||||||
language_id: params.text_document.language_id,
|
|
||||||
version: params.text_document.version,
|
|
||||||
text: params.text_document.text,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn did_change(&self, params: DidChangeTextDocumentParams) {
|
|
||||||
self.recompile(TextDocumentItem {
|
|
||||||
text: params.content_changes[0].text.clone(),
|
|
||||||
uri: params.text_document.uri,
|
|
||||||
version: params.text_document.version,
|
|
||||||
language_id: String::new(),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn did_save(&self, params: DidSaveTextDocumentParams) {
|
|
||||||
self.recompile(TextDocumentItem {
|
|
||||||
text: params.text.unwrap(),
|
|
||||||
uri: params.text_document.uri,
|
|
||||||
version: 0,
|
|
||||||
language_id: String::new(),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn semantic_tokens_full(
|
|
||||||
&self,
|
|
||||||
params: SemanticTokensParams,
|
|
||||||
) -> jsonrpc::Result<Option<SemanticTokensResult>> {
|
|
||||||
let path = PathBuf::from(params.text_document.uri.path());
|
|
||||||
let analysis = self.analysis.get(&path);
|
|
||||||
|
|
||||||
let mut semantic_tokens = Vec::new();
|
|
||||||
if let Some(analysis) = analysis {
|
|
||||||
let mut prev_line = 0;
|
|
||||||
let mut prev_start = 0;
|
|
||||||
for (i, token) in analysis.tokens.iter().enumerate() {
|
|
||||||
let vscode_line = token.position.1.max(1) - 1;
|
|
||||||
let vscode_col = token.position.0.max(1) - 1;
|
|
||||||
|
|
||||||
let delta_line = vscode_line - prev_line;
|
|
||||||
let delta_start = if delta_line == 0 {
|
|
||||||
vscode_col - prev_start
|
|
||||||
} else {
|
|
||||||
vscode_col
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(token_analysis) = analysis.state.map.get(&i) {
|
|
||||||
if let Some(symbol_id) = token_analysis.symbol {
|
|
||||||
let symbol = analysis.state.get_local_symbol(symbol_id);
|
|
||||||
if let Some(idx) = symbol.kind.into_token_idx(&self.state_map()) {
|
|
||||||
let semantic_token = SemanticToken {
|
|
||||||
delta_line,
|
|
||||||
delta_start,
|
|
||||||
length: token.token.len() as u32,
|
|
||||||
token_type: idx,
|
|
||||||
token_modifiers_bitset: symbol.kind.get_modifier().unwrap_or(0),
|
|
||||||
};
|
|
||||||
semantic_tokens.push(semantic_token);
|
|
||||||
prev_line = vscode_line;
|
|
||||||
prev_start = vscode_col;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Some(SemanticTokensResult::Tokens(lsp_types::SemanticTokens {
|
|
||||||
result_id: None,
|
|
||||||
data: semantic_tokens,
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn goto_definition(&self, params: GotoDefinitionParams) -> jsonrpc::Result<Option<GotoDefinitionResponse>> {
|
|
||||||
let path = PathBuf::from(params.text_document_position_params.text_document.uri.path());
|
|
||||||
let analysis = self.analysis.get(&path);
|
|
||||||
let position = params.text_document_position_params.position;
|
|
||||||
|
|
||||||
if let Some(analysis) = &analysis {
|
|
||||||
let token = analysis.tokens.iter().enumerate().find(|(_, tok)| {
|
|
||||||
tok.position.1 == position.line + 1
|
|
||||||
&& (tok.position.0 <= position.character + 1
|
|
||||||
&& (tok.position.0 + tok.token.len() as u32) > position.character + 1)
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(token) = token {
|
|
||||||
if let Some((module_id, def_token)) = analysis.find_definition(token.0, &self.state_map()) {
|
|
||||||
return if let Some(path) = self.module_to_path.get(&module_id) {
|
|
||||||
Ok(Some(GotoDefinitionResponse::Scalar(lsp_types::Location {
|
|
||||||
uri: Url::from_file_path(path.value()).unwrap(),
|
|
||||||
range: token_to_range(def_token),
|
|
||||||
})))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn references(&self, params: ReferenceParams) -> jsonrpc::Result<Option<Vec<Location>>> {
|
|
||||||
let path = PathBuf::from(params.text_document_position.text_document.uri.path());
|
|
||||||
let analysis = self.analysis.get(&path);
|
|
||||||
let position = params.text_document_position.position;
|
|
||||||
|
|
||||||
if let Some(analysis) = &analysis {
|
|
||||||
let token = analysis.tokens.iter().enumerate().find(|(_, tok)| {
|
|
||||||
tok.position.1 == position.line + 1
|
|
||||||
&& (tok.position.0 <= position.character + 1
|
|
||||||
&& (tok.position.0 + tok.token.len() as u32) > position.character + 1)
|
|
||||||
});
|
|
||||||
if let Some(token) = token {
|
|
||||||
let reference_tokens = analysis.find_references(token.0, &self.state_map());
|
|
||||||
let mut locations = Vec::new();
|
|
||||||
if let Some(reference_tokens) = reference_tokens {
|
|
||||||
for (module_id, symbol_idx) in reference_tokens {
|
|
||||||
if let Some(path) = self.module_to_path.get(&module_id) {
|
|
||||||
let url = Url::from_file_path(path.value()).unwrap();
|
|
||||||
if let Some(inner_analysis) = self.analysis.get(path.value()) {
|
|
||||||
if let Some(token_idx) = inner_analysis.state.symbol_to_token.get(&symbol_idx) {
|
|
||||||
let token = inner_analysis.tokens.get(*token_idx).unwrap();
|
|
||||||
|
|
||||||
locations.push(lsp_types::Location {
|
|
||||||
uri: url,
|
|
||||||
range: token_to_range(token),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Some(locations))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn rename(&self, params: RenameParams) -> jsonrpc::Result<Option<WorkspaceEdit>> {
|
|
||||||
let path = PathBuf::from(params.text_document_position.text_document.uri.path());
|
|
||||||
let analysis = self.analysis.get(&path);
|
|
||||||
let position = params.text_document_position.position;
|
|
||||||
|
|
||||||
if let Some(analysis) = &analysis {
|
|
||||||
let token = analysis.tokens.iter().enumerate().find(|(_, tok)| {
|
|
||||||
tok.position.1 == position.line + 1
|
|
||||||
&& (tok.position.0 <= position.character + 1
|
|
||||||
&& (tok.position.0 + tok.token.len() as u32) > position.character + 1)
|
|
||||||
});
|
|
||||||
if let Some(token) = token {
|
|
||||||
let symbols = analysis.find_references(token.0, &self.state_map());
|
|
||||||
let mut changes: HashMap<Url, Vec<TextEdit>> = HashMap::new();
|
|
||||||
if let Some(symbols) = symbols {
|
|
||||||
for (module_id, symbol_id) in symbols {
|
|
||||||
let path = self.module_to_path.get(&module_id);
|
|
||||||
if let Some(path) = path {
|
|
||||||
let url = Url::from_file_path(path.value()).unwrap();
|
|
||||||
let analysis = self.analysis.get(&path.clone());
|
|
||||||
|
|
||||||
if let Some(analysis) = analysis {
|
|
||||||
if let Some(token_idx) = analysis.state.symbol_to_token.get(&symbol_id) {
|
|
||||||
let token = analysis.tokens.get(*token_idx).unwrap();
|
|
||||||
|
|
||||||
// edits = changes.get(k)
|
|
||||||
let edit = TextEdit {
|
|
||||||
range: token_to_range(token),
|
|
||||||
new_text: params.new_name.clone(),
|
|
||||||
};
|
|
||||||
if let Some(edits) = changes.get_mut(&url) {
|
|
||||||
edits.push(edit);
|
|
||||||
} else {
|
|
||||||
changes.insert(url, vec![edit]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Some(WorkspaceEdit {
|
|
||||||
changes: Some(changes),
|
|
||||||
document_changes: None,
|
|
||||||
change_annotations: None,
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn token_to_range(token: &FullToken) -> lsp_types::Range {
|
|
||||||
Range {
|
|
||||||
start: lsp_types::Position {
|
|
||||||
line: token.position.1.max(1) - 1,
|
|
||||||
character: token.position.0.max(1) - 1,
|
|
||||||
},
|
|
||||||
end: lsp_types::Position {
|
|
||||||
line: token.position.1.max(1) - 1,
|
|
||||||
character: token.position.0.max(1) - 1 + token.token.len() as u32,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Backend {
|
|
||||||
fn state_map(&self) -> StateMap {
|
|
||||||
let mut state_map = HashMap::new();
|
|
||||||
for path_state in self.analysis.iter() {
|
|
||||||
let (path, state) = path_state.pair();
|
|
||||||
if let Some(module_id) = self.path_to_module.get(path) {
|
|
||||||
state_map.insert(*module_id, state.state.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state_map
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn recompile(&self, params: TextDocumentItem) {
|
|
||||||
let file_path = PathBuf::from(params.uri.clone().path());
|
|
||||||
|
|
||||||
let mut map: ErrorModules = Default::default();
|
|
||||||
for url_module in self.path_to_module.iter() {
|
|
||||||
let (url, module) = url_module.pair();
|
|
||||||
map.add_module(
|
|
||||||
url.file_name().unwrap().to_str().unwrap().to_owned(),
|
|
||||||
Some(url.clone()),
|
|
||||||
Some(*module),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let module_id = if let Some(module_id) = self.path_to_module.get(&file_path) {
|
|
||||||
*module_id
|
|
||||||
} else {
|
|
||||||
let mut lock = self.module_id_counter.lock().await;
|
|
||||||
let module_id = lock.increment();
|
|
||||||
drop(lock);
|
|
||||||
self.path_to_module.insert(file_path.clone(), module_id);
|
|
||||||
self.module_to_path.insert(module_id, file_path.clone());
|
|
||||||
module_id
|
|
||||||
};
|
|
||||||
|
|
||||||
let parse_res = parse(¶ms.text, file_path.clone(), &mut map, module_id);
|
|
||||||
let (tokens, result) = match parse_res {
|
|
||||||
Ok((module_id, tokens)) => (
|
|
||||||
tokens.clone(),
|
|
||||||
analyze(module_id, tokens, file_path.clone(), &mut map, &self.state_map()),
|
|
||||||
),
|
|
||||||
Err(e) => (Vec::new(), Err(e)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut diagnostics = Vec::new();
|
|
||||||
match result {
|
|
||||||
Ok(Some(mut analysis)) => {
|
|
||||||
if let Some(reid_error) = &mut analysis.error {
|
|
||||||
self.client
|
|
||||||
.log_message(
|
|
||||||
MessageType::INFO,
|
|
||||||
format!("Successfully compiled despite parsing errors!"),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
reid_error.errors.dedup();
|
|
||||||
for error in &reid_error.errors {
|
|
||||||
diagnostics.push(reid_error_into_diagnostic(error, &tokens));
|
|
||||||
self.client.log_message(MessageType::INFO, format!("{}", error)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.analysis.insert(file_path, analysis);
|
|
||||||
}
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(mut reid_error) => {
|
|
||||||
reid_error.errors.dedup();
|
|
||||||
for error in &reid_error.errors {
|
|
||||||
diagnostics.push(reid_error_into_diagnostic(error, &tokens));
|
|
||||||
self.client.log_message(MessageType::INFO, format!("{}", error)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.client
|
|
||||||
.publish_diagnostics(params.uri.clone(), diagnostics, Some(params.version))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reid_error_into_diagnostic(error: &error_raporting::ErrorKind, tokens: &Vec<FullToken>) -> Diagnostic {
|
|
||||||
let meta = error.get_meta();
|
|
||||||
let positions = meta
|
|
||||||
.range
|
|
||||||
.into_position(&tokens)
|
|
||||||
.unwrap_or((Position(0, 0), Position(0, 0)));
|
|
||||||
|
|
||||||
Diagnostic {
|
|
||||||
range: Range {
|
|
||||||
start: lsp_types::Position {
|
|
||||||
line: ((positions.0.1 as i32) - 1).max(0) as u32,
|
|
||||||
character: ((positions.0.0 as i32) - 1).max(0) as u32,
|
|
||||||
},
|
|
||||||
end: lsp_types::Position {
|
|
||||||
line: ((positions.1.1 as i32) - 1).max(0) as u32,
|
|
||||||
character: ((positions.1.0 as i32) - 1).max(0) as u32,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
severity: Some(DiagnosticSeverity::ERROR),
|
|
||||||
code: None,
|
|
||||||
code_description: None,
|
|
||||||
source: Some(error.get_type_str().to_owned()),
|
|
||||||
message: format!("{}", error),
|
|
||||||
related_information: None,
|
|
||||||
tags: None,
|
|
||||||
data: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse(
|
|
||||||
source: &str,
|
|
||||||
path: PathBuf,
|
|
||||||
map: &mut ErrorModules,
|
|
||||||
module_id: SourceModuleId,
|
|
||||||
) -> Result<(SourceModuleId, Vec<FullToken>), ReidError> {
|
|
||||||
let file_name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
|
||||||
|
|
||||||
Ok(parse_module(
|
|
||||||
source,
|
|
||||||
file_name.clone(),
|
|
||||||
Some(path),
|
|
||||||
map,
|
|
||||||
Some(module_id),
|
|
||||||
)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
let stdin = tokio::io::stdin();
|
|
||||||
let stdout = tokio::io::stdout();
|
|
||||||
|
|
||||||
let (service, socket) = LspService::new(|client| Backend {
|
|
||||||
client,
|
|
||||||
analysis: DashMap::new(),
|
|
||||||
module_to_path: DashMap::new(),
|
|
||||||
path_to_module: DashMap::new(),
|
|
||||||
module_id_counter: Mutex::new(SourceModuleId(0)),
|
|
||||||
});
|
|
||||||
Server::new(stdin, stdout, socket).serve(service).await;
|
|
||||||
}
|
|
||||||
@ -1,281 +0,0 @@
|
|||||||
{
|
|
||||||
"scopeName": "source.reid",
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#expression"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"repository": {
|
|
||||||
"expression": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#comment"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#fn-signature"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#namespace"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#common-type"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#struct-definition"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#binop"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#cast"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#function-call"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#parenthesis"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#array"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#keywords"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#number-literal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#string-literal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#identifier"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#punctuation"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"punctuation": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"match": "::",
|
|
||||||
"name": "keyword.operator.namespace.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": ":",
|
|
||||||
"name": "keyword.operator.colon.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": ";",
|
|
||||||
"name": "punctuation.semi.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": ".",
|
|
||||||
"name": "punctuation.dot.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": ",",
|
|
||||||
"name": "punctuation.comma.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\{|\\}",
|
|
||||||
"name": "punctuation.brackets.curly.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\(|\\)",
|
|
||||||
"name": "punctuation.parenthesis.reid"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"comment": {
|
|
||||||
"match": "\\/\\/(.|\\/)*",
|
|
||||||
"name": "comment.line.double-slash.reid"
|
|
||||||
},
|
|
||||||
"struct-definition": {
|
|
||||||
"match": "(struct)\\s*(\\w+)",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "keyword.struct.reid"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "entity.name.type"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"struct-expression": {
|
|
||||||
"begin": "\\b([A-Z]\\w*)\\s*\\{",
|
|
||||||
"end": "\\}",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "entity.name.type.struct.reid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#expression"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"number-literal": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"match": "\\b0x[0-9a-fA-F]+(\\.[0-9a-fA-F]+)?\\b",
|
|
||||||
"name": "constant.hexadecimal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\b0o[0-7]+(\\.[0-7]+)?\\b",
|
|
||||||
"name": "constant.octal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\b0b[01]+(\\.[01]+)?\\b",
|
|
||||||
"name": "constant.binary"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\b[0-9]+(\\.[0-9]+)?\\b",
|
|
||||||
"name": "constant.numeric"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"string-literal": {
|
|
||||||
"begin": "\"",
|
|
||||||
"end": "\"",
|
|
||||||
"name": "string.quoted.double",
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"match": "\\\\\\w",
|
|
||||||
"name": "constant.character.escape"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"namespace": {
|
|
||||||
"match": "(\\w+)(\\:\\:)",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "entity.name.namespace.reid"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "keyword.operator.namespace.reid"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cast": {
|
|
||||||
"match": "(as)\\s+(\\w+)",
|
|
||||||
"captures": {
|
|
||||||
"1": {
|
|
||||||
"name": "keyword.cast.reid"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "entity.name.type.reid"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"function-call": {
|
|
||||||
"begin": "(\\w+)?(\\()",
|
|
||||||
"end": "(\\))",
|
|
||||||
"beginCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "entity.name.function.reid"
|
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "punctuation.parenthesis.reid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"endCaptures": {
|
|
||||||
"1": {
|
|
||||||
"name": "punctuation.parenthesis.reid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#expression"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"parenthesis": {
|
|
||||||
"begin": "\\(",
|
|
||||||
"end": "\\)",
|
|
||||||
"beginCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "keyword.operator.parenthesis.reid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "keyword.operator.parenthesis.reid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#expression"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"identifier": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"match": "\\b(?:\\w+)\\b",
|
|
||||||
"name": "variable.language.reid"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"keywords": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"match": "\\b(?:let|mut|pub|extern)\\b",
|
|
||||||
"name": "storage.type.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\bimport\\b",
|
|
||||||
"name": "keyword.import.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\bbinop\\b",
|
|
||||||
"name": "keyword.binop.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\bimpl\\b",
|
|
||||||
"name": "keyword.impl.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\b(?:if|return|for|in)\\b",
|
|
||||||
"name": "keyword.control"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\bself\\b",
|
|
||||||
"name": "variable.language.self.reid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match": "\\bfn\\b",
|
|
||||||
"name": "keyword.fn.reid"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"binop": {
|
|
||||||
"match": "\\<\\=|\\>\\=|\\=\\=|\\<|\\>|\\*|\\+|\\-|\\^|\\&\\&|\\&",
|
|
||||||
"name": "keyword.operator.math.reid"
|
|
||||||
},
|
|
||||||
"array": {
|
|
||||||
"begin": "\\[",
|
|
||||||
"end": "\\]",
|
|
||||||
"beginCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "entity.name.type.array.reid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"endCaptures": {
|
|
||||||
"0": {
|
|
||||||
"name": "entity.name.type.array.reid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#expression"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"common-type": {
|
|
||||||
"match": "\\b(?:u8|u16|u32|u64|u128|i8|i16|i32|i64|i128|f16|f16b|f32|f64|f80|f128|f128ppc|bool|char|([A-Z]\\w*))\\b",
|
|
||||||
"name": "entity.name.type.common.reid"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,149 +0,0 @@
|
|||||||
scopeName: source.reid
|
|
||||||
patterns:
|
|
||||||
- include: "#expression"
|
|
||||||
repository:
|
|
||||||
expression:
|
|
||||||
patterns:
|
|
||||||
- include: "#comment"
|
|
||||||
- include: "#fn-signature"
|
|
||||||
- include: "#namespace"
|
|
||||||
- include: "#common-type"
|
|
||||||
- include: "#struct-definition"
|
|
||||||
- include: "#binop"
|
|
||||||
- include: "#cast"
|
|
||||||
- include: "#function-call"
|
|
||||||
- include: "#parenthesis"
|
|
||||||
- include: "#array"
|
|
||||||
- include: "#keywords"
|
|
||||||
- include: "#number-literal"
|
|
||||||
- include: "#string-literal"
|
|
||||||
- include: "#identifier"
|
|
||||||
- include: "#punctuation"
|
|
||||||
punctuation:
|
|
||||||
patterns:
|
|
||||||
- match: "::"
|
|
||||||
name: keyword.operator.namespace.reid
|
|
||||||
- match: ":"
|
|
||||||
name: keyword.operator.colon.reid
|
|
||||||
- match: ";"
|
|
||||||
name: punctuation.semi.reid
|
|
||||||
- match: "."
|
|
||||||
name: punctuation.dot.reid
|
|
||||||
- match: ","
|
|
||||||
name: punctuation.comma.reid
|
|
||||||
- match: "\\{|\\}"
|
|
||||||
name: punctuation.brackets.curly.reid
|
|
||||||
- match: "\\(|\\)"
|
|
||||||
name: punctuation.parenthesis.reid
|
|
||||||
comment:
|
|
||||||
match: "\\/\\/(.|\\/)*"
|
|
||||||
name: comment.line.double-slash.reid
|
|
||||||
struct-definition:
|
|
||||||
match: "(struct)\\s*(\\w+)"
|
|
||||||
captures:
|
|
||||||
1:
|
|
||||||
name: keyword.struct.reid
|
|
||||||
2:
|
|
||||||
name: entity.name.type
|
|
||||||
struct-expression:
|
|
||||||
begin: "\\b([A-Z]\\w*)\\s*\\{"
|
|
||||||
end: "\\}"
|
|
||||||
captures:
|
|
||||||
1:
|
|
||||||
name: entity.name.type.struct.reid
|
|
||||||
patterns:
|
|
||||||
- include: "#expression"
|
|
||||||
number-literal:
|
|
||||||
patterns:
|
|
||||||
- match: "\\b0x[0-9a-fA-F]+(\\.[0-9a-fA-F]+)?\\b"
|
|
||||||
name: "constant.hexadecimal"
|
|
||||||
- match: "\\b0o[0-7]+(\\.[0-7]+)?\\b"
|
|
||||||
name: "constant.octal"
|
|
||||||
- match: "\\b0b[01]+(\\.[01]+)?\\b"
|
|
||||||
name: "constant.binary"
|
|
||||||
- match: "\\b[0-9]+(\\.[0-9]+)?\\b"
|
|
||||||
name: "constant.numeric"
|
|
||||||
string-literal:
|
|
||||||
begin: '"'
|
|
||||||
end: '"'
|
|
||||||
name: string.quoted.double
|
|
||||||
patterns:
|
|
||||||
- match: "\\\\\\w"
|
|
||||||
name: constant.character.escape
|
|
||||||
namespace:
|
|
||||||
match: "(\\w+)(\\:\\:)"
|
|
||||||
captures:
|
|
||||||
1:
|
|
||||||
name: entity.name.namespace.reid
|
|
||||||
2:
|
|
||||||
name: keyword.operator.namespace.reid
|
|
||||||
cast:
|
|
||||||
match: "(as)\\s+(\\w+)"
|
|
||||||
captures:
|
|
||||||
1:
|
|
||||||
name: keyword.cast.reid
|
|
||||||
2:
|
|
||||||
name: entity.name.type.reid
|
|
||||||
function-call:
|
|
||||||
begin: "(\\w+)?(\\()"
|
|
||||||
end: "(\\))"
|
|
||||||
beginCaptures:
|
|
||||||
1:
|
|
||||||
name: entity.name.function.reid
|
|
||||||
2:
|
|
||||||
name: punctuation.parenthesis.reid
|
|
||||||
endCaptures:
|
|
||||||
1:
|
|
||||||
name: punctuation.parenthesis.reid
|
|
||||||
patterns:
|
|
||||||
- include: "#expression"
|
|
||||||
parenthesis:
|
|
||||||
begin: "\\("
|
|
||||||
end: "\\)"
|
|
||||||
beginCaptures:
|
|
||||||
0:
|
|
||||||
name: keyword.operator.parenthesis.reid
|
|
||||||
endCaptures:
|
|
||||||
0:
|
|
||||||
name: keyword.operator.parenthesis.reid
|
|
||||||
patterns:
|
|
||||||
- include: "#expression"
|
|
||||||
identifier:
|
|
||||||
patterns:
|
|
||||||
- match: "\\b(?:\\w+)\\b"
|
|
||||||
name: variable.language.reid
|
|
||||||
keywords:
|
|
||||||
patterns:
|
|
||||||
- match: "\\b(?:let|mut|pub|extern)\\b"
|
|
||||||
name: storage.type.reid
|
|
||||||
- match: "\\bimport\\b"
|
|
||||||
name: keyword.import.reid
|
|
||||||
- match: "\\bbinop\\b"
|
|
||||||
name: keyword.binop.reid
|
|
||||||
- match: "\\bimpl\\b"
|
|
||||||
name: keyword.impl.reid
|
|
||||||
- match: "\\b(?:if|return|for|in)\\b"
|
|
||||||
name: keyword.control
|
|
||||||
- match: "\\bself\\b"
|
|
||||||
name: variable.language.self.reid
|
|
||||||
- match: "\\bfn\\b"
|
|
||||||
name: keyword.fn.reid
|
|
||||||
binop:
|
|
||||||
match: "\\<\\=|\\>\\=|\\=\\=|\\<|\\>|\\*|\\+|\\-|\\^|\\&\\&|\\&"
|
|
||||||
name: keyword.operator.math.reid
|
|
||||||
array:
|
|
||||||
begin: "\\["
|
|
||||||
end: "\\]"
|
|
||||||
beginCaptures:
|
|
||||||
0:
|
|
||||||
name: entity.name.type.array.reid
|
|
||||||
endCaptures:
|
|
||||||
0:
|
|
||||||
name: entity.name.type.array.reid
|
|
||||||
patterns:
|
|
||||||
- include: "#expression"
|
|
||||||
common-type:
|
|
||||||
match: "\\b(?:u8|u16|u32|u64|u128|i8|i16|i32|i64|i128|f16|f16b|f32|f64|f80|f128|f128ppc|bool|char|([A-Z]\\w*))\\b"
|
|
||||||
name: entity.name.type.common.reid
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "Node16",
|
|
||||||
"target": "ES2022",
|
|
||||||
"lib": [
|
|
||||||
"ES2022"
|
|
||||||
],
|
|
||||||
"sourceMap": true,
|
|
||||||
"rootDir": "src",
|
|
||||||
"outDir": "out",
|
|
||||||
"strict": true /* enable all strict type-checking options */
|
|
||||||
/* Additional Checks */
|
|
||||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
|
||||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
|
||||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
".vscode-test"
|
|
||||||
],
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "./client/"
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
# Welcome to your VS Code Extension
|
|
||||||
|
|
||||||
## What's in the folder
|
|
||||||
|
|
||||||
* This folder contains all of the files necessary for your extension.
|
|
||||||
* `package.json` - this is the manifest file in which you declare your extension and command.
|
|
||||||
* The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin.
|
|
||||||
* `src/extension.ts` - this is the main file where you will provide the implementation of your command.
|
|
||||||
* The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
|
|
||||||
* We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
* install the recommended extensions (amodio.tsl-problem-matcher, ms-vscode.extension-test-runner, and dbaeumer.vscode-eslint)
|
|
||||||
|
|
||||||
|
|
||||||
## Get up and running straight away
|
|
||||||
|
|
||||||
* Press `F5` to open a new window with your extension loaded.
|
|
||||||
* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
|
|
||||||
* Set breakpoints in your code inside `src/extension.ts` to debug your extension.
|
|
||||||
* Find output from your extension in the debug console.
|
|
||||||
|
|
||||||
## Make changes
|
|
||||||
|
|
||||||
* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
|
|
||||||
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
|
|
||||||
|
|
||||||
|
|
||||||
## Explore the API
|
|
||||||
|
|
||||||
* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`.
|
|
||||||
|
|
||||||
## Run tests
|
|
||||||
|
|
||||||
* Install the [Extension Test Runner](https://marketplace.visualstudio.com/items?itemName=ms-vscode.extension-test-runner)
|
|
||||||
* Run the "watch" task via the **Tasks: Run Task** command. Make sure this is running, or tests might not be discovered.
|
|
||||||
* Open the Testing view from the activity bar and click the Run Test" button, or use the hotkey `Ctrl/Cmd + ; A`
|
|
||||||
* See the output of the test result in the Test Results view.
|
|
||||||
* Make changes to `src/test/extension.test.ts` or create new test files inside the `test` folder.
|
|
||||||
* The provided test runner will only consider files matching the name pattern `**.test.ts`.
|
|
||||||
* You can create folders inside the `test` folder to structure your tests any way you want.
|
|
||||||
|
|
||||||
## Go further
|
|
||||||
|
|
||||||
* Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension).
|
|
||||||
* [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace.
|
|
||||||
* Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
//@ts-check
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
//@ts-check
|
|
||||||
/** @typedef {import('webpack').Configuration} WebpackConfig **/
|
|
||||||
|
|
||||||
/** @type WebpackConfig */
|
|
||||||
const extensionConfig = {
|
|
||||||
target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
|
|
||||||
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
|
|
||||||
|
|
||||||
entry: './client/src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
|
||||||
output: {
|
|
||||||
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
|
|
||||||
path: path.resolve(__dirname, 'dist'),
|
|
||||||
filename: 'extension.js',
|
|
||||||
libraryTarget: 'commonjs2'
|
|
||||||
},
|
|
||||||
externals: {
|
|
||||||
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
|
|
||||||
// modules added here also need to be added in the .vscodeignore file
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
|
|
||||||
extensions: ['.ts', '.js']
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.ts$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'ts-loader'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
devtool: 'nosources-source-map',
|
|
||||||
infrastructureLogging: {
|
|
||||||
level: "log", // enables logging required for problem matchers
|
|
||||||
},
|
|
||||||
};
|
|
||||||
module.exports = [extensionConfig];
|
|
||||||
@ -1,23 +1,19 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "reid"
|
name = "reid"
|
||||||
version = "1.0.0"
|
version = "1.0.0-beta.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["color", "cli"]
|
default = ["color"]
|
||||||
|
|
||||||
color = ["colored"]
|
color = ["colored"]
|
||||||
cli = ["argh", "stderrlog"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
## Make it easier to generate errors
|
## Make it easier to generate errors
|
||||||
thiserror = "1.0.44"
|
thiserror = "1.0.44"
|
||||||
reid-lib = { path = "../reid-llvm-lib", version = "1.0.0", registry="gitea-teascade" }
|
reid-lib = { path = "../reid-llvm-lib", version = "1.0.0-beta.1", registry="gitea-teascade" }
|
||||||
|
|
||||||
argh = { version = "0.1.13", optional = true }
|
colored = {version = "3.0.0", optional = true}
|
||||||
stderrlog = { version = "0.6.0", optional = true }
|
|
||||||
log = "*"
|
|
||||||
colored = { version = "3.0.0", optional = true }
|
|
||||||
@ -12,6 +12,7 @@ fn main() -> Result<(), std::io::Error> {
|
|||||||
libraries.push(libname);
|
libraries.push(libname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbg!(&filename);
|
||||||
let path = PathBuf::from(filename).canonicalize().unwrap();
|
let path = PathBuf::from(filename).canonicalize().unwrap();
|
||||||
let parent = path.with_extension("");
|
let parent = path.with_extension("");
|
||||||
let llvm_ir_path = parent.with_extension("ll");
|
let llvm_ir_path = parent.with_extension("ll");
|
||||||
@ -30,27 +31,27 @@ fn main() -> Result<(), std::io::Error> {
|
|||||||
match compile_simple(&text, PathBuf::from(&path), Some(cpu), vec![features]) {
|
match compile_simple(&text, PathBuf::from(&path), Some(cpu), vec![features]) {
|
||||||
Ok((
|
Ok((
|
||||||
CompileOutput {
|
CompileOutput {
|
||||||
triple: _triple,
|
triple,
|
||||||
assembly,
|
assembly,
|
||||||
obj_buffer,
|
obj_buffer,
|
||||||
llvm_ir: _llvm_ir,
|
llvm_ir,
|
||||||
},
|
},
|
||||||
CustomIRs { llir, mir },
|
CustomIRs { llir, mir },
|
||||||
)) => {
|
)) => {
|
||||||
log::trace!("{}", _llvm_ir);
|
println!("{}", llvm_ir);
|
||||||
log::debug!("Compiled with triple: {}\n", &_triple);
|
|
||||||
log::debug!("Output LLVM IR to {:?}", llvm_ir_path);
|
|
||||||
log::debug!("Output Assembly to {:?}", asm_path);
|
|
||||||
log::debug!("Output Object-file to {:?}\n", object_path);
|
|
||||||
log::debug!("Output LLIR-file to {:?}\n", llir_path);
|
|
||||||
log::debug!("Output MIR-file to {:?}\n", mir_path);
|
|
||||||
|
|
||||||
fs::write(&llvm_ir_path, &_llvm_ir).expect("Could not write LLVM IR -file!");
|
|
||||||
fs::write(&asm_path, &assembly).expect("Could not write Assembly-file!");
|
|
||||||
fs::write(&object_path, &obj_buffer).expect("Could not write Object-file!");
|
|
||||||
fs::write(&llir_path, &llir).expect("Could not write LLIR-file!");
|
|
||||||
fs::write(&mir_path, &mir).expect("Could not write MIR-file!");
|
|
||||||
let after = std::time::SystemTime::now();
|
let after = std::time::SystemTime::now();
|
||||||
|
println!("Compiled with triple: {}\n", &triple);
|
||||||
|
fs::write(&llvm_ir_path, &llvm_ir).expect("Could not write LLVM IR -file!");
|
||||||
|
println!("Output LLVM IR to {:?}", llvm_ir_path);
|
||||||
|
fs::write(&asm_path, &assembly).expect("Could not write Assembly-file!");
|
||||||
|
println!("Output Assembly to {:?}", asm_path);
|
||||||
|
fs::write(&object_path, &obj_buffer).expect("Could not write Object-file!");
|
||||||
|
println!("Output Object-file to {:?}\n", object_path);
|
||||||
|
fs::write(&llir_path, &llir).expect("Could not write LLIR-file!");
|
||||||
|
println!("Output LLIR-file to {:?}\n", llir_path);
|
||||||
|
fs::write(&mir_path, &mir).expect("Could not write MIR-file!");
|
||||||
|
println!("Output MIR-file to {:?}\n", mir_path);
|
||||||
println!(
|
println!(
|
||||||
"Compilation took: {:.2}ms\n",
|
"Compilation took: {:.2}ms\n",
|
||||||
(after.duration_since(before).unwrap().as_micros() as f32) / 1000.
|
(after.duration_since(before).unwrap().as_micros() as f32) / 1000.
|
||||||
@ -59,7 +60,7 @@ fn main() -> Result<(), std::io::Error> {
|
|||||||
println!("Linking {:?}", &object_path);
|
println!("Linking {:?}", &object_path);
|
||||||
|
|
||||||
let linker = std::env::var("LD").unwrap_or("ld".to_owned());
|
let linker = std::env::var("LD").unwrap_or("ld".to_owned());
|
||||||
let mut linker = LDRunner::from_command(&linker).with_library("c").with_library("m");
|
let mut linker = LDRunner::from_command(&linker).with_library("c");
|
||||||
for library in libraries {
|
for library in libraries {
|
||||||
linker = linker.with_library(&library);
|
linker = linker.with_library(&library);
|
||||||
}
|
}
|
||||||
@ -68,7 +69,7 @@ fn main() -> Result<(), std::io::Error> {
|
|||||||
Err(e) => panic!("{}", e),
|
Err(e) => panic!("{}", e),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
log::error!("Please input compiled file path!")
|
println!("Please input compiled file path!")
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
extern fn puts(message: *char) -> i32;
|
extern fn puts(message: *char) -> i32;
|
||||||
|
extern fn malloc(size: u64) -> *u8;
|
||||||
extern fn free(ptr: *u8);
|
extern fn free(ptr: *u8);
|
||||||
extern fn div(numerator: i32, denominator: i32) -> div_t;
|
extern fn div(numerator: i32, denominator: i32) -> div_t;
|
||||||
|
|
||||||
/// Editable string value that can be printed and extended
|
|
||||||
struct String {
|
struct String {
|
||||||
inner: *char,
|
inner: *char,
|
||||||
length: u64,
|
length: u64,
|
||||||
@ -12,18 +12,15 @@ struct String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl String {
|
impl String {
|
||||||
/// Returns a new empty `String`-object, which must later be manually freed.
|
|
||||||
pub fn new() -> String {
|
pub fn new() -> String {
|
||||||
String {
|
String {
|
||||||
inner: char::malloc(0),
|
inner: allocate(0),
|
||||||
length: 0,
|
length: 0,
|
||||||
max_length: 0,
|
max_length: 0,
|
||||||
must_be_freed: true,
|
must_be_freed: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `String`-object containing initially data from the given
|
|
||||||
/// string-literal which must be later freed.
|
|
||||||
pub fn from(str: *char) -> String {
|
pub fn from(str: *char) -> String {
|
||||||
let length = str_length(str) as u64;
|
let length = str_length(str) as u64;
|
||||||
let mut new = String::new();
|
let mut new = String::new();
|
||||||
@ -37,17 +34,15 @@ impl String {
|
|||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `concat`
|
|
||||||
pub fn push(&mut self, other: String) {
|
pub fn push(&mut self, other: String) {
|
||||||
for i in 0 .. (str_length(other.inner) - 1) {
|
for i in 0 .. (str_length(other.inner) - 1) {
|
||||||
add_char(self, other.inner[i]);
|
add_char(self, other.inner[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a character to the end of this string
|
|
||||||
pub fn add_char(&mut self, c: char) {
|
pub fn add_char(&mut self, c: char) {
|
||||||
if ((*self).length + 1) >= (*self).max_length {
|
if ((*self).length + 1) >= (*self).max_length {
|
||||||
let new = char::malloc((*self).max_length + 4);
|
let new = allocate((*self).max_length + 4) as *char;
|
||||||
copy_bits((*self).inner, new, (*self).max_length);
|
copy_bits((*self).inner, new, (*self).max_length);
|
||||||
|
|
||||||
if (*self).must_be_freed == true {
|
if (*self).must_be_freed == true {
|
||||||
@ -63,7 +58,6 @@ impl String {
|
|||||||
(*self).length = (*self).length + 1;
|
(*self).length = (*self).length + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats the given number into the end of the string.
|
|
||||||
pub fn push_num(&mut self, num: u64) {
|
pub fn push_num(&mut self, num: u64) {
|
||||||
if num >= 10 {
|
if num >= 10 {
|
||||||
self.push_num(num / 10)
|
self.push_num(num / 10)
|
||||||
@ -82,22 +76,18 @@ impl String {
|
|||||||
else if rem == 9 { self.add_char('9'); }
|
else if rem == 9 { self.add_char('9'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Concatenates `source` to the end of `destination`.
|
|
||||||
pub fn concat(&mut self, other: &String) {
|
pub fn concat(&mut self, other: &String) {
|
||||||
for i in 0 .. *other.length {
|
for i in 0 .. *other.length {
|
||||||
self.add_char(*other.inner[i]);
|
self.add_char(*other.inner[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Edits given `string` by setting the character at index `position` to be
|
|
||||||
/// `c`.
|
|
||||||
pub fn set(&mut self, c: char, position: u64) {
|
pub fn set(&mut self, c: char, position: u64) {
|
||||||
if position <= (*self).length {
|
if position <= (*self).length {
|
||||||
(*self).inner[position] = c;
|
(*self).inner[position] = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Frees this given string
|
|
||||||
pub fn free(&self) {
|
pub fn free(&self) {
|
||||||
free((*self).inner as *u8);
|
free((*self).inner as *u8);
|
||||||
}
|
}
|
||||||
@ -122,28 +112,27 @@ struct div_t {
|
|||||||
remainder: i32,
|
remainder: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print given string to stdout
|
|
||||||
pub fn print(message: String) {
|
pub fn print(message: String) {
|
||||||
puts(message.inner);
|
puts(message.inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Divide an integer, returning the quotient and remainder.
|
|
||||||
pub fn int_div(numerator: i32, denominator: i32) -> div_t {
|
pub fn int_div(numerator: i32, denominator: i32) -> div_t {
|
||||||
return div(numerator, denominator);
|
return div(numerator, denominator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (deprecated) creates a new editable string
|
pub fn allocate(size: u64) -> *u8 {
|
||||||
|
malloc(size)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_string() -> String {
|
pub fn new_string() -> String {
|
||||||
String {
|
String {
|
||||||
inner: char::malloc(0),
|
inner: allocate(0),
|
||||||
length: 0,
|
length: 0,
|
||||||
max_length: 0,
|
max_length: 0,
|
||||||
must_be_freed: true,
|
must_be_freed: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `String`-object containing initially data from the given
|
|
||||||
/// string-literal which must be later freed.
|
|
||||||
pub fn from_str(str: *char) -> String {
|
pub fn from_str(str: *char) -> String {
|
||||||
let length = str_length(str) as u64;
|
let length = str_length(str) as u64;
|
||||||
let mut new = new_string();
|
let mut new = new_string();
|
||||||
@ -157,10 +146,9 @@ pub fn from_str(str: *char) -> String {
|
|||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (deprecated) Adds a character to the end of a given string
|
|
||||||
pub fn add_char(string: &mut String, c: char) {
|
pub fn add_char(string: &mut String, c: char) {
|
||||||
if ((*string).length + 1) >= (*string).max_length {
|
if ((*string).length + 1) >= (*string).max_length {
|
||||||
let new = char::malloc((*string).max_length + 4);
|
let new = allocate((*string).max_length + 4) as *char;
|
||||||
copy_bits((*string).inner, new, (*string).max_length);
|
copy_bits((*string).inner, new, (*string).max_length);
|
||||||
|
|
||||||
if (*string).must_be_freed == true {
|
if (*string).must_be_freed == true {
|
||||||
@ -176,14 +164,12 @@ pub fn add_char(string: &mut String, c: char) {
|
|||||||
(*string).length = (*string).length + 1;
|
(*string).length = (*string).length + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (deprecated) sets a character in a string
|
|
||||||
pub fn set_char(string: &mut String, c: char, position: u64) {
|
pub fn set_char(string: &mut String, c: char, position: u64) {
|
||||||
if position <= (*string).length {
|
if position <= (*string).length {
|
||||||
(*string).inner[position] = c;
|
(*string).inner[position] = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (deprecated) frees given string
|
|
||||||
pub fn free_string(string: &String) {
|
pub fn free_string(string: &String) {
|
||||||
free((*string).inner as *u8);
|
free((*string).inner as *u8);
|
||||||
}
|
}
|
||||||
@ -202,7 +188,6 @@ fn str_length(string: *char) -> u32 {
|
|||||||
return pos + 1;
|
return pos + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (deprecated) concatenates number to the end of this string.
|
|
||||||
pub fn add_num_to_str(string: &mut String, num: u64) {
|
pub fn add_num_to_str(string: &mut String, num: u64) {
|
||||||
if num >= 10 {
|
if num >= 10 {
|
||||||
add_num_to_str(string, num / 10)
|
add_num_to_str(string, num / 10)
|
||||||
@ -221,15 +206,12 @@ pub fn add_num_to_str(string: &mut String, num: u64) {
|
|||||||
else if rem == 9 { add_char(string, '9'); }
|
else if rem == 9 { add_char(string, '9'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (deprecated) concatenates two strings to the destination
|
|
||||||
pub fn concat_strings(destination: &mut String, source: String) {
|
pub fn concat_strings(destination: &mut String, source: String) {
|
||||||
for i in 0 .. (str_length(source.inner) - 1) {
|
for i in 0 .. (str_length(source.inner) - 1) {
|
||||||
add_char(destination, source.inner[i]);
|
add_char(destination, source.inner[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `value` as clamped between `min` and `max`. Equivalent to
|
|
||||||
/// `max(min(value, max), min)`
|
|
||||||
pub fn clamp(min: f32, max: f32, value: f32) -> f32 {
|
pub fn clamp(min: f32, max: f32, value: f32) -> f32 {
|
||||||
if value > max {
|
if value > max {
|
||||||
return max;
|
return max;
|
||||||
@ -240,7 +222,6 @@ pub fn clamp(min: f32, max: f32, value: f32) -> f32 {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the absolute value of `value`.
|
|
||||||
pub fn abs(f: f32) -> f32 {
|
pub fn abs(f: f32) -> f32 {
|
||||||
if f < 0.0 {
|
if f < 0.0 {
|
||||||
return f * (0.0 - 1.0);
|
return f * (0.0 - 1.0);
|
||||||
|
|||||||
@ -7,7 +7,7 @@ static HEXADECIMAL_NUMERICS: &[char] = &[
|
|||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Clone, PartialOrd, Ord, Hash)]
|
#[derive(Eq, PartialEq, Clone, PartialOrd, Ord)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
/// Values
|
/// Values
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
@ -114,9 +114,6 @@ pub enum Token {
|
|||||||
|
|
||||||
Unknown(char),
|
Unknown(char),
|
||||||
|
|
||||||
Whitespace(String),
|
|
||||||
Comment(String),
|
|
||||||
Doc(String),
|
|
||||||
Eof,
|
Eof,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,9 +192,6 @@ impl ToString for Token {
|
|||||||
Token::Eof => String::new(),
|
Token::Eof => String::new(),
|
||||||
Token::Slash => String::from('/'),
|
Token::Slash => String::from('/'),
|
||||||
Token::Percent => String::from('%'),
|
Token::Percent => String::from('%'),
|
||||||
Token::Whitespace(val) => val.clone(),
|
|
||||||
Token::Comment(val) => format!("//{}", val.clone()),
|
|
||||||
Token::Doc(val) => format!("///{}", val.clone()),
|
|
||||||
Token::Unknown(val) => val.to_string(),
|
Token::Unknown(val) => val.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +207,7 @@ impl std::fmt::Debug for Token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A token with a position
|
/// A token with a position
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct FullToken {
|
pub struct FullToken {
|
||||||
pub token: Token,
|
pub token: Token,
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
@ -299,37 +293,13 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
|||||||
|
|
||||||
let variant = match character {
|
let variant = match character {
|
||||||
// Whitespace
|
// Whitespace
|
||||||
w if w.is_whitespace() => {
|
w if w.is_whitespace() => continue,
|
||||||
let mut whitespace = String::from(*w);
|
|
||||||
while let Some(w) = cursor.first() {
|
|
||||||
if !w.is_whitespace() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
whitespace.push(cursor.next().unwrap());
|
|
||||||
}
|
|
||||||
Token::Whitespace(whitespace)
|
|
||||||
}
|
|
||||||
// Comments
|
// Comments
|
||||||
'/' if cursor.first() == Some('/') => {
|
'/' if cursor.first() == Some('/') => {
|
||||||
cursor.next();
|
|
||||||
let doc = if cursor.first() == Some('/') {
|
|
||||||
cursor.next();
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut comment = String::new();
|
|
||||||
while !matches!(cursor.first(), Some('\n') | None) {
|
while !matches!(cursor.first(), Some('\n') | None) {
|
||||||
if let Some(c) = cursor.next() {
|
cursor.next();
|
||||||
comment.push(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if doc {
|
|
||||||
Token::Doc(comment)
|
|
||||||
} else {
|
|
||||||
Token::Comment(comment)
|
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
'\"' | '\'' => {
|
'\"' | '\'' => {
|
||||||
let mut value = String::new();
|
let mut value = String::new();
|
||||||
|
|||||||
@ -88,7 +88,7 @@ pub enum ExpressionKind {
|
|||||||
/// Array-indexed, e.g. <expr>[<expr>]
|
/// Array-indexed, e.g. <expr>[<expr>]
|
||||||
Indexed(Box<Expression>, Box<Expression>),
|
Indexed(Box<Expression>, Box<Expression>),
|
||||||
/// Struct-accessed, e.g. <expr>.<expr>
|
/// Struct-accessed, e.g. <expr>.<expr>
|
||||||
Accessed(Box<Expression>, String, TokenRange),
|
Accessed(Box<Expression>, String),
|
||||||
/// Associated function call, but with a shorthand
|
/// Associated function call, but with a shorthand
|
||||||
AccessCall(Box<Expression>, Box<FunctionCallExpression>),
|
AccessCall(Box<Expression>, Box<FunctionCallExpression>),
|
||||||
Binop(BinaryOperator, Box<Expression>, Box<Expression>),
|
Binop(BinaryOperator, Box<Expression>, Box<Expression>),
|
||||||
@ -159,12 +159,7 @@ impl BinaryOperator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FunctionCallExpression {
|
pub struct FunctionCallExpression(pub String, pub Vec<Expression>, pub TokenRange);
|
||||||
pub name: String,
|
|
||||||
pub params: Vec<Expression>,
|
|
||||||
pub range: TokenRange,
|
|
||||||
pub is_macro: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IfExpression(
|
pub struct IfExpression(
|
||||||
@ -184,7 +179,7 @@ pub struct LetStatement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ImportStatement(pub Vec<(String, TokenRange)>, pub TokenRange);
|
pub struct ImportStatement(pub Vec<String>, pub TokenRange);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub TokenRange);
|
pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub TokenRange);
|
||||||
@ -192,9 +187,8 @@ pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub To
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FunctionSignature {
|
pub struct FunctionSignature {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub documentation: Option<String>,
|
|
||||||
pub self_kind: SelfKind,
|
pub self_kind: SelfKind,
|
||||||
pub params: Vec<(String, Type, TokenRange)>,
|
pub params: Vec<(String, Type)>,
|
||||||
pub return_type: Option<Type>,
|
pub return_type: Option<Type>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub range: TokenRange,
|
pub range: TokenRange,
|
||||||
@ -202,13 +196,13 @@ pub struct FunctionSignature {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum SelfKind {
|
pub enum SelfKind {
|
||||||
Owned(Type),
|
Owned(TypeKind),
|
||||||
Borrow(Type),
|
Borrow(TypeKind),
|
||||||
MutBorrow(Type),
|
MutBorrow(TypeKind),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum ReturnType {
|
pub enum ReturnType {
|
||||||
Soft,
|
Soft,
|
||||||
Hard,
|
Hard,
|
||||||
@ -217,7 +211,7 @@ pub enum ReturnType {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StructExpression {
|
pub struct StructExpression {
|
||||||
name: String,
|
name: String,
|
||||||
fields: Vec<(String, Expression, TokenRange)>,
|
fields: Vec<(String, Expression)>,
|
||||||
range: TokenRange,
|
range: TokenRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,9 +267,9 @@ pub enum TopLevelStatement {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BinopDefinition {
|
pub struct BinopDefinition {
|
||||||
pub lhs: (String, Type, TokenRange),
|
pub lhs: (String, Type),
|
||||||
pub op: BinaryOperator,
|
pub op: BinaryOperator,
|
||||||
pub rhs: (String, Type, TokenRange),
|
pub rhs: (String, Type),
|
||||||
pub return_ty: Type,
|
pub return_ty: Type,
|
||||||
pub block: Block,
|
pub block: Block,
|
||||||
pub signature_range: TokenRange,
|
pub signature_range: TokenRange,
|
||||||
|
|||||||
@ -175,50 +175,7 @@ impl Parse for AssociatedFunctionCall {
|
|||||||
let ty = stream.parse()?;
|
let ty = stream.parse()?;
|
||||||
stream.expect(Token::Colon)?;
|
stream.expect(Token::Colon)?;
|
||||||
stream.expect(Token::Colon)?;
|
stream.expect(Token::Colon)?;
|
||||||
|
Ok(AssociatedFunctionCall(ty, stream.parse()?))
|
||||||
if stream.next_is_whitespace() {
|
|
||||||
stream.expecting_err_nonfatal("associated function name");
|
|
||||||
return Ok(AssociatedFunctionCall(
|
|
||||||
ty,
|
|
||||||
FunctionCallExpression {
|
|
||||||
name: String::new(),
|
|
||||||
params: Vec::new(),
|
|
||||||
range: stream.get_range_prev_curr().unwrap(),
|
|
||||||
is_macro: false,
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
match stream.parse() {
|
|
||||||
Ok(fn_call) => Ok(AssociatedFunctionCall(ty, fn_call)),
|
|
||||||
_ => {
|
|
||||||
if let Some(Token::Identifier(fn_name)) = stream.peek() {
|
|
||||||
stream.next();
|
|
||||||
stream.expected_err_nonfatal("associated function call");
|
|
||||||
|
|
||||||
Ok(AssociatedFunctionCall(
|
|
||||||
ty,
|
|
||||||
FunctionCallExpression {
|
|
||||||
name: fn_name,
|
|
||||||
params: Vec::new(),
|
|
||||||
range: stream.get_range_prev_curr().unwrap(),
|
|
||||||
is_macro: false,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
stream.expected_err_nonfatal("associated function name");
|
|
||||||
Ok(AssociatedFunctionCall(
|
|
||||||
ty,
|
|
||||||
FunctionCallExpression {
|
|
||||||
name: String::new(),
|
|
||||||
params: Vec::new(),
|
|
||||||
range: stream.get_range_prev_curr().unwrap(),
|
|
||||||
is_macro: false,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,11 +191,10 @@ where
|
|||||||
),
|
),
|
||||||
expr.0 .1,
|
expr.0 .1,
|
||||||
),
|
),
|
||||||
ExpressionKind::Accessed(value_expr, index_name, range) => Expression(
|
ExpressionKind::Accessed(value_expr, index_name) => Expression(
|
||||||
ExpressionKind::Accessed(
|
ExpressionKind::Accessed(
|
||||||
Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)),
|
Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)),
|
||||||
index_name.clone(),
|
index_name.clone(),
|
||||||
*range,
|
|
||||||
),
|
),
|
||||||
expr.0 .1,
|
expr.0 .1,
|
||||||
),
|
),
|
||||||
@ -287,9 +243,9 @@ impl Parse for PrimaryExpression {
|
|||||||
stream.get_range().unwrap(),
|
stream.get_range().unwrap(),
|
||||||
)
|
)
|
||||||
} else if let Some(Token::Star) = stream.peek() {
|
} else if let Some(Token::Star) = stream.peek() {
|
||||||
stream.next(); // Consume Star
|
stream.next(); // Consume Et
|
||||||
apply_inner(stream.parse()?, |e| {
|
apply_inner(stream.parse()?, |e| {
|
||||||
Expression(Kind::Deref(Box::new(e.0.clone())), e.0 .1)
|
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(
|
||||||
@ -443,9 +399,9 @@ impl Parse for PrimaryExpression {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
ValueIndex::Dot(val) => match val {
|
ValueIndex::Dot(val) => match val {
|
||||||
DotIndexKind::StructValueIndex(name, range) => {
|
DotIndexKind::StructValueIndex(name) => {
|
||||||
expr = Expression(
|
expr = Expression(
|
||||||
ExpressionKind::Accessed(Box::new(expr), name, range),
|
ExpressionKind::Accessed(Box::new(expr), name),
|
||||||
stream.get_range().unwrap(),
|
stream.get_range().unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -510,7 +466,7 @@ fn parse_binop_rhs(
|
|||||||
if curr_token_prec < next_prec {
|
if curr_token_prec < next_prec {
|
||||||
// Operator on the right of rhs has more precedence, turn
|
// Operator on the right of rhs has more precedence, turn
|
||||||
// rhs into lhs for new binop
|
// rhs into lhs for new binop
|
||||||
rhs = stream.parse_with(|mut st| parse_binop_rhs(&mut st, rhs, Some(op)))?;
|
rhs = parse_binop_rhs(stream, rhs, Some(op))?;
|
||||||
} else {
|
} else {
|
||||||
let _ = prev_operator.insert(next_op);
|
let _ = prev_operator.insert(next_op);
|
||||||
}
|
}
|
||||||
@ -581,20 +537,8 @@ impl Parse for BinaryOperator {
|
|||||||
impl Parse for FunctionCallExpression {
|
impl Parse for FunctionCallExpression {
|
||||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||||
if let Some(Token::Identifier(name)) = stream.next() {
|
if let Some(Token::Identifier(name)) = stream.next() {
|
||||||
let is_macro = if let Some(Token::Exclamation) = stream.peek() {
|
|
||||||
stream.next(); // Consume !
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
let args = stream.parse::<FunctionArgs>()?;
|
let args = stream.parse::<FunctionArgs>()?;
|
||||||
Ok(FunctionCallExpression {
|
Ok(FunctionCallExpression(name, args.0, stream.get_range().unwrap()))
|
||||||
name,
|
|
||||||
params: args.0,
|
|
||||||
range: stream.get_range().unwrap(),
|
|
||||||
is_macro,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Err(stream.expected_err("identifier")?)
|
Err(stream.expected_err("identifier")?)
|
||||||
}
|
}
|
||||||
@ -653,7 +597,7 @@ impl Parse for LetStatement {
|
|||||||
stream.expect(Token::Equals)?;
|
stream.expect(Token::Equals)?;
|
||||||
|
|
||||||
let expression = stream.parse()?;
|
let expression = stream.parse()?;
|
||||||
stream.expect_nonfatal(Token::Semi).ok();
|
stream.expect(Token::Semi)?;
|
||||||
Ok(LetStatement {
|
Ok(LetStatement {
|
||||||
name: variable,
|
name: variable,
|
||||||
ty,
|
ty,
|
||||||
@ -674,21 +618,19 @@ impl Parse for ImportStatement {
|
|||||||
let mut import_list = Vec::new();
|
let mut import_list = Vec::new();
|
||||||
|
|
||||||
if let Some(Token::Identifier(name)) = stream.next() {
|
if let Some(Token::Identifier(name)) = stream.next() {
|
||||||
import_list.push((name, stream.get_range_prev_curr().unwrap()));
|
import_list.push(name);
|
||||||
while stream.expect(Token::Colon).is_ok() && stream.expect(Token::Colon).is_ok() {
|
while stream.expect(Token::Colon).is_ok() && stream.expect(Token::Colon).is_ok() {
|
||||||
if let Some(Token::Identifier(name)) = stream.peek() {
|
if let Some(Token::Identifier(name)) = stream.next() {
|
||||||
stream.next(); // Consume identifier
|
import_list.push(name);
|
||||||
import_list.push((name, stream.get_range_prev_curr().unwrap()));
|
|
||||||
} else {
|
} else {
|
||||||
stream.expected_err_nonfatal("identifier");
|
Err(stream.expected_err("identifier")?)?
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(stream.expected_err("identifier")?)?
|
Err(stream.expected_err("identifier")?)?
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.expect_nonfatal(Token::Semi).ok();
|
stream.expect(Token::Semi)?;
|
||||||
|
|
||||||
Ok(ImportStatement(import_list, stream.get_range().unwrap()))
|
Ok(ImportStatement(import_list, stream.get_range().unwrap()))
|
||||||
}
|
}
|
||||||
@ -696,8 +638,6 @@ impl Parse for ImportStatement {
|
|||||||
|
|
||||||
impl Parse for FunctionDefinition {
|
impl Parse for FunctionDefinition {
|
||||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||||
let documentation = stream.find_documentation();
|
|
||||||
|
|
||||||
let is_pub = if let Some(Token::PubKeyword) = stream.peek() {
|
let is_pub = if let Some(Token::PubKeyword) = stream.peek() {
|
||||||
stream.next(); // Consume pub
|
stream.next(); // Consume pub
|
||||||
true
|
true
|
||||||
@ -706,10 +646,8 @@ impl Parse for FunctionDefinition {
|
|||||||
};
|
};
|
||||||
|
|
||||||
stream.expect(Token::FnKeyword)?;
|
stream.expect(Token::FnKeyword)?;
|
||||||
let mut signature: FunctionSignature = stream.parse()?;
|
|
||||||
signature.documentation = documentation;
|
|
||||||
Ok(FunctionDefinition(
|
Ok(FunctionDefinition(
|
||||||
signature,
|
stream.parse()?,
|
||||||
is_pub,
|
is_pub,
|
||||||
stream.parse()?,
|
stream.parse()?,
|
||||||
stream.get_range().unwrap(),
|
stream.get_range().unwrap(),
|
||||||
@ -718,7 +656,7 @@ impl Parse for FunctionDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct FunctionParam(String, Type, TokenRange);
|
struct FunctionParam(String, Type);
|
||||||
|
|
||||||
impl Parse for FunctionParam {
|
impl Parse for FunctionParam {
|
||||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||||
@ -726,7 +664,7 @@ impl Parse for FunctionParam {
|
|||||||
return Err(stream.expected_err("parameter name")?);
|
return Err(stream.expected_err("parameter name")?);
|
||||||
};
|
};
|
||||||
stream.expect(Token::Colon)?;
|
stream.expect(Token::Colon)?;
|
||||||
Ok(FunctionParam(arg_name, stream.parse()?, stream.get_range().unwrap()))
|
Ok(FunctionParam(arg_name, stream.parse()?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,18 +696,9 @@ impl Parse for SelfParam {
|
|||||||
};
|
};
|
||||||
if name == "self" {
|
if name == "self" {
|
||||||
match kind {
|
match kind {
|
||||||
SelfParamKind::BorrowMut => Ok(SelfParam(SelfKind::MutBorrow(Type(
|
SelfParamKind::BorrowMut => Ok(SelfParam(SelfKind::MutBorrow(TypeKind::Unknown))),
|
||||||
TypeKind::Unknown,
|
SelfParamKind::Borrow => Ok(SelfParam(SelfKind::Borrow(TypeKind::Unknown))),
|
||||||
stream.get_range_prev().unwrap(),
|
SelfParamKind::Owned => Ok(SelfParam(SelfKind::Owned(TypeKind::Unknown))),
|
||||||
)))),
|
|
||||||
SelfParamKind::Borrow => Ok(SelfParam(SelfKind::Borrow(Type(
|
|
||||||
TypeKind::Unknown,
|
|
||||||
stream.get_range_prev().unwrap(),
|
|
||||||
)))),
|
|
||||||
SelfParamKind::Owned => Ok(SelfParam(SelfKind::Owned(Type(
|
|
||||||
TypeKind::Unknown,
|
|
||||||
stream.get_range_prev().unwrap(),
|
|
||||||
)))),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(stream.expected_err("self parameter")?)
|
Err(stream.expected_err("self parameter")?)
|
||||||
@ -788,11 +717,11 @@ impl Parse for FunctionSignature {
|
|||||||
match &self_kind {
|
match &self_kind {
|
||||||
SelfKind::None => {
|
SelfKind::None => {
|
||||||
if let Ok(param) = stream.parse::<FunctionParam>() {
|
if let Ok(param) = stream.parse::<FunctionParam>() {
|
||||||
params.push((param.0, param.1, param.2));
|
params.push((param.0, param.1));
|
||||||
while let Some(Token::Comma) = stream.peek() {
|
while let Some(Token::Comma) = stream.peek() {
|
||||||
stream.next();
|
stream.next();
|
||||||
let param = stream.parse::<FunctionParam>()?;
|
let param = stream.parse::<FunctionParam>()?;
|
||||||
params.push((param.0, param.1, param.2));
|
params.push((param.0, param.1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -800,7 +729,7 @@ impl Parse for FunctionSignature {
|
|||||||
while let Some(Token::Comma) = stream.peek() {
|
while let Some(Token::Comma) = stream.peek() {
|
||||||
stream.next();
|
stream.next();
|
||||||
let param = stream.parse::<FunctionParam>()?;
|
let param = stream.parse::<FunctionParam>()?;
|
||||||
params.push((param.0, param.1, param.2));
|
params.push((param.0, param.1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -814,7 +743,6 @@ impl Parse for FunctionSignature {
|
|||||||
|
|
||||||
Ok(FunctionSignature {
|
Ok(FunctionSignature {
|
||||||
name,
|
name,
|
||||||
documentation: None,
|
|
||||||
params,
|
params,
|
||||||
self_kind,
|
self_kind,
|
||||||
return_type,
|
return_type,
|
||||||
@ -838,7 +766,7 @@ impl Parse for Block {
|
|||||||
// if semicolon is missing.
|
// if semicolon is missing.
|
||||||
if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) {
|
if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) {
|
||||||
// In theory could ignore the missing semicolon..
|
// In theory could ignore the missing semicolon..
|
||||||
stream.expected_err_nonfatal("semicolon to complete statement");
|
return Err(stream.expected_err("semicolon to complete statement")?);
|
||||||
}
|
}
|
||||||
|
|
||||||
statements.push(BlockLevelStatement::Expression(e));
|
statements.push(BlockLevelStatement::Expression(e));
|
||||||
@ -869,10 +797,9 @@ impl Parse for StructExpression {
|
|||||||
let Some(Token::Identifier(name)) = stream.next() else {
|
let Some(Token::Identifier(name)) = stream.next() else {
|
||||||
return Err(stream.expected_err("struct identifier")?);
|
return Err(stream.expected_err("struct identifier")?);
|
||||||
};
|
};
|
||||||
|
|
||||||
stream.expect(Token::BraceOpen)?;
|
stream.expect(Token::BraceOpen)?;
|
||||||
let named_list = stream.parse::<NamedFieldList<Expression>>()?;
|
let named_list = stream.parse::<NamedFieldList<Expression>>()?;
|
||||||
let fields = named_list.0.into_iter().map(|f| (f.0, f.1, f.2)).collect();
|
let fields = named_list.0.into_iter().map(|f| (f.0, f.1)).collect();
|
||||||
|
|
||||||
stream.expect(Token::BraceClose)?;
|
stream.expect(Token::BraceClose)?;
|
||||||
|
|
||||||
@ -949,35 +876,25 @@ impl Parse for ArrayValueIndex {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum DotIndexKind {
|
pub enum DotIndexKind {
|
||||||
StructValueIndex(String, TokenRange),
|
StructValueIndex(String),
|
||||||
FunctionCall(FunctionCallExpression),
|
FunctionCall(FunctionCallExpression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for DotIndexKind {
|
impl Parse for DotIndexKind {
|
||||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||||
stream.expect(Token::Dot)?;
|
stream.expect(Token::Dot)?;
|
||||||
if let Some(Token::Identifier(name)) = stream.peek() {
|
if let Some(Token::Identifier(name)) = stream.next() {
|
||||||
stream.next(); // Consume identifer
|
|
||||||
if let Ok(args) = stream.parse::<FunctionArgs>() {
|
if let Ok(args) = stream.parse::<FunctionArgs>() {
|
||||||
Ok(Self::FunctionCall(FunctionCallExpression {
|
Ok(Self::FunctionCall(FunctionCallExpression(
|
||||||
name,
|
name,
|
||||||
params: args.0,
|
args.0,
|
||||||
range: stream.get_range_prev().unwrap(),
|
stream.get_range_prev().unwrap(),
|
||||||
is_macro: false,
|
)))
|
||||||
}))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Self::StructValueIndex(name, stream.get_range_prev().unwrap()))
|
Ok(Self::StructValueIndex(name))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if stream.next_is_whitespace() {
|
return Err(stream.expected_err("struct index (number)")?);
|
||||||
stream.expecting_err_nonfatal("struct index");
|
|
||||||
Ok(Self::StructValueIndex(
|
|
||||||
String::new(),
|
|
||||||
stream.get_range_prev_curr().unwrap(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Err(stream.expecting_err("struct index")?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -991,7 +908,7 @@ impl Parse for BlockLevelStatement {
|
|||||||
Some(Token::ReturnKeyword) => {
|
Some(Token::ReturnKeyword) => {
|
||||||
stream.next();
|
stream.next();
|
||||||
let exp = stream.parse().ok();
|
let exp = stream.parse().ok();
|
||||||
stream.expect_nonfatal(Token::Semi).ok();
|
stream.expect(Token::Semi)?;
|
||||||
Stmt::Return(ReturnType::Hard, exp)
|
Stmt::Return(ReturnType::Hard, exp)
|
||||||
}
|
}
|
||||||
Some(Token::For) => {
|
Some(Token::For) => {
|
||||||
@ -1056,7 +973,7 @@ impl Parse for SetStatement {
|
|||||||
let var_ref = stream.parse()?;
|
let var_ref = stream.parse()?;
|
||||||
stream.expect(Token::Equals)?;
|
stream.expect(Token::Equals)?;
|
||||||
let expr = stream.parse()?;
|
let expr = stream.parse()?;
|
||||||
stream.expect_nonfatal(Token::Semi).ok();
|
stream.expect(Token::Semi)?;
|
||||||
Ok(SetStatement(var_ref, expr, stream.get_range().unwrap()))
|
Ok(SetStatement(var_ref, expr, stream.get_range().unwrap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1094,13 +1011,10 @@ impl Parse for TopLevelStatement {
|
|||||||
Ok(match stream.peek() {
|
Ok(match stream.peek() {
|
||||||
Some(Token::ImportKeyword) => Stmt::Import(stream.parse()?),
|
Some(Token::ImportKeyword) => Stmt::Import(stream.parse()?),
|
||||||
Some(Token::Extern) => {
|
Some(Token::Extern) => {
|
||||||
let documentation = stream.find_documentation();
|
|
||||||
stream.next(); // Consume Extern
|
stream.next(); // Consume Extern
|
||||||
stream.expect(Token::FnKeyword)?;
|
stream.expect(Token::FnKeyword)?;
|
||||||
let mut signature: FunctionSignature = stream.parse()?;
|
let extern_fn = Stmt::ExternFunction(stream.parse()?);
|
||||||
signature.documentation = documentation;
|
stream.expect(Token::Semi)?;
|
||||||
let extern_fn = Stmt::ExternFunction(signature);
|
|
||||||
stream.expect_nonfatal(Token::Semi).ok();
|
|
||||||
extern_fn
|
extern_fn
|
||||||
}
|
}
|
||||||
Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?),
|
Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?),
|
||||||
@ -1134,7 +1048,6 @@ impl Parse for BinopDefinition {
|
|||||||
let Some(Token::Identifier(lhs_name)) = stream.next() else {
|
let Some(Token::Identifier(lhs_name)) = stream.next() else {
|
||||||
return Err(stream.expected_err("lhs name")?);
|
return Err(stream.expected_err("lhs name")?);
|
||||||
};
|
};
|
||||||
let lhs_range = stream.get_range_prev_curr().unwrap();
|
|
||||||
stream.expect(Token::Colon)?;
|
stream.expect(Token::Colon)?;
|
||||||
let lhs_type = stream.parse()?;
|
let lhs_type = stream.parse()?;
|
||||||
stream.expect(Token::ParenClose)?;
|
stream.expect(Token::ParenClose)?;
|
||||||
@ -1145,7 +1058,6 @@ impl Parse for BinopDefinition {
|
|||||||
let Some(Token::Identifier(rhs_name)) = stream.next() else {
|
let Some(Token::Identifier(rhs_name)) = stream.next() else {
|
||||||
return Err(stream.expected_err("rhs name")?);
|
return Err(stream.expected_err("rhs name")?);
|
||||||
};
|
};
|
||||||
let rhs_range = stream.get_range_prev_curr().unwrap();
|
|
||||||
stream.expect(Token::Colon)?;
|
stream.expect(Token::Colon)?;
|
||||||
let rhs_type = stream.parse()?;
|
let rhs_type = stream.parse()?;
|
||||||
stream.expect(Token::ParenClose)?;
|
stream.expect(Token::ParenClose)?;
|
||||||
@ -1155,9 +1067,9 @@ impl Parse for BinopDefinition {
|
|||||||
stream.expect(Token::Arrow)?;
|
stream.expect(Token::Arrow)?;
|
||||||
|
|
||||||
Ok(BinopDefinition {
|
Ok(BinopDefinition {
|
||||||
lhs: (lhs_name, lhs_type, lhs_range),
|
lhs: (lhs_name, lhs_type),
|
||||||
op: operator,
|
op: operator,
|
||||||
rhs: (rhs_name, rhs_type, rhs_range),
|
rhs: (rhs_name, rhs_type),
|
||||||
return_ty: stream.parse()?,
|
return_ty: stream.parse()?,
|
||||||
block: stream.parse()?,
|
block: stream.parse()?,
|
||||||
signature_range,
|
signature_range,
|
||||||
@ -1178,11 +1090,11 @@ impl Parse for AssociatedFunctionBlock {
|
|||||||
match stream.peek() {
|
match stream.peek() {
|
||||||
Some(Token::FnKeyword) | Some(Token::PubKeyword) => {
|
Some(Token::FnKeyword) | Some(Token::PubKeyword) => {
|
||||||
let mut fun: FunctionDefinition = stream.parse()?;
|
let mut fun: FunctionDefinition = stream.parse()?;
|
||||||
match &mut fun.0.self_kind {
|
fun.0.self_kind = match fun.0.self_kind {
|
||||||
SelfKind::Owned(inner_ty) => inner_ty.0 = ty.0.clone(),
|
SelfKind::Owned(_) => SelfKind::Owned(ty.0.clone()),
|
||||||
SelfKind::Borrow(inner_ty) => inner_ty.0 = ty.0.clone(),
|
SelfKind::Borrow(_) => SelfKind::Borrow(ty.0.clone()),
|
||||||
SelfKind::MutBorrow(inner_ty) => inner_ty.0 = ty.0.clone(),
|
SelfKind::MutBorrow(_) => SelfKind::MutBorrow(ty.0.clone()),
|
||||||
SelfKind::None => {}
|
SelfKind::None => SelfKind::None,
|
||||||
};
|
};
|
||||||
functions.push(fun);
|
functions.push(fun);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, ReturnType},
|
ast::{self},
|
||||||
mir::{
|
mir::{
|
||||||
self, CustomTypeKey, FunctionParam, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind,
|
self, CustomTypeKey, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind, StructField,
|
||||||
StructField, StructType, WhileStatement,
|
StructType, WhileStatement,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -30,20 +30,12 @@ impl ast::Module {
|
|||||||
for stmt in &self.top_level_statements {
|
for stmt in &self.top_level_statements {
|
||||||
match stmt {
|
match stmt {
|
||||||
Import(import) => {
|
Import(import) => {
|
||||||
imports.push(mir::Import(
|
imports.push(mir::Import(import.0.clone(), import.1.as_meta(module_id)));
|
||||||
import
|
|
||||||
.0
|
|
||||||
.iter()
|
|
||||||
.map(|(s, range)| (s.clone(), range.as_meta(module_id)))
|
|
||||||
.collect(),
|
|
||||||
import.1.as_meta(module_id),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
FunctionDefinition(function_def) => functions.push(function_def.into_mir(module_id)),
|
FunctionDefinition(function_def) => functions.push(function_def.into_mir(module_id)),
|
||||||
ExternFunction(signature) => {
|
ExternFunction(signature) => {
|
||||||
let def = mir::FunctionDefinition {
|
let def = mir::FunctionDefinition {
|
||||||
name: signature.name.clone(),
|
name: signature.name.clone(),
|
||||||
documentation: signature.documentation.clone(),
|
|
||||||
linkage_name: None,
|
linkage_name: None,
|
||||||
is_pub: false,
|
is_pub: false,
|
||||||
is_imported: false,
|
is_imported: false,
|
||||||
@ -56,15 +48,9 @@ impl ast::Module {
|
|||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|p| mir::FunctionParam {
|
.map(|p| (p.0, p.1 .0.into_mir(module_id)))
|
||||||
name: p.0,
|
|
||||||
ty: p.1 .0.into_mir(module_id),
|
|
||||||
meta: p.2.as_meta(module_id),
|
|
||||||
})
|
|
||||||
.collect(),
|
.collect(),
|
||||||
kind: mir::FunctionDefinitionKind::Extern(false),
|
kind: mir::FunctionDefinitionKind::Extern(false),
|
||||||
source: Some(module_id),
|
|
||||||
signature_meta: signature.range.as_meta(module_id),
|
|
||||||
};
|
};
|
||||||
functions.push(def);
|
functions.push(def);
|
||||||
}
|
}
|
||||||
@ -102,17 +88,9 @@ impl ast::Module {
|
|||||||
signature_range,
|
signature_range,
|
||||||
}) => {
|
}) => {
|
||||||
binops.push(mir::BinopDefinition {
|
binops.push(mir::BinopDefinition {
|
||||||
lhs: mir::FunctionParam {
|
lhs: (lhs.0.clone(), lhs.1 .0.into_mir(module_id)),
|
||||||
name: lhs.0.clone(),
|
|
||||||
ty: lhs.1 .0.into_mir(module_id),
|
|
||||||
meta: lhs.2.as_meta(module_id),
|
|
||||||
},
|
|
||||||
op: op.mir(),
|
op: op.mir(),
|
||||||
rhs: mir::FunctionParam {
|
rhs: (rhs.0.clone(), rhs.1 .0.into_mir(module_id)),
|
||||||
name: rhs.0.clone(),
|
|
||||||
ty: rhs.1 .0.into_mir(module_id),
|
|
||||||
meta: rhs.2.as_meta(module_id),
|
|
||||||
},
|
|
||||||
return_type: return_ty.0.into_mir(module_id),
|
return_type: return_ty.0.into_mir(module_id),
|
||||||
fn_kind: mir::FunctionDefinitionKind::Local(
|
fn_kind: mir::FunctionDefinitionKind::Local(
|
||||||
block.into_mir(module_id),
|
block.into_mir(module_id),
|
||||||
@ -137,7 +115,6 @@ impl ast::Module {
|
|||||||
imports,
|
imports,
|
||||||
associated_functions,
|
associated_functions,
|
||||||
functions,
|
functions,
|
||||||
globals: Vec::new(),
|
|
||||||
path: self.path.clone(),
|
path: self.path.clone(),
|
||||||
is_main: self.is_main,
|
is_main: self.is_main,
|
||||||
tokens: self.tokens,
|
tokens: self.tokens,
|
||||||
@ -152,32 +129,27 @@ impl ast::FunctionDefinition {
|
|||||||
|
|
||||||
let mut params = Vec::new();
|
let mut params = Vec::new();
|
||||||
match &signature.self_kind {
|
match &signature.self_kind {
|
||||||
ast::SelfKind::Borrow(ty) => params.push(mir::FunctionParam {
|
ast::SelfKind::Borrow(type_kind) => params.push((
|
||||||
name: "self".to_owned(),
|
"self".to_owned(),
|
||||||
ty: mir::TypeKind::Borrow(Box::new(ty.0.into_mir(module_id)), false),
|
mir::TypeKind::Borrow(Box::new(type_kind.into_mir(module_id)), false),
|
||||||
meta: ty.1.as_meta(module_id),
|
)),
|
||||||
}),
|
ast::SelfKind::MutBorrow(type_kind) => params.push((
|
||||||
ast::SelfKind::MutBorrow(ty) => params.push(mir::FunctionParam {
|
"self".to_owned(),
|
||||||
name: "self".to_owned(),
|
mir::TypeKind::Borrow(Box::new(type_kind.into_mir(module_id)), true),
|
||||||
ty: mir::TypeKind::Borrow(Box::new(ty.0.into_mir(module_id)), true),
|
)),
|
||||||
meta: ty.1.as_meta(module_id),
|
ast::SelfKind::Owned(type_kind) => params.push(("self".to_owned(), type_kind.into_mir(module_id))),
|
||||||
}),
|
|
||||||
ast::SelfKind::Owned(ty) => params.push(mir::FunctionParam {
|
|
||||||
name: "self".to_owned(),
|
|
||||||
ty: ty.0.into_mir(module_id),
|
|
||||||
meta: ty.1.as_meta(module_id),
|
|
||||||
}),
|
|
||||||
ast::SelfKind::None => {}
|
ast::SelfKind::None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
params.extend(signature.params.iter().cloned().map(|p| FunctionParam {
|
params.extend(
|
||||||
name: p.0,
|
signature
|
||||||
ty: p.1 .0.into_mir(module_id),
|
.params
|
||||||
meta: p.2.as_meta(module_id),
|
.iter()
|
||||||
}));
|
.cloned()
|
||||||
|
.map(|p| (p.0, p.1 .0.into_mir(module_id))),
|
||||||
|
);
|
||||||
mir::FunctionDefinition {
|
mir::FunctionDefinition {
|
||||||
name: signature.name.clone(),
|
name: signature.name.clone(),
|
||||||
documentation: signature.documentation.clone(),
|
|
||||||
linkage_name: None,
|
linkage_name: None,
|
||||||
is_pub: *is_pub,
|
is_pub: *is_pub,
|
||||||
is_imported: false,
|
is_imported: false,
|
||||||
@ -188,8 +160,6 @@ impl ast::FunctionDefinition {
|
|||||||
.unwrap_or(mir::TypeKind::Void),
|
.unwrap_or(mir::TypeKind::Void),
|
||||||
parameters: params,
|
parameters: params,
|
||||||
kind: mir::FunctionDefinitionKind::Local(block.into_mir(module_id), (range).as_meta(module_id)),
|
kind: mir::FunctionDefinitionKind::Local(block.into_mir(module_id), (range).as_meta(module_id)),
|
||||||
source: Some(module_id),
|
|
||||||
signature_meta: signature.range.as_meta(module_id),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,9 +207,8 @@ impl ast::Block {
|
|||||||
);
|
);
|
||||||
let let_statement = mir::Statement(
|
let let_statement = mir::Statement(
|
||||||
StmtKind::Let(counter_var.clone(), true, start.process(module_id)),
|
StmtKind::Let(counter_var.clone(), true, start.process(module_id)),
|
||||||
start.1.as_meta(module_id),
|
counter_range.as_meta(module_id),
|
||||||
);
|
);
|
||||||
let statement_range = counter_range.clone() + start.1 + end.1 + block.2;
|
|
||||||
|
|
||||||
let set_new = mir::Statement(
|
let set_new = mir::Statement(
|
||||||
StmtKind::Set(
|
StmtKind::Set(
|
||||||
@ -265,33 +234,8 @@ impl ast::Block {
|
|||||||
),
|
),
|
||||||
counter_range.as_meta(module_id),
|
counter_range.as_meta(module_id),
|
||||||
);
|
);
|
||||||
|
let mut block = block.into_mir(module_id);
|
||||||
let mir_block = if let Some((ret_kind, ret_expr)) = &block.1 {
|
block.statements.push(set_new);
|
||||||
if *ret_kind == ReturnType::Soft {
|
|
||||||
if let Some(ret_expr) = ret_expr {
|
|
||||||
let mir_ret = ret_expr.process(module_id);
|
|
||||||
let mut clone = block.clone();
|
|
||||||
clone.1 = None;
|
|
||||||
let mut mir_block = clone.into_mir(module_id);
|
|
||||||
mir_block
|
|
||||||
.statements
|
|
||||||
.push(mir::Statement(StmtKind::Expression(mir_ret.clone()), mir_ret.1));
|
|
||||||
mir_block.statements.push(set_new);
|
|
||||||
mir_block
|
|
||||||
} else {
|
|
||||||
let mut mir_block = block.into_mir(module_id);
|
|
||||||
mir_block.statements.push(set_new);
|
|
||||||
mir_block
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
block.into_mir(module_id)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let mut mir_block = block.into_mir(module_id);
|
|
||||||
mir_block.statements.push(set_new);
|
|
||||||
mir_block
|
|
||||||
};
|
|
||||||
|
|
||||||
let while_statement = mir::Statement(
|
let while_statement = mir::Statement(
|
||||||
StmtKind::While(WhileStatement {
|
StmtKind::While(WhileStatement {
|
||||||
condition: mir::Expression(
|
condition: mir::Expression(
|
||||||
@ -304,23 +248,23 @@ impl ast::Block {
|
|||||||
Box::new(end.process(module_id)),
|
Box::new(end.process(module_id)),
|
||||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||||
),
|
),
|
||||||
end.1.as_meta(module_id),
|
counter_range.as_meta(module_id),
|
||||||
),
|
),
|
||||||
block: mir_block.clone(),
|
block,
|
||||||
meta: (*counter_range + end.1 + block.2).as_meta(module_id),
|
meta: self.2.as_meta(module_id),
|
||||||
}),
|
}),
|
||||||
(*counter_range + end.1 + block.2).as_meta(module_id),
|
self.2.as_meta(module_id),
|
||||||
);
|
);
|
||||||
|
|
||||||
let inner_scope = StmtKind::Expression(mir::Expression(
|
let inner_scope = StmtKind::Expression(mir::Expression(
|
||||||
mir::ExprKind::Block(mir::Block {
|
mir::ExprKind::Block(mir::Block {
|
||||||
statements: vec![let_statement, while_statement],
|
statements: vec![let_statement, while_statement],
|
||||||
return_expression: None,
|
return_expression: None,
|
||||||
meta: statement_range.as_meta(module_id),
|
meta: counter_range.as_meta(module_id) + end.1.as_meta(module_id),
|
||||||
}),
|
}),
|
||||||
statement_range.as_meta(module_id),
|
counter_range.as_meta(module_id) + end.1.as_meta(module_id),
|
||||||
));
|
));
|
||||||
(inner_scope, statement_range)
|
(inner_scope, self.2)
|
||||||
}
|
}
|
||||||
ast::BlockLevelStatement::WhileLoop(expression, block) => (
|
ast::BlockLevelStatement::WhileLoop(expression, block) => (
|
||||||
StmtKind::While(WhileStatement {
|
StmtKind::While(WhileStatement {
|
||||||
@ -328,7 +272,7 @@ impl ast::Block {
|
|||||||
block: block.into_mir(module_id),
|
block: block.into_mir(module_id),
|
||||||
meta: self.2.as_meta(module_id),
|
meta: self.2.as_meta(module_id),
|
||||||
}),
|
}),
|
||||||
expression.1 + block.2,
|
self.2,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -378,11 +322,10 @@ impl ast::Expression {
|
|||||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||||
),
|
),
|
||||||
ast::ExpressionKind::FunctionCall(fn_call_expr) => mir::ExprKind::FunctionCall(mir::FunctionCall {
|
ast::ExpressionKind::FunctionCall(fn_call_expr) => mir::ExprKind::FunctionCall(mir::FunctionCall {
|
||||||
name: fn_call_expr.name.clone(),
|
name: fn_call_expr.0.clone(),
|
||||||
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||||
parameters: fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(),
|
parameters: fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(),
|
||||||
meta: fn_call_expr.range.as_meta(module_id),
|
meta: fn_call_expr.2.as_meta(module_id),
|
||||||
is_macro: fn_call_expr.is_macro,
|
|
||||||
}),
|
}),
|
||||||
ast::ExpressionKind::BlockExpr(block) => mir::ExprKind::Block(block.into_mir(module_id)),
|
ast::ExpressionKind::BlockExpr(block) => mir::ExprKind::Block(block.into_mir(module_id)),
|
||||||
ast::ExpressionKind::IfExpr(if_expression) => {
|
ast::ExpressionKind::IfExpr(if_expression) => {
|
||||||
@ -408,18 +351,17 @@ impl ast::Expression {
|
|||||||
Box::new(idx_expr.process(module_id)),
|
Box::new(idx_expr.process(module_id)),
|
||||||
),
|
),
|
||||||
ast::ExpressionKind::StructExpression(struct_init) => mir::ExprKind::Struct(
|
ast::ExpressionKind::StructExpression(struct_init) => mir::ExprKind::Struct(
|
||||||
CustomTypeKey(struct_init.name.clone(), module_id),
|
struct_init.name.clone(),
|
||||||
struct_init
|
struct_init
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(n, e, r)| (n.clone(), e.process(module_id), r.as_meta(module_id)))
|
.map(|(n, e)| (n.clone(), e.process(module_id)))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
ast::ExpressionKind::Accessed(expression, name, name_range) => mir::ExprKind::Accessed(
|
ast::ExpressionKind::Accessed(expression, name) => mir::ExprKind::Accessed(
|
||||||
Box::new(expression.process(module_id)),
|
Box::new(expression.process(module_id)),
|
||||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||||
name.clone(),
|
name.clone(),
|
||||||
name_range.as_meta(module_id),
|
|
||||||
),
|
),
|
||||||
ast::ExpressionKind::Borrow(expr, mutable) => {
|
ast::ExpressionKind::Borrow(expr, mutable) => {
|
||||||
mir::ExprKind::Borrow(Box::new(expr.process(module_id)), *mutable)
|
mir::ExprKind::Borrow(Box::new(expr.process(module_id)), *mutable)
|
||||||
@ -467,15 +409,14 @@ impl ast::Expression {
|
|||||||
ast::ExpressionKind::AssociatedFunctionCall(ty, fn_call_expr) => mir::ExprKind::AssociatedFunctionCall(
|
ast::ExpressionKind::AssociatedFunctionCall(ty, fn_call_expr) => mir::ExprKind::AssociatedFunctionCall(
|
||||||
ty.0.into_mir(module_id),
|
ty.0.into_mir(module_id),
|
||||||
mir::FunctionCall {
|
mir::FunctionCall {
|
||||||
name: fn_call_expr.name.clone(),
|
name: fn_call_expr.0.clone(),
|
||||||
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||||
parameters: fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(),
|
parameters: fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(),
|
||||||
meta: fn_call_expr.range.as_meta(module_id),
|
meta: fn_call_expr.2.as_meta(module_id),
|
||||||
is_macro: fn_call_expr.is_macro,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ast::ExpressionKind::AccessCall(expression, fn_call_expr) => {
|
ast::ExpressionKind::AccessCall(expression, fn_call_expr) => {
|
||||||
let mut params: Vec<_> = fn_call_expr.params.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(
|
params.insert(
|
||||||
0,
|
0,
|
||||||
mir::Expression(
|
mir::Expression(
|
||||||
@ -483,18 +424,13 @@ impl ast::Expression {
|
|||||||
expression.1.as_meta(module_id),
|
expression.1.as_meta(module_id),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if fn_call_expr.is_macro {
|
|
||||||
panic!("Macros aren't supported as access-calls!");
|
|
||||||
};
|
|
||||||
|
|
||||||
mir::ExprKind::AssociatedFunctionCall(
|
mir::ExprKind::AssociatedFunctionCall(
|
||||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||||
mir::FunctionCall {
|
mir::FunctionCall {
|
||||||
name: fn_call_expr.name.clone(),
|
name: fn_call_expr.0.clone(),
|
||||||
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||||
parameters: params,
|
parameters: params,
|
||||||
meta: fn_call_expr.range.as_meta(module_id),
|
meta: fn_call_expr.2.as_meta(module_id),
|
||||||
is_macro: fn_call_expr.is_macro,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -583,7 +519,7 @@ impl ast::TypeKind {
|
|||||||
}
|
}
|
||||||
ast::TypeKind::Ptr(type_kind) => mir::TypeKind::UserPtr(Box::new(type_kind.clone().into_mir(source_mod))),
|
ast::TypeKind::Ptr(type_kind) => mir::TypeKind::UserPtr(Box::new(type_kind.clone().into_mir(source_mod))),
|
||||||
ast::TypeKind::F16 => mir::TypeKind::F16,
|
ast::TypeKind::F16 => mir::TypeKind::F16,
|
||||||
ast::TypeKind::F32B => mir::TypeKind::F16B,
|
ast::TypeKind::F32B => mir::TypeKind::F32B,
|
||||||
ast::TypeKind::F32 => mir::TypeKind::F32,
|
ast::TypeKind::F32 => mir::TypeKind::F32,
|
||||||
ast::TypeKind::F64 => mir::TypeKind::F64,
|
ast::TypeKind::F64 => mir::TypeKind::F64,
|
||||||
ast::TypeKind::F80 => mir::TypeKind::F80,
|
ast::TypeKind::F80 => mir::TypeKind::F80,
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
//! Contains relevant code for parsing tokens received from
|
//! Contains relevant code for parsing tokens received from
|
||||||
//! Lexing/Tokenizing-stage.
|
//! Lexing/Tokenizing-stage.
|
||||||
|
|
||||||
use std::{cell::RefCell, rc::Rc};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::parse::Parse,
|
ast::parse::Parse,
|
||||||
lexer::{FullToken, Token},
|
lexer::{FullToken, Token},
|
||||||
@ -14,7 +12,6 @@ use crate::{
|
|||||||
pub struct TokenStream<'a, 'b> {
|
pub struct TokenStream<'a, 'b> {
|
||||||
ref_position: Option<&'b mut usize>,
|
ref_position: Option<&'b mut usize>,
|
||||||
tokens: &'a [FullToken],
|
tokens: &'a [FullToken],
|
||||||
errors: Rc<RefCell<Vec<Error>>>,
|
|
||||||
pub position: usize,
|
pub position: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +20,6 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
TokenStream {
|
TokenStream {
|
||||||
ref_position: None,
|
ref_position: None,
|
||||||
tokens,
|
tokens,
|
||||||
errors: Rc::new(RefCell::new(Vec::new())),
|
|
||||||
position: 0,
|
position: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,42 +38,24 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns expected-error for the next token in-line. Useful in conjunction
|
|
||||||
/// with [`TokenStream::peek`]
|
|
||||||
pub fn expected_err_nonfatal<T: Into<String>>(&mut self, expected: T) {
|
|
||||||
let err = match self.expected_err(expected) {
|
|
||||||
Ok(e) => e,
|
|
||||||
Err(e) => e,
|
|
||||||
};
|
|
||||||
self.errors.borrow_mut().push(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns expected-error for the previous token that was already consumed.
|
/// Returns expected-error for the previous token that was already consumed.
|
||||||
/// Useful in conjunction with [`TokenStream::next`]
|
/// Useful in conjunction with [`TokenStream::next`]
|
||||||
pub fn expecting_err<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> {
|
pub fn expecting_err<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> {
|
||||||
let next_token = self.peek().unwrap_or(Token::Eof);
|
let next_token = self.peek().unwrap_or(Token::Eof);
|
||||||
let pos = self.next_token(self.position).0;
|
|
||||||
Ok(Error::Expected(
|
Ok(Error::Expected(
|
||||||
expected.into(),
|
expected.into(),
|
||||||
next_token,
|
next_token,
|
||||||
TokenRange { start: pos, end: pos },
|
TokenRange {
|
||||||
|
start: self.position,
|
||||||
|
end: self.position,
|
||||||
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns expected-error for the previous token that was already consumed.
|
|
||||||
/// Useful in conjunction with [`TokenStream::next`]
|
|
||||||
pub fn expecting_err_nonfatal<T: Into<String>>(&mut self, expected: T) {
|
|
||||||
let err = match self.expecting_err(expected) {
|
|
||||||
Ok(e) => e,
|
|
||||||
Err(e) => e,
|
|
||||||
};
|
|
||||||
self.errors.borrow_mut().push(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expect(&mut self, token: Token) -> Result<(), Error> {
|
pub fn expect(&mut self, token: Token) -> Result<(), Error> {
|
||||||
if let (pos, Some(peeked)) = self.next_token(self.position) {
|
if let Some(peeked) = self.peek() {
|
||||||
if token == peeked.token {
|
if token == peeked {
|
||||||
self.position = pos + 1;
|
self.position += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(self.expecting_err(token)?)
|
Err(self.expecting_err(token)?)
|
||||||
@ -87,62 +65,38 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_documentation(&mut self) -> Option<String> {
|
|
||||||
let mut from = self.position;
|
|
||||||
let mut documentation = None;
|
|
||||||
while let Some(token) = self.tokens.get(from) {
|
|
||||||
if matches!(token.token, Token::Whitespace(_) | Token::Comment(_) | Token::Doc(_)) {
|
|
||||||
from += 1;
|
|
||||||
if let Token::Doc(doctext) = &token.token {
|
|
||||||
documentation = Some(
|
|
||||||
match documentation {
|
|
||||||
Some(t) => t + " ",
|
|
||||||
None => String::new(),
|
|
||||||
} + doctext.trim(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
documentation
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expect_nonfatal(&mut self, token: Token) -> Result<(), ()> {
|
|
||||||
if let (pos, Some(peeked)) = self.next_token(self.position) {
|
|
||||||
if token == peeked.token {
|
|
||||||
self.position = pos + 1;
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
self.expecting_err_nonfatal(token);
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.expecting_err_nonfatal(token);
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next(&mut self) -> Option<Token> {
|
pub fn next(&mut self) -> Option<Token> {
|
||||||
let (position, token) = self.next_token(self.position);
|
let value = if self.tokens.len() < self.position {
|
||||||
self.position = position + 1;
|
None
|
||||||
token.map(|t| t.token.clone())
|
} else {
|
||||||
|
Some(self.tokens[self.position].token.clone())
|
||||||
|
};
|
||||||
|
self.position += 1;
|
||||||
|
value
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn previous(&mut self) -> Option<Token> {
|
pub fn previous(&mut self) -> Option<Token> {
|
||||||
let (_, token) = self.previous_token(self.position);
|
if (self.position as i32 - 1) < 0 {
|
||||||
token.map(|t| t.token.clone())
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.tokens[self.position - 1].token.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek(&mut self) -> Option<Token> {
|
pub fn peek(&mut self) -> Option<Token> {
|
||||||
let (_, token) = self.next_token(self.position);
|
if self.tokens.len() < self.position {
|
||||||
token.map(|t| t.token.clone())
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.tokens[self.position].token.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek2(&mut self) -> Option<Token> {
|
pub fn peek2(&mut self) -> Option<Token> {
|
||||||
let (pos2, _) = self.next_token(self.position);
|
if self.tokens.len() < (self.position + 1) {
|
||||||
let (_, token) = self.next_token(pos2 + 1);
|
None
|
||||||
token.map(|t| t.token.clone())
|
} else {
|
||||||
|
Some(self.tokens[self.position + 1].token.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the next value of trait Parse. If the parse succeeded, the related
|
/// Parse the next value of trait Parse. If the parse succeeded, the related
|
||||||
@ -207,7 +161,6 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
let clone = TokenStream {
|
let clone = TokenStream {
|
||||||
ref_position: Some(&mut ref_pos),
|
ref_position: Some(&mut ref_pos),
|
||||||
tokens: self.tokens,
|
tokens: self.tokens,
|
||||||
errors: self.errors.clone(),
|
|
||||||
position,
|
position,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -220,29 +173,6 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_with<T, U>(&mut self, fun: T) -> Result<U, Error>
|
|
||||||
where
|
|
||||||
T: FnOnce(TokenStream) -> Result<U, Error>,
|
|
||||||
{
|
|
||||||
let mut ref_pos = self.position;
|
|
||||||
|
|
||||||
let position = self.position;
|
|
||||||
let clone = TokenStream {
|
|
||||||
ref_position: Some(&mut ref_pos),
|
|
||||||
tokens: self.tokens,
|
|
||||||
errors: self.errors.clone(),
|
|
||||||
position,
|
|
||||||
};
|
|
||||||
|
|
||||||
match fun(clone) {
|
|
||||||
Ok(res) => {
|
|
||||||
self.position = ref_pos.max(self.position);
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_range(&self) -> Option<TokenRange> {
|
pub fn get_range(&self) -> Option<TokenRange> {
|
||||||
self.ref_position.as_ref().map(|ref_pos| TokenRange {
|
self.ref_position.as_ref().map(|ref_pos| TokenRange {
|
||||||
start: **ref_pos,
|
start: **ref_pos,
|
||||||
@ -255,56 +185,9 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
pub fn get_range_prev(&self) -> Option<TokenRange> {
|
pub fn get_range_prev(&self) -> Option<TokenRange> {
|
||||||
self.ref_position.as_ref().map(|ref_pos| TokenRange {
|
self.ref_position.as_ref().map(|ref_pos| TokenRange {
|
||||||
start: **ref_pos,
|
start: **ref_pos,
|
||||||
end: self.previous_token(self.position).0,
|
end: self.position - 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets range of the previous token only.
|
|
||||||
pub fn get_range_prev_curr(&self) -> Option<TokenRange> {
|
|
||||||
Some(TokenRange {
|
|
||||||
start: self.previous_token(self.position).0,
|
|
||||||
end: self.previous_token(self.position).0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn previous_token(&self, mut from: usize) -> (usize, Option<&'a FullToken>) {
|
|
||||||
from -= 1;
|
|
||||||
while let Some(token) = self.tokens.get(from) {
|
|
||||||
if matches!(token.token, Token::Whitespace(_) | Token::Comment(_) | Token::Doc(_)) {
|
|
||||||
from -= 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(from, self.tokens.get(from))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_token(&self, mut from: usize) -> (usize, Option<&'a FullToken>) {
|
|
||||||
while let Some(token) = self.tokens.get(from) {
|
|
||||||
if matches!(token.token, Token::Whitespace(_) | Token::Comment(_) | Token::Doc(_)) {
|
|
||||||
from += 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(from, self.tokens.get(from))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn errors(&self) -> Vec<Error> {
|
|
||||||
self.errors.borrow().clone().clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next_is_whitespace(&self) -> bool {
|
|
||||||
if let Some(token) = self.tokens.get(self.position) {
|
|
||||||
if let Token::Whitespace(_) = token.token {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TokenStream<'_, '_> {
|
impl Drop for TokenStream<'_, '_> {
|
||||||
@ -334,8 +217,8 @@ impl std::ops::Add for TokenRange {
|
|||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
TokenRange {
|
TokenRange {
|
||||||
start: self.start.min(rhs.start).min(rhs.end),
|
start: self.start.min(rhs.start),
|
||||||
end: self.end.max(rhs.end).max(rhs.start),
|
end: self.end.min(rhs.end),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,12 +2,12 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use reid_lib::{
|
use reid_lib::{
|
||||||
builder::{InstructionValue, TypeValue},
|
builder::{InstructionValue, TypeValue},
|
||||||
Block, Instr,
|
Block,
|
||||||
};
|
};
|
||||||
|
|
||||||
use mir::{CustomTypeKey, FunctionDefinitionKind, IfExpression, TypeKind, WhileStatement};
|
use mir::{CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, TypeKind, WhileStatement};
|
||||||
|
|
||||||
use crate::mir::{self, FunctionParam, Metadata, SourceModuleId};
|
use crate::mir;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Allocator {
|
pub struct Allocator {
|
||||||
@ -16,18 +16,21 @@ pub struct Allocator {
|
|||||||
|
|
||||||
pub struct AllocatorScope<'ctx, 'a> {
|
pub struct AllocatorScope<'ctx, 'a> {
|
||||||
pub(super) block: &'a mut Block<'ctx>,
|
pub(super) block: &'a mut Block<'ctx>,
|
||||||
pub(super) mod_id: SourceModuleId,
|
|
||||||
pub(super) type_values: &'a HashMap<CustomTypeKey, TypeValue>,
|
pub(super) type_values: &'a HashMap<CustomTypeKey, TypeValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocator {
|
impl Allocator {
|
||||||
pub fn from(func: &FunctionDefinitionKind, params: &Vec<FunctionParam>, scope: &mut AllocatorScope) -> Allocator {
|
pub fn from(
|
||||||
|
func: &FunctionDefinitionKind,
|
||||||
|
params: &Vec<(String, TypeKind)>,
|
||||||
|
scope: &mut AllocatorScope,
|
||||||
|
) -> Allocator {
|
||||||
func.allocate(scope, params)
|
func.allocate(scope, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate(&mut self, meta: &Metadata, ty: &TypeKind) -> Option<InstructionValue> {
|
pub fn allocate(&mut self, name: &String, ty: &TypeKind) -> Option<InstructionValue> {
|
||||||
let mut allocs = self.allocations.iter().cloned().enumerate();
|
let mut allocs = self.allocations.iter().cloned().enumerate();
|
||||||
let val = allocs.find(|a| a.1 .0 == *meta && a.1 .1 == *ty);
|
let val = allocs.find(|a| a.1 .0 == *name && a.1 .1 == *ty);
|
||||||
if let Some((i, _)) = val {
|
if let Some((i, _)) = val {
|
||||||
self.allocations.remove(i);
|
self.allocations.remove(i);
|
||||||
}
|
}
|
||||||
@ -36,13 +39,13 @@ impl Allocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Allocation(Metadata, TypeKind, InstructionValue);
|
pub struct Allocation(String, TypeKind, InstructionValue);
|
||||||
|
|
||||||
impl mir::FunctionDefinitionKind {
|
impl mir::FunctionDefinitionKind {
|
||||||
fn allocate<'ctx, 'a>(
|
fn allocate<'ctx, 'a>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut AllocatorScope<'ctx, 'a>,
|
scope: &mut AllocatorScope<'ctx, 'a>,
|
||||||
parameters: &Vec<mir::FunctionParam>,
|
parameters: &Vec<(String, TypeKind)>,
|
||||||
) -> Allocator {
|
) -> Allocator {
|
||||||
let mut allocated = Vec::new();
|
let mut allocated = Vec::new();
|
||||||
match &self {
|
match &self {
|
||||||
@ -51,11 +54,11 @@ impl mir::FunctionDefinitionKind {
|
|||||||
let allocation = scope
|
let allocation = scope
|
||||||
.block
|
.block
|
||||||
.build_named(
|
.build_named(
|
||||||
param.name.clone(),
|
param.0.clone(),
|
||||||
reid_lib::Instr::Alloca(param.ty.get_type(scope.type_values)),
|
reid_lib::Instr::Alloca(param.1.get_type(scope.type_values)),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
allocated.push(Allocation(param.meta, param.ty.clone(), allocation));
|
allocated.push(Allocation(param.0.clone(), param.1.clone(), allocation));
|
||||||
}
|
}
|
||||||
allocated.extend(block.allocate(scope));
|
allocated.extend(block.allocate(scope));
|
||||||
}
|
}
|
||||||
@ -100,7 +103,7 @@ impl mir::Statement {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
allocated.push(Allocation(
|
allocated.push(Allocation(
|
||||||
named_variable_ref.2,
|
named_variable_ref.1.clone(),
|
||||||
named_variable_ref.0.clone(),
|
named_variable_ref.0.clone(),
|
||||||
allocation,
|
allocation,
|
||||||
));
|
));
|
||||||
@ -133,42 +136,17 @@ impl mir::Expression {
|
|||||||
allocated.extend(expr.allocate(scope));
|
allocated.extend(expr.allocate(scope));
|
||||||
allocated.extend(idx.allocate(scope));
|
allocated.extend(idx.allocate(scope));
|
||||||
}
|
}
|
||||||
mir::ExprKind::Accessed(expression, ..) => {
|
mir::ExprKind::Accessed(expression, _, _) => {
|
||||||
allocated.extend(expression.allocate(scope));
|
allocated.extend(expression.allocate(scope));
|
||||||
}
|
}
|
||||||
mir::ExprKind::Array(expressions) => {
|
mir::ExprKind::Array(expressions) => {
|
||||||
let (_, ty) = self.return_type(&Default::default(), scope.mod_id).unwrap();
|
|
||||||
let TypeKind::Array(elem_ty, _) = &ty else { panic!() };
|
|
||||||
let array_name = format!("{}.{}", elem_ty, expressions.len());
|
|
||||||
|
|
||||||
let allocation = scope
|
|
||||||
.block
|
|
||||||
.build_named(array_name, Instr::Alloca(ty.get_type(scope.type_values)))
|
|
||||||
.unwrap();
|
|
||||||
allocated.push(Allocation(self.1, ty, allocation));
|
|
||||||
|
|
||||||
for expression in expressions {
|
for expression in expressions {
|
||||||
allocated.extend(expression.allocate(scope));
|
allocated.extend(expression.allocate(scope));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::ExprKind::Struct(key, items) => {
|
mir::ExprKind::Struct(_, items) => {
|
||||||
let (_, ty) = self.return_type(&Default::default(), scope.mod_id).unwrap();
|
for (_, expression) in items {
|
||||||
let allocation = scope
|
|
||||||
.block
|
|
||||||
.build_named(key.0.clone(), Instr::Alloca(ty.get_type(scope.type_values)))
|
|
||||||
.unwrap();
|
|
||||||
allocated.push(Allocation(self.1, ty, allocation));
|
|
||||||
|
|
||||||
for (field_name, expression, _) in items {
|
|
||||||
allocated.extend(expression.allocate(scope));
|
allocated.extend(expression.allocate(scope));
|
||||||
|
|
||||||
let (_, ty) = expression.return_type(&Default::default(), scope.mod_id).unwrap();
|
|
||||||
|
|
||||||
let allocation = scope
|
|
||||||
.block
|
|
||||||
.build_named(field_name, Instr::Alloca(ty.get_type(scope.type_values)))
|
|
||||||
.unwrap();
|
|
||||||
allocated.push(Allocation(expression.1, ty, allocation));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::ExprKind::Literal(_) => {}
|
mir::ExprKind::Literal(_) => {}
|
||||||
@ -176,7 +154,11 @@ impl mir::Expression {
|
|||||||
allocated.extend(lhs.allocate(scope));
|
allocated.extend(lhs.allocate(scope));
|
||||||
allocated.extend(rhs.allocate(scope));
|
allocated.extend(rhs.allocate(scope));
|
||||||
}
|
}
|
||||||
mir::ExprKind::FunctionCall(fn_call) => allocated.extend(fn_call.allocate(&fn_call.name, scope)),
|
mir::ExprKind::FunctionCall(FunctionCall { parameters, .. }) => {
|
||||||
|
for param in parameters {
|
||||||
|
allocated.extend(param.allocate(scope));
|
||||||
|
}
|
||||||
|
}
|
||||||
mir::ExprKind::If(IfExpression(cond, then_ex, else_ex)) => {
|
mir::ExprKind::If(IfExpression(cond, then_ex, else_ex)) => {
|
||||||
allocated.extend(cond.allocate(scope));
|
allocated.extend(cond.allocate(scope));
|
||||||
allocated.extend(then_ex.allocate(scope));
|
allocated.extend(then_ex.allocate(scope));
|
||||||
@ -192,30 +174,11 @@ impl mir::Expression {
|
|||||||
mir::ExprKind::CastTo(expression, _) => {
|
mir::ExprKind::CastTo(expression, _) => {
|
||||||
allocated.extend(expression.allocate(scope));
|
allocated.extend(expression.allocate(scope));
|
||||||
}
|
}
|
||||||
mir::ExprKind::AssociatedFunctionCall(ty, fn_call) => {
|
mir::ExprKind::AssociatedFunctionCall(_, FunctionCall { parameters, .. }) => {
|
||||||
allocated.extend(fn_call.allocate(&format!("{}::{}", ty, fn_call.name), scope))
|
for param in parameters {
|
||||||
}
|
|
||||||
mir::ExprKind::GlobalRef(..) => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
allocated
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mir::FunctionCall {
|
|
||||||
fn allocate<'ctx, 'a>(&self, name: &String, scope: &mut AllocatorScope<'ctx, 'a>) -> Vec<Allocation> {
|
|
||||||
let mut allocated = Vec::new();
|
|
||||||
|
|
||||||
for param in &self.parameters {
|
|
||||||
allocated.extend(param.allocate(scope));
|
allocated.extend(param.allocate(scope));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if self.return_type != TypeKind::Void {
|
|
||||||
let allocation = scope
|
|
||||||
.block
|
|
||||||
.build_named(name, Instr::Alloca(self.return_type.get_type(scope.type_values)))
|
|
||||||
.unwrap();
|
|
||||||
allocated.push(Allocation(self.meta, self.return_type.clone(), allocation));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allocated
|
allocated
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValueKind, Instr, Type};
|
use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValue, Instr, Type};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{ErrorKind, StackValueKind},
|
codegen::{ErrorKind, StackValueKind},
|
||||||
mir::{
|
mir::{BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, TypeKind},
|
||||||
implement::TypeCategory, BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition,
|
|
||||||
FunctionDefinitionKind, FunctionParam, TypeKind,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::scope::{Scope, StackValue};
|
use super::scope::{Scope, StackValue};
|
||||||
@ -26,431 +23,50 @@ const INTEGERS: [TypeKind; 10] = [
|
|||||||
const FLOATS: [TypeKind; 7] = [
|
const FLOATS: [TypeKind; 7] = [
|
||||||
TypeKind::F16,
|
TypeKind::F16,
|
||||||
TypeKind::F32,
|
TypeKind::F32,
|
||||||
TypeKind::F16B,
|
TypeKind::F32B,
|
||||||
TypeKind::F64,
|
TypeKind::F64,
|
||||||
TypeKind::F80,
|
TypeKind::F80,
|
||||||
TypeKind::F128,
|
TypeKind::F128,
|
||||||
TypeKind::F128PPC,
|
TypeKind::F128PPC,
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
|
||||||
pub enum LLVMIntrinsicKind {
|
|
||||||
Max(TypeKind),
|
|
||||||
Min(TypeKind),
|
|
||||||
Abs(TypeKind),
|
|
||||||
Memcpy(TypeKind),
|
|
||||||
Sqrt(TypeKind),
|
|
||||||
PowI(TypeKind, TypeKind),
|
|
||||||
Pow(TypeKind),
|
|
||||||
Sin(TypeKind),
|
|
||||||
Cos(TypeKind),
|
|
||||||
Tan(TypeKind),
|
|
||||||
ASin(TypeKind),
|
|
||||||
ACos(TypeKind),
|
|
||||||
ATan(TypeKind),
|
|
||||||
ATan2(TypeKind),
|
|
||||||
SinH(TypeKind),
|
|
||||||
CosH(TypeKind),
|
|
||||||
TanH(TypeKind),
|
|
||||||
Log(TypeKind),
|
|
||||||
Log2(TypeKind),
|
|
||||||
Log10(TypeKind),
|
|
||||||
Copysign(TypeKind),
|
|
||||||
Floor(TypeKind),
|
|
||||||
Ceil(TypeKind),
|
|
||||||
Trunc(TypeKind),
|
|
||||||
RoundEven(TypeKind),
|
|
||||||
Round(TypeKind),
|
|
||||||
}
|
|
||||||
|
|
||||||
const INTRINSIC_IDENT: &str = "reid.intrinsic";
|
|
||||||
const MALLOC_IDENT: &str = "malloc";
|
|
||||||
|
|
||||||
macro_rules! doc {
|
|
||||||
($str:expr) => {
|
|
||||||
Some($str.to_string())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn form_intrinsics() -> Vec<FunctionDefinition> {
|
pub fn form_intrinsics() -> Vec<FunctionDefinition> {
|
||||||
let mut intrinsics = Vec::new();
|
let intrinsics = Vec::new();
|
||||||
|
|
||||||
intrinsics.push(FunctionDefinition {
|
|
||||||
name: MALLOC_IDENT.to_owned(),
|
|
||||||
documentation: doc!("Allocates `size` bytes and returns a `u8`-pointer."),
|
|
||||||
linkage_name: Some("malloc".to_owned()),
|
|
||||||
is_pub: false,
|
|
||||||
is_imported: true,
|
|
||||||
return_type: TypeKind::UserPtr(Box::new(TypeKind::U8)),
|
|
||||||
parameters: vec![FunctionParam {
|
|
||||||
name: "size".to_owned(),
|
|
||||||
ty: TypeKind::U64,
|
|
||||||
meta: Default::default(),
|
|
||||||
}],
|
|
||||||
kind: FunctionDefinitionKind::Extern(false),
|
|
||||||
source: None,
|
|
||||||
signature_meta: Default::default(),
|
|
||||||
});
|
|
||||||
|
|
||||||
intrinsics
|
intrinsics
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simple_intrinsic<T: Into<String> + Clone>(
|
pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDefinition> {
|
||||||
name: T,
|
match name {
|
||||||
doc: T,
|
"sizeof" => Some(FunctionDefinition {
|
||||||
params: Vec<T>,
|
|
||||||
ret: TypeKind,
|
|
||||||
intrisic: LLVMIntrinsicKind,
|
|
||||||
) -> FunctionDefinition {
|
|
||||||
FunctionDefinition {
|
|
||||||
name: name.into(),
|
|
||||||
documentation: Some(doc.into()),
|
|
||||||
linkage_name: None,
|
|
||||||
is_pub: true,
|
|
||||||
is_imported: false,
|
|
||||||
return_type: ret.clone(),
|
|
||||||
parameters: params
|
|
||||||
.iter()
|
|
||||||
.map(|p| FunctionParam::from(p.clone(), ret.clone()))
|
|
||||||
.collect(),
|
|
||||||
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicLLVM(intrisic, ret.clone()))),
|
|
||||||
source: None,
|
|
||||||
signature_meta: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
|
|
||||||
let mut intrinsics = Vec::new();
|
|
||||||
if let TypeKind::Array(_, len) = ty {
|
|
||||||
intrinsics.push(FunctionDefinition {
|
|
||||||
name: "length".to_owned(),
|
|
||||||
documentation: doc!("Returns the length of this given array"),
|
|
||||||
linkage_name: None,
|
|
||||||
is_pub: true,
|
|
||||||
is_imported: false,
|
|
||||||
return_type: TypeKind::U64,
|
|
||||||
parameters: vec![FunctionParam {
|
|
||||||
name: String::from("self"),
|
|
||||||
ty: TypeKind::Borrow(Box::new(ty.clone()), false),
|
|
||||||
meta: Default::default(),
|
|
||||||
}],
|
|
||||||
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicConst(*len))),
|
|
||||||
source: None,
|
|
||||||
signature_meta: Default::default(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ty.category() == TypeCategory::Real {
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"sqrt",
|
|
||||||
"Calculates the square-root of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Sqrt(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"sin",
|
|
||||||
"Calculates sine of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Sin(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"cos",
|
|
||||||
"Calculates cosine of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Cos(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"tan",
|
|
||||||
"Calculates tangent of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Tan(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"sinh",
|
|
||||||
"Calculates hyperbolic sine of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::SinH(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"cosh",
|
|
||||||
"Calculates hyperbolic cosine of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::CosH(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"tanh",
|
|
||||||
"Calculates hyperbolic tangent of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::TanH(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"asin",
|
|
||||||
"Calculates arcsine of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::ASin(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"acos",
|
|
||||||
"Calculates arccosine of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::ACos(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"atan",
|
|
||||||
"Calculates arctangent of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::ATan(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"atan2",
|
|
||||||
"Calculates 2-argument arctangent of `value`",
|
|
||||||
vec!["self", "other"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::ATan2(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"log",
|
|
||||||
"Returns logₑ of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Log(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"log2",
|
|
||||||
"Returns log₂ of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Log2(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"log10",
|
|
||||||
"Returns log₁₀ of `value`",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Log10(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"floor",
|
|
||||||
"Rounds `value` towards negative infinity.",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Floor(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"ceil",
|
|
||||||
"Rounds `value` towards positive infinity.",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Ceil(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"trunc",
|
|
||||||
"Truncates `value` to the integer nearest to `0`.",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Trunc(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"round",
|
|
||||||
"Rounds `value` to the closest even integer.",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Round(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"even",
|
|
||||||
"Rounds `value` to the closest even integer.",
|
|
||||||
vec!["self"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::RoundEven(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"pow",
|
|
||||||
"Returns `value` raised to the exponent of `exponent`.",
|
|
||||||
vec!["self", "exponent"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Pow(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(FunctionDefinition {
|
|
||||||
name: "powi".to_owned(),
|
|
||||||
documentation: doc!("Returns `value` raised to the exponent of `exponent`."),
|
|
||||||
linkage_name: None,
|
|
||||||
is_pub: true,
|
|
||||||
is_imported: false,
|
|
||||||
return_type: ty.clone(),
|
|
||||||
parameters: vec![
|
|
||||||
FunctionParam {
|
|
||||||
name: String::from("self"),
|
|
||||||
ty: ty.clone(),
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
FunctionParam {
|
|
||||||
name: String::from("exponent"),
|
|
||||||
ty: TypeKind::U32,
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicLLVM(
|
|
||||||
LLVMIntrinsicKind::PowI(ty.clone(), TypeKind::U32),
|
|
||||||
ty.clone(),
|
|
||||||
))),
|
|
||||||
source: None,
|
|
||||||
signature_meta: Default::default(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
match ty.category() {
|
|
||||||
TypeCategory::Integer | TypeCategory::Real | TypeCategory::Bool => {
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"max",
|
|
||||||
"Returns the larger of `a` and `b`.",
|
|
||||||
vec!["self", "other"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Max(ty.clone()),
|
|
||||||
));
|
|
||||||
intrinsics.push(simple_intrinsic(
|
|
||||||
"min",
|
|
||||||
"Returns the smaller of `a` and `b`.",
|
|
||||||
vec!["self", "other"],
|
|
||||||
ty.clone(),
|
|
||||||
LLVMIntrinsicKind::Min(ty.clone()),
|
|
||||||
));
|
|
||||||
if ty.signed() {
|
|
||||||
intrinsics.push(FunctionDefinition {
|
|
||||||
name: "abs".to_owned(),
|
|
||||||
documentation: doc!("Returns the absolute value of `value`."),
|
|
||||||
linkage_name: None,
|
|
||||||
is_pub: true,
|
|
||||||
is_imported: false,
|
|
||||||
return_type: ty.clone(),
|
|
||||||
parameters: vec![FunctionParam {
|
|
||||||
name: String::from("self"),
|
|
||||||
ty: ty.clone(),
|
|
||||||
meta: Default::default(),
|
|
||||||
}],
|
|
||||||
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleUnaryInstr({
|
|
||||||
let ty = ty.clone();
|
|
||||||
|scope, param| {
|
|
||||||
let intrinsic = scope.get_intrinsic(LLVMIntrinsicKind::Abs(ty));
|
|
||||||
let constant = scope.block.build(Instr::Constant(ConstValueKind::Bool(false))).unwrap();
|
|
||||||
let value = scope
|
|
||||||
.block
|
|
||||||
.build(Instr::FunctionCall(intrinsic, vec![param, constant]))
|
|
||||||
.unwrap();
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}))),
|
|
||||||
source: None,
|
|
||||||
signature_meta: Default::default(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
intrinsics.push(FunctionDefinition {
|
|
||||||
name: "sizeof".to_owned(),
|
name: "sizeof".to_owned(),
|
||||||
documentation: doc!("Simply returns the size of type `T` in bytes."),
|
|
||||||
linkage_name: None,
|
linkage_name: None,
|
||||||
is_pub: true,
|
is_pub: true,
|
||||||
is_imported: false,
|
is_imported: false,
|
||||||
return_type: TypeKind::U64,
|
return_type: TypeKind::U64,
|
||||||
parameters: Vec::new(),
|
parameters: Vec::new(),
|
||||||
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSizeOf(ty.clone()))),
|
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSizeOf(ty.clone()))),
|
||||||
source: None,
|
}),
|
||||||
signature_meta: Default::default(),
|
"alloca" => Some(FunctionDefinition {
|
||||||
});
|
name: "alloca".to_owned(),
|
||||||
intrinsics.push(FunctionDefinition {
|
|
||||||
name: "malloc".to_owned(),
|
|
||||||
documentation: doc!("Allocates `T::sizeof() * size` bytes and returns a pointer to `T`."),
|
|
||||||
linkage_name: None,
|
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())),
|
||||||
parameters: vec![FunctionParam {
|
parameters: vec![(String::from("size"), TypeKind::U64)],
|
||||||
name: String::from("size"),
|
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicAlloca(ty.clone()))),
|
||||||
ty: TypeKind::U64,
|
}),
|
||||||
meta: Default::default(),
|
"null" => Some(FunctionDefinition {
|
||||||
}],
|
|
||||||
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMalloc(ty.clone()))),
|
|
||||||
source: None,
|
|
||||||
signature_meta: Default::default(),
|
|
||||||
});
|
|
||||||
|
|
||||||
intrinsics.push(FunctionDefinition {
|
|
||||||
name: "memcpy".to_owned(),
|
|
||||||
documentation: doc!(
|
|
||||||
"Copies `T::sizeof() * size` bytes from pointer `source` to pointer
|
|
||||||
`destination`."
|
|
||||||
),
|
|
||||||
linkage_name: None,
|
|
||||||
is_pub: true,
|
|
||||||
is_imported: false,
|
|
||||||
return_type: TypeKind::Void,
|
|
||||||
parameters: vec![
|
|
||||||
FunctionParam {
|
|
||||||
name: String::from("destination"),
|
|
||||||
ty: TypeKind::UserPtr(Box::new(ty.clone())),
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
FunctionParam {
|
|
||||||
name: String::from("source"),
|
|
||||||
ty: TypeKind::UserPtr(Box::new(ty.clone())),
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
FunctionParam {
|
|
||||||
name: String::from("length"),
|
|
||||||
ty: TypeKind::U64,
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMemcpy(ty.clone()))),
|
|
||||||
source: None,
|
|
||||||
signature_meta: Default::default(),
|
|
||||||
});
|
|
||||||
|
|
||||||
intrinsics.push(FunctionDefinition {
|
|
||||||
name: "null".to_owned(),
|
name: "null".to_owned(),
|
||||||
documentation: doc!("Returns a null-pointer of type `T`."),
|
|
||||||
linkage_name: None,
|
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())),
|
||||||
parameters: Vec::new(),
|
parameters: Vec::new(),
|
||||||
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicNullPtr(ty.clone()))),
|
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicNullPtr(ty.clone()))),
|
||||||
source: None,
|
}),
|
||||||
signature_meta: Default::default(),
|
_ => None,
|
||||||
});
|
}
|
||||||
|
|
||||||
intrinsics.push(FunctionDefinition {
|
|
||||||
name: "is_null".to_owned(),
|
|
||||||
documentation: doc!("Returns a boolean representing if `val` is a nullptr or not."),
|
|
||||||
linkage_name: None,
|
|
||||||
is_pub: true,
|
|
||||||
is_imported: false,
|
|
||||||
return_type: TypeKind::Bool,
|
|
||||||
parameters: vec![FunctionParam {
|
|
||||||
name: "value".to_string(),
|
|
||||||
ty: TypeKind::UserPtr(Box::new(ty.clone())),
|
|
||||||
meta: Default::default(),
|
|
||||||
}],
|
|
||||||
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicIsNull)),
|
|
||||||
source: None,
|
|
||||||
signature_meta: Default::default(),
|
|
||||||
});
|
|
||||||
|
|
||||||
intrinsics
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDefinition> {
|
|
||||||
get_intrinsic_assoc_functions(ty).into_iter().find(|f| f.name == name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
|
fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
|
||||||
@ -458,19 +74,11 @@ where
|
|||||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||||
{
|
{
|
||||||
BinopDefinition {
|
BinopDefinition {
|
||||||
lhs: FunctionParam {
|
lhs: ("lhs".to_owned(), ty.clone()),
|
||||||
name: "lhs".to_owned(),
|
|
||||||
ty: ty.clone(),
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
op,
|
op,
|
||||||
rhs: FunctionParam {
|
rhs: ("rhs".to_owned(), ty.clone()),
|
||||||
name: "rhs".to_owned(),
|
|
||||||
ty: ty.clone(),
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
return_type: ty.clone(),
|
return_type: ty.clone(),
|
||||||
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleBinaryInstr(fun))),
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))),
|
||||||
meta: Default::default(),
|
meta: Default::default(),
|
||||||
exported: false,
|
exported: false,
|
||||||
}
|
}
|
||||||
@ -481,19 +89,11 @@ where
|
|||||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||||
{
|
{
|
||||||
BinopDefinition {
|
BinopDefinition {
|
||||||
lhs: FunctionParam {
|
lhs: ("lhs".to_owned(), lhs.clone()),
|
||||||
name: "lhs".to_owned(),
|
|
||||||
ty: lhs.clone(),
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
op,
|
op,
|
||||||
rhs: FunctionParam {
|
rhs: ("rhs".to_owned(), rhs.clone()),
|
||||||
name: "rhs".to_owned(),
|
|
||||||
ty: rhs.clone(),
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
return_type: lhs.clone(),
|
return_type: lhs.clone(),
|
||||||
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleBinaryInstr(fun))),
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))),
|
||||||
meta: Default::default(),
|
meta: Default::default(),
|
||||||
exported: false,
|
exported: false,
|
||||||
}
|
}
|
||||||
@ -504,17 +104,9 @@ where
|
|||||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||||
{
|
{
|
||||||
BinopDefinition {
|
BinopDefinition {
|
||||||
lhs: FunctionParam {
|
lhs: ("lhs".to_owned(), ty.clone()),
|
||||||
name: "lhs".to_owned(),
|
|
||||||
ty: ty.clone(),
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
op,
|
op,
|
||||||
rhs: FunctionParam {
|
rhs: ("rhs".to_owned(), ty.clone()),
|
||||||
name: "rhs".to_owned(),
|
|
||||||
ty: ty.clone(),
|
|
||||||
meta: Default::default(),
|
|
||||||
},
|
|
||||||
return_type: TypeKind::Bool,
|
return_type: TypeKind::Bool,
|
||||||
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))),
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))),
|
||||||
meta: Default::default(),
|
meta: Default::default(),
|
||||||
@ -581,17 +173,26 @@ pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
|
|||||||
scope.block.build(Instr::XOr(lhs, rhs)).unwrap()
|
scope.block.build(Instr::XOr(lhs, rhs)).unwrap()
|
||||||
}));
|
}));
|
||||||
if ty.signed() {
|
if ty.signed() {
|
||||||
intrinsics.push(complex_binop_def(BitshiftRight, &ty, &ty, |scope, lhs, rhs| {
|
intrinsics.push(complex_binop_def(
|
||||||
scope.block.build(Instr::ShiftRightArithmetic(lhs, rhs)).unwrap()
|
BitshiftRight,
|
||||||
}));
|
&ty,
|
||||||
|
&TypeKind::U64,
|
||||||
|
|scope, lhs, rhs| scope.block.build(Instr::ShiftRightArithmetic(lhs, rhs)).unwrap(),
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
intrinsics.push(complex_binop_def(BitshiftRight, &ty, &ty, |scope, lhs, rhs| {
|
intrinsics.push(complex_binop_def(
|
||||||
scope.block.build(Instr::ShiftRightLogical(lhs, rhs)).unwrap()
|
BitshiftRight,
|
||||||
}));
|
&ty,
|
||||||
|
&TypeKind::U64,
|
||||||
|
|scope, lhs, rhs| scope.block.build(Instr::ShiftRightLogical(lhs, rhs)).unwrap(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
intrinsics.push(complex_binop_def(BitshiftLeft, &ty, &ty, |scope, lhs, rhs| {
|
intrinsics.push(complex_binop_def(
|
||||||
scope.block.build(Instr::ShiftLeft(lhs, rhs)).unwrap()
|
BitshiftLeft,
|
||||||
}));
|
&ty,
|
||||||
|
&TypeKind::U64,
|
||||||
|
|scope, lhs, rhs| scope.block.build(Instr::ShiftLeft(lhs, rhs)).unwrap(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
for ty in INTEGERS.iter().chain(&[TypeKind::Bool, TypeKind::Char]) {
|
for ty in INTEGERS.iter().chain(&[TypeKind::Bool, TypeKind::Char]) {
|
||||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
|
||||||
@ -614,22 +215,17 @@ pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
|
|||||||
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
|
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
|
||||||
scope.block.build(Instr::FDiv(lhs, rhs)).unwrap()
|
scope.block.build(Instr::FDiv(lhs, rhs)).unwrap()
|
||||||
}));
|
}));
|
||||||
intrinsics.push(simple_binop_def(Mod, &ty, {
|
intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
|
||||||
let ty = ty.clone();
|
|
||||||
|scope, lhs, rhs| {
|
|
||||||
let div = scope.block.build(Instr::FDiv(lhs, rhs)).unwrap();
|
let div = scope.block.build(Instr::FDiv(lhs, rhs)).unwrap();
|
||||||
let fun = scope.get_intrinsic(LLVMIntrinsicKind::Trunc(ty));
|
let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
|
||||||
let div_truncated = scope.block.build(Instr::FunctionCall(fun, vec![div])).unwrap();
|
scope.block.build(Instr::Sub(lhs, mul)).unwrap()
|
||||||
let mul = scope.block.build(Instr::FMul(rhs, div_truncated)).unwrap();
|
|
||||||
scope.block.build(Instr::FSub(lhs, mul)).unwrap()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::NE), &ty, |scope, lhs, rhs| {
|
|
||||||
scope.block.build(Instr::FCmp(CmpPredicate::NE, lhs, rhs)).unwrap()
|
|
||||||
}));
|
}));
|
||||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
|
||||||
scope.block.build(Instr::FCmp(CmpPredicate::EQ, lhs, rhs)).unwrap()
|
scope.block.build(Instr::FCmp(CmpPredicate::EQ, lhs, rhs)).unwrap()
|
||||||
}));
|
}));
|
||||||
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::NE), &ty, |scope, lhs, rhs| {
|
||||||
|
scope.block.build(Instr::FCmp(CmpPredicate::NE, lhs, rhs)).unwrap()
|
||||||
|
}));
|
||||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| {
|
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| {
|
||||||
scope.block.build(Instr::FCmp(CmpPredicate::GT, lhs, rhs)).unwrap()
|
scope.block.build(Instr::FCmp(CmpPredicate::GT, lhs, rhs)).unwrap()
|
||||||
}));
|
}));
|
||||||
@ -675,37 +271,12 @@ macro_rules! intrinsic_debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct IntrinsicSimpleUnaryInstr<T>(T)
|
pub struct IntrinsicSimpleInstr<T>(T)
|
||||||
where
|
|
||||||
T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue;
|
|
||||||
|
|
||||||
impl<T> std::fmt::Debug for IntrinsicSimpleUnaryInstr<T>
|
|
||||||
where
|
|
||||||
T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.debug_tuple("IntrinsicSimpleUnaryInstr").finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleUnaryInstr<T>
|
|
||||||
where
|
|
||||||
T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue,
|
|
||||||
{
|
|
||||||
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
||||||
let param = params.get(0).unwrap();
|
|
||||||
let instr = self.clone().0(scope, param.instr());
|
|
||||||
Ok(StackValue(StackValueKind::Literal(instr), param.1.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct IntrinsicSimpleBinaryInstr<T>(T)
|
|
||||||
where
|
where
|
||||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
||||||
intrinsic_debug!(IntrinsicSimpleBinaryInstr<T>, "IntrinsicSimpleBinaryInstr");
|
intrinsic_debug!(IntrinsicSimpleInstr<T>, "IntrinsicSimpleInstr");
|
||||||
|
|
||||||
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleBinaryInstr<T>
|
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleInstr<T>
|
||||||
where
|
where
|
||||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||||
{
|
{
|
||||||
@ -741,60 +312,21 @@ impl IntrinsicFunction for IntrinsicSizeOf {
|
|||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
||||||
let instr = scope
|
let instr = scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::Constant(reid_lib::ConstValueKind::U64(
|
.build(Instr::Constant(reid_lib::ConstValue::U64(self.0.size_of())))
|
||||||
self.0.size_of(&scope.type_map) / 8,
|
|
||||||
)))
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(StackValue(StackValueKind::Literal(instr), self.0.clone()))
|
Ok(StackValue(StackValueKind::Literal(instr), self.0.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct IntrinsicMemcpy(TypeKind);
|
pub struct IntrinsicAlloca(TypeKind);
|
||||||
impl IntrinsicFunction for IntrinsicMemcpy {
|
impl IntrinsicFunction for IntrinsicAlloca {
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
||||||
let dest = params.get(0).unwrap();
|
|
||||||
let src = params.get(1).unwrap();
|
|
||||||
let length = params.get(2).unwrap();
|
|
||||||
let intrinsic = scope.get_intrinsic(LLVMIntrinsicKind::Memcpy(TypeKind::UserPtr(Box::new(self.0.clone()))));
|
|
||||||
|
|
||||||
let sizeof = scope
|
|
||||||
.block
|
|
||||||
.build(Instr::Constant(ConstValueKind::U64(
|
|
||||||
self.0.size_of(&scope.type_map) / 8,
|
|
||||||
)))
|
|
||||||
.unwrap();
|
|
||||||
let bytes = scope.block.build(Instr::Mul(sizeof, length.instr())).unwrap();
|
|
||||||
|
|
||||||
let params = vec![
|
|
||||||
dest.instr(),
|
|
||||||
src.instr(),
|
|
||||||
bytes,
|
|
||||||
scope.block.build(Instr::Constant(ConstValueKind::Bool(false))).unwrap(),
|
|
||||||
];
|
|
||||||
let value = scope.block.build(Instr::FunctionCall(intrinsic, params)).unwrap();
|
|
||||||
Ok(StackValue(StackValueKind::Literal(value), TypeKind::Void))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct IntrinsicMalloc(TypeKind);
|
|
||||||
impl IntrinsicFunction for IntrinsicMalloc {
|
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
||||||
let amount = params.get(0).unwrap();
|
let amount = params.get(0).unwrap();
|
||||||
let function = scope
|
let instr = scope
|
||||||
.block
|
.block
|
||||||
.find_function(&format!("{}.{}", INTRINSIC_IDENT, MALLOC_IDENT))
|
.build(Instr::ArrayAlloca(self.0.get_type(scope.type_values), amount.instr()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let sizeof = scope
|
|
||||||
.block
|
|
||||||
.build(Instr::Constant(ConstValueKind::U64(
|
|
||||||
self.0.size_of(&scope.type_map) / 8,
|
|
||||||
)))
|
|
||||||
.unwrap();
|
|
||||||
let bytes = scope.block.build(Instr::Mul(sizeof, amount.instr())).unwrap();
|
|
||||||
let instr = scope.block.build(Instr::FunctionCall(function, vec![bytes])).unwrap();
|
|
||||||
Ok(StackValue(StackValueKind::Literal(instr), self.0.clone()))
|
Ok(StackValue(StackValueKind::Literal(instr), self.0.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -803,7 +335,7 @@ impl IntrinsicFunction for IntrinsicMalloc {
|
|||||||
pub struct IntrinsicNullPtr(TypeKind);
|
pub struct IntrinsicNullPtr(TypeKind);
|
||||||
impl IntrinsicFunction for IntrinsicNullPtr {
|
impl IntrinsicFunction for IntrinsicNullPtr {
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
||||||
let zero = scope.block.build(Instr::Constant(ConstValueKind::I8(0))).unwrap();
|
let zero = scope.block.build(Instr::Constant(ConstValue::I8(0))).unwrap();
|
||||||
let instr = scope
|
let instr = scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::IntToPtr(
|
.build(Instr::IntToPtr(
|
||||||
@ -818,42 +350,6 @@ impl IntrinsicFunction for IntrinsicNullPtr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct IntrinsicIsNull;
|
|
||||||
impl IntrinsicFunction for IntrinsicIsNull {
|
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
||||||
let val = params.get(0).unwrap().instr();
|
|
||||||
let instr = scope.block.build(Instr::IsNull(val)).unwrap();
|
|
||||||
Ok(StackValue(StackValueKind::Literal(instr), TypeKind::Bool))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct IntrinsicConst(u64);
|
|
||||||
impl IntrinsicFunction for IntrinsicConst {
|
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
||||||
let zero = scope.block.build(Instr::Constant(ConstValueKind::U64(self.0))).unwrap();
|
|
||||||
Ok(StackValue(StackValueKind::Literal(zero), TypeKind::U64))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct IntrinsicLLVM(LLVMIntrinsicKind, TypeKind);
|
|
||||||
impl IntrinsicFunction for IntrinsicLLVM {
|
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
|
|
||||||
let intrinsic = scope.get_intrinsic(self.0.clone());
|
|
||||||
let value = scope
|
|
||||||
.block
|
|
||||||
.build(Instr::FunctionCall(
|
|
||||||
intrinsic,
|
|
||||||
params.iter().map(|p| p.instr()).collect(),
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Ok(StackValue(StackValueKind::Literal(value), self.1.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl IntrinsicFunction for IntrinsicIAdd {
|
// impl IntrinsicFunction for IntrinsicIAdd {
|
||||||
// fn codegen<'ctx, 'a>(
|
// fn codegen<'ctx, 'a>(
|
||||||
// &self,
|
// &self,
|
||||||
|
|||||||
@ -1,20 +1,14 @@
|
|||||||
use std::{
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
cell::RefCell,
|
|
||||||
collections::{HashMap, HashSet},
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use allocator::{Allocator, AllocatorScope};
|
use allocator::{Allocator, AllocatorScope};
|
||||||
use intrinsics::*;
|
use intrinsics::*;
|
||||||
use reid_lib::{
|
use reid_lib::{
|
||||||
builder::ConstantValue,
|
|
||||||
compile::CompiledModule,
|
compile::CompiledModule,
|
||||||
debug_information::{
|
debug_information::{
|
||||||
DebugFileData, DebugLexicalScope, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind,
|
DebugFileData, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind, DebugSubprogramData,
|
||||||
DebugSubprogramData, DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DwarfFlags,
|
DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DwarfFlags, InstructionDebugRecordData,
|
||||||
InstructionDebugRecordData,
|
|
||||||
},
|
},
|
||||||
CmpPredicate, ConstValueKind, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, NamedStruct,
|
CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, NamedStruct,
|
||||||
TerminatorKind as Term, Type,
|
TerminatorKind as Term, Type,
|
||||||
};
|
};
|
||||||
use scope::*;
|
use scope::*;
|
||||||
@ -24,8 +18,8 @@ use crate::{
|
|||||||
self,
|
self,
|
||||||
implement::TypeCategory,
|
implement::TypeCategory,
|
||||||
pass::{AssociatedFunctionKey, BinopKey},
|
pass::{AssociatedFunctionKey, BinopKey},
|
||||||
CustomTypeKey, FunctionCall, FunctionDefinitionKind, FunctionParam, NamedVariableRef, SourceModuleId,
|
CustomTypeKey, FunctionCall, FunctionDefinitionKind, NamedVariableRef, SourceModuleId, StructField, StructType,
|
||||||
StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
|
TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
|
||||||
},
|
},
|
||||||
util::try_all,
|
util::try_all,
|
||||||
};
|
};
|
||||||
@ -62,12 +56,10 @@ impl mir::Context {
|
|||||||
let mut modules = HashMap::new();
|
let mut modules = HashMap::new();
|
||||||
let mut modules_sorted = self.modules.iter().map(|(_, m)| m).collect::<Vec<_>>();
|
let mut modules_sorted = self.modules.iter().map(|(_, m)| m).collect::<Vec<_>>();
|
||||||
modules_sorted.sort_by(|m1, m2| m2.module_id.cmp(&m1.module_id));
|
modules_sorted.sort_by(|m1, m2| m2.module_id.cmp(&m1.module_id));
|
||||||
for module in &modules_sorted {
|
|
||||||
modules.insert(module.module_id, *module);
|
|
||||||
}
|
|
||||||
|
|
||||||
for module in &modules_sorted {
|
for module in &modules_sorted {
|
||||||
module.codegen(context, modules.clone())?;
|
let codegen = module.codegen(context, modules.clone())?;
|
||||||
|
modules.insert(module.module_id, codegen);
|
||||||
}
|
}
|
||||||
Ok(CodegenContext { context })
|
Ok(CodegenContext { context })
|
||||||
}
|
}
|
||||||
@ -102,45 +94,11 @@ impl Default for State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mir::GlobalKind {
|
|
||||||
fn codegen<'ctx>(
|
|
||||||
&'ctx self,
|
|
||||||
context: &'ctx Context,
|
|
||||||
types: &HashMap<CustomTypeKey, reid_lib::builder::TypeValue>,
|
|
||||||
module: &Module,
|
|
||||||
) -> Result<(ConstantValue, TypeKind), ErrorKind> {
|
|
||||||
Ok(match self {
|
|
||||||
mir::GlobalKind::Literal(literal) => (module.add_constant(literal.as_const_kind()), literal.as_type()),
|
|
||||||
mir::GlobalKind::Array(globals) => {
|
|
||||||
let values = try_all(globals.into_iter().map(|g| g.codegen(context, types, module)).collect())
|
|
||||||
.map_err(|e| e.first().unwrap().clone())?;
|
|
||||||
let elem_ty = values.iter().map(|(_, t)| t.clone()).next().unwrap_or(TypeKind::Void);
|
|
||||||
let values = values.iter().map(|(v, _)| *v).collect::<Vec<_>>();
|
|
||||||
(
|
|
||||||
module.add_constant(ConstValueKind::Array(values, elem_ty.get_type(&types))),
|
|
||||||
TypeKind::Array(Box::new(elem_ty), globals.len() as u64),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_typekey(ty: &TypeKind) -> Option<CustomTypeKey> {
|
|
||||||
match ty {
|
|
||||||
TypeKind::Array(type_kind, _) => get_typekey(type_kind.as_ref()),
|
|
||||||
TypeKind::CustomType(custom_type_key) => Some(custom_type_key.clone()),
|
|
||||||
TypeKind::Borrow(type_kind, _) => get_typekey(type_kind.as_ref()),
|
|
||||||
TypeKind::UserPtr(type_kind) => get_typekey(type_kind.as_ref()),
|
|
||||||
TypeKind::CodegenPtr(type_kind) => get_typekey(type_kind.as_ref()),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mir::Module {
|
impl mir::Module {
|
||||||
fn codegen<'ctx>(
|
fn codegen<'ctx>(
|
||||||
&'ctx self,
|
&'ctx self,
|
||||||
context: &'ctx Context,
|
context: &'ctx Context,
|
||||||
modules: HashMap<SourceModuleId, &mir::Module>,
|
modules: HashMap<SourceModuleId, ModuleCodegen<'ctx>>,
|
||||||
) -> Result<ModuleCodegen<'ctx>, ErrorKind> {
|
) -> Result<ModuleCodegen<'ctx>, ErrorKind> {
|
||||||
let mut module = context.module(&self.name, self.is_main);
|
let mut module = context.module(&self.name, self.is_main);
|
||||||
let tokens = &self.tokens;
|
let tokens = &self.tokens;
|
||||||
@ -160,7 +118,6 @@ impl mir::Module {
|
|||||||
let mut types = HashMap::new();
|
let mut types = HashMap::new();
|
||||||
let mut type_values = HashMap::new();
|
let mut type_values = HashMap::new();
|
||||||
let mut debug_types = HashMap::new();
|
let mut debug_types = HashMap::new();
|
||||||
let mut type_map = HashMap::new();
|
|
||||||
|
|
||||||
macro_rules! insert_debug {
|
macro_rules! insert_debug {
|
||||||
($kind:expr) => {
|
($kind:expr) => {
|
||||||
@ -170,7 +127,8 @@ impl mir::Module {
|
|||||||
&compile_unit,
|
&compile_unit,
|
||||||
&debug,
|
&debug,
|
||||||
&debug_types,
|
&debug_types,
|
||||||
&type_map,
|
&type_values,
|
||||||
|
&types,
|
||||||
self.module_id,
|
self.module_id,
|
||||||
&self.tokens,
|
&self.tokens,
|
||||||
&modules,
|
&modules,
|
||||||
@ -193,49 +151,20 @@ impl mir::Module {
|
|||||||
insert_debug!(&TypeKind::Void);
|
insert_debug!(&TypeKind::Void);
|
||||||
insert_debug!(&TypeKind::Char);
|
insert_debug!(&TypeKind::Char);
|
||||||
|
|
||||||
// Since we know by this point that no types are recursive, we can
|
let mut typedefs = self.typedefs.clone();
|
||||||
// somewhat easily sort the type-definitions such that we can process
|
typedefs.sort_by(|a, b| b.source_module.cmp(&a.source_module));
|
||||||
// the ones with no depencencies first, and later the ones that depend
|
|
||||||
// on the earlier ones.
|
|
||||||
let mut typekeys_seen: HashSet<CustomTypeKey> = HashSet::new();
|
|
||||||
let mut typedefs_sorted: Vec<TypeDefinition> = Vec::new();
|
|
||||||
let mut typedefs_left = self.typedefs.clone();
|
|
||||||
while let Some(typedef) = typedefs_left.pop() {
|
|
||||||
let is_ok = match &typedef.kind {
|
|
||||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
|
||||||
let mut field_iter = fields.iter();
|
|
||||||
loop {
|
|
||||||
if let Some(field) = field_iter.next() {
|
|
||||||
if let Some(key) = get_typekey(&field.1) {
|
|
||||||
if !typekeys_seen.contains(&key) {
|
|
||||||
break false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if is_ok {
|
for typedef in typedefs {
|
||||||
typekeys_seen.insert(CustomTypeKey(typedef.name.clone(), typedef.source_module));
|
|
||||||
typedefs_sorted.push(typedef);
|
|
||||||
} else {
|
|
||||||
typedefs_left.insert(0, typedef.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for typedef in typedefs_sorted {
|
|
||||||
let type_key = CustomTypeKey(typedef.name.clone(), typedef.source_module);
|
let type_key = CustomTypeKey(typedef.name.clone(), typedef.source_module);
|
||||||
type_map.insert(type_key.clone(), typedef.clone());
|
|
||||||
|
|
||||||
let type_value = match &typedef.kind {
|
let type_value = match &typedef.kind {
|
||||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
TypeDefinitionKind::Struct(StructType(fields)) => {
|
||||||
module.custom_type(CustomTypeKind::NamedStruct(NamedStruct(
|
module.custom_type(CustomTypeKind::NamedStruct(NamedStruct(
|
||||||
typedef.name.clone(),
|
typedef.name.clone(),
|
||||||
fields
|
fields
|
||||||
.iter()
|
.iter()
|
||||||
|
// TODO: Reorder custom-type definitions such that
|
||||||
|
// inner types get evaluated first. Otherwise this
|
||||||
|
// will cause a panic!
|
||||||
.map(|StructField(_, t, _)| t.get_type(&type_values))
|
.map(|StructField(_, t, _)| t.get_type(&type_values))
|
||||||
.collect(),
|
.collect(),
|
||||||
)))
|
)))
|
||||||
@ -243,47 +172,22 @@ impl mir::Module {
|
|||||||
};
|
};
|
||||||
types.insert(type_value, typedef.clone());
|
types.insert(type_value, typedef.clone());
|
||||||
type_values.insert(type_key.clone(), type_value);
|
type_values.insert(type_key.clone(), type_value);
|
||||||
|
|
||||||
insert_debug!(&TypeKind::CustomType(type_key.clone()));
|
insert_debug!(&TypeKind::CustomType(type_key.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut globals = HashMap::new();
|
|
||||||
for global in &self.globals {
|
|
||||||
let (const_value, _) = global.kind.codegen(context, &type_values, &module)?;
|
|
||||||
globals.insert(global.name.clone(), module.add_global(&global.name, const_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut functions = HashMap::new();
|
let mut functions = HashMap::new();
|
||||||
|
|
||||||
for function in &self.functions {
|
for function in &self.functions {
|
||||||
let param_types: Vec<Type> = function
|
let param_types: Vec<Type> = function
|
||||||
.parameters
|
.parameters
|
||||||
.iter()
|
.iter()
|
||||||
.map(|FunctionParam { ty, .. }| ty.get_type(&type_values))
|
.map(|(_, p)| p.get_type(&type_values))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let is_main = self.is_main && function.name == "main";
|
let is_main = self.is_main && function.name == "main";
|
||||||
|
|
||||||
let module_prefix = if let Some(module) = function.source {
|
|
||||||
if module == self.module_id {
|
|
||||||
format!("reid.{}.", self.name)
|
|
||||||
} else {
|
|
||||||
format!("reid.{}.", modules.get(&module).unwrap().name)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
format!("reid.intrinsic.")
|
|
||||||
};
|
|
||||||
let linkage_name = function.linkage_name.clone().unwrap_or(function.name.clone());
|
|
||||||
let full_name = format!(
|
|
||||||
"{}{}",
|
|
||||||
module_prefix,
|
|
||||||
function.linkage_name.clone().unwrap_or(function.name.clone())
|
|
||||||
);
|
|
||||||
|
|
||||||
let func = match &function.kind {
|
let func = match &function.kind {
|
||||||
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
|
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
|
||||||
&full_name,
|
&function.linkage_name.clone().unwrap_or(function.name.clone()),
|
||||||
None,
|
|
||||||
function.return_type.get_type(&type_values),
|
function.return_type.get_type(&type_values),
|
||||||
param_types,
|
param_types,
|
||||||
FunctionFlags {
|
FunctionFlags {
|
||||||
@ -294,16 +198,7 @@ impl mir::Module {
|
|||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
|
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
|
||||||
&full_name,
|
&function.linkage_name.clone().unwrap_or(function.name.clone()),
|
||||||
if function.source == None {
|
|
||||||
Some(function.linkage_name.clone().unwrap())
|
|
||||||
} else {
|
|
||||||
if !*imported {
|
|
||||||
Some(linkage_name.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function.return_type.get_type(&type_values),
|
function.return_type.get_type(&type_values),
|
||||||
param_types,
|
param_types,
|
||||||
FunctionFlags {
|
FunctionFlags {
|
||||||
@ -326,24 +221,13 @@ impl mir::Module {
|
|||||||
let param_types: Vec<Type> = function
|
let param_types: Vec<Type> = function
|
||||||
.parameters
|
.parameters
|
||||||
.iter()
|
.iter()
|
||||||
.map(|FunctionParam { ty, .. }| ty.get_type(&type_values))
|
.map(|(_, p)| p.get_type(&type_values))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let is_main = self.is_main && function.name == "main";
|
let is_main = self.is_main && function.name == "main";
|
||||||
let module_prefix = if let Some(module_id) = function.source {
|
|
||||||
if module_id == self.module_id {
|
|
||||||
format!("reid.{}.", self.name)
|
|
||||||
} else {
|
|
||||||
format!("reid.{}.", modules.get(&module_id).unwrap().name)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
format!("reid.intrinsic.")
|
|
||||||
};
|
|
||||||
let full_name = format!("{}{}::{}", module_prefix, ty, function.name);
|
|
||||||
let func = match &function.kind {
|
let func = match &function.kind {
|
||||||
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
|
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
|
||||||
&full_name,
|
&format!("{}::{}", ty, function.name),
|
||||||
None,
|
|
||||||
function.return_type.get_type(&type_values),
|
function.return_type.get_type(&type_values),
|
||||||
param_types,
|
param_types,
|
||||||
FunctionFlags {
|
FunctionFlags {
|
||||||
@ -354,8 +238,7 @@ impl mir::Module {
|
|||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
|
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
|
||||||
&full_name,
|
&function.linkage_name.clone().unwrap_or(function.name.clone()),
|
||||||
None,
|
|
||||||
function.return_type.get_type(&type_values),
|
function.return_type.get_type(&type_values),
|
||||||
param_types,
|
param_types,
|
||||||
FunctionFlags {
|
FunctionFlags {
|
||||||
@ -379,11 +262,11 @@ impl mir::Module {
|
|||||||
for binop in &self.binop_defs {
|
for binop in &self.binop_defs {
|
||||||
let binop_fn_name = format!(
|
let binop_fn_name = format!(
|
||||||
"binop.{}.{:?}.{}.{}",
|
"binop.{}.{:?}.{}.{}",
|
||||||
binop.lhs.ty, binop.op, binop.rhs.ty, binop.return_type
|
binop.lhs.1, binop.op, binop.rhs.1, binop.return_type
|
||||||
);
|
);
|
||||||
binops.insert(
|
binops.insert(
|
||||||
BinopKey {
|
BinopKey {
|
||||||
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||||
operator: binop.op,
|
operator: binop.op,
|
||||||
},
|
},
|
||||||
StackBinopDefinition {
|
StackBinopDefinition {
|
||||||
@ -393,9 +276,8 @@ impl mir::Module {
|
|||||||
FunctionDefinitionKind::Local(..) => {
|
FunctionDefinitionKind::Local(..) => {
|
||||||
let ir_function = module.function(
|
let ir_function = module.function(
|
||||||
&binop_fn_name,
|
&binop_fn_name,
|
||||||
None,
|
|
||||||
binop.return_type.get_type(&type_values),
|
binop.return_type.get_type(&type_values),
|
||||||
vec![binop.lhs.ty.get_type(&type_values), binop.rhs.ty.get_type(&type_values)],
|
vec![binop.lhs.1.get_type(&type_values), binop.rhs.1.get_type(&type_values)],
|
||||||
FunctionFlags {
|
FunctionFlags {
|
||||||
is_pub: binop.exported,
|
is_pub: binop.exported,
|
||||||
is_imported: binop.exported,
|
is_imported: binop.exported,
|
||||||
@ -410,7 +292,6 @@ impl mir::Module {
|
|||||||
&mut AllocatorScope {
|
&mut AllocatorScope {
|
||||||
block: &mut entry,
|
block: &mut entry,
|
||||||
type_values: &type_values,
|
type_values: &type_values,
|
||||||
mod_id: self.module_id,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -426,8 +307,6 @@ impl mir::Module {
|
|||||||
functions: &functions,
|
functions: &functions,
|
||||||
types: &types,
|
types: &types,
|
||||||
type_values: &type_values,
|
type_values: &type_values,
|
||||||
type_map: &type_map,
|
|
||||||
globals: &globals,
|
|
||||||
stack_values: HashMap::new(),
|
stack_values: HashMap::new(),
|
||||||
debug: Some(Debug {
|
debug: Some(Debug {
|
||||||
info: &debug,
|
info: &debug,
|
||||||
@ -436,7 +315,6 @@ impl mir::Module {
|
|||||||
}),
|
}),
|
||||||
binops: &binops,
|
binops: &binops,
|
||||||
allocator: Rc::new(RefCell::new(allocator)),
|
allocator: Rc::new(RefCell::new(allocator)),
|
||||||
llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
binop
|
binop
|
||||||
@ -462,9 +340,8 @@ impl mir::Module {
|
|||||||
}
|
}
|
||||||
FunctionDefinitionKind::Extern(imported) => ScopeFunctionKind::UserGenerated(module.function(
|
FunctionDefinitionKind::Extern(imported) => ScopeFunctionKind::UserGenerated(module.function(
|
||||||
&binop_fn_name,
|
&binop_fn_name,
|
||||||
None,
|
|
||||||
binop.return_type.get_type(&type_values),
|
binop.return_type.get_type(&type_values),
|
||||||
vec![binop.lhs.ty.get_type(&type_values), binop.rhs.ty.get_type(&type_values)],
|
vec![binop.lhs.1.get_type(&type_values), binop.rhs.1.get_type(&type_values)],
|
||||||
FunctionFlags {
|
FunctionFlags {
|
||||||
is_extern: true,
|
is_extern: true,
|
||||||
is_imported: *imported,
|
is_imported: *imported,
|
||||||
@ -489,7 +366,6 @@ impl mir::Module {
|
|||||||
&mut AllocatorScope {
|
&mut AllocatorScope {
|
||||||
block: &mut entry,
|
block: &mut entry,
|
||||||
type_values: &type_values,
|
type_values: &type_values,
|
||||||
mod_id: self.module_id,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -505,17 +381,14 @@ impl mir::Module {
|
|||||||
functions: &functions,
|
functions: &functions,
|
||||||
types: &types,
|
types: &types,
|
||||||
type_values: &type_values,
|
type_values: &type_values,
|
||||||
type_map: &type_map,
|
|
||||||
stack_values: HashMap::new(),
|
stack_values: HashMap::new(),
|
||||||
debug: Some(Debug {
|
debug: Some(Debug {
|
||||||
info: &debug,
|
info: &debug,
|
||||||
scope: compile_unit.clone(),
|
scope: compile_unit.clone(),
|
||||||
types: &debug_types,
|
types: &debug_types,
|
||||||
}),
|
}),
|
||||||
globals: &globals,
|
|
||||||
binops: &binops,
|
binops: &binops,
|
||||||
allocator: Rc::new(RefCell::new(allocator)),
|
allocator: Rc::new(RefCell::new(allocator)),
|
||||||
llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mir_function
|
mir_function
|
||||||
@ -552,7 +425,6 @@ impl mir::Module {
|
|||||||
&mut AllocatorScope {
|
&mut AllocatorScope {
|
||||||
block: &mut entry,
|
block: &mut entry,
|
||||||
type_values: &type_values,
|
type_values: &type_values,
|
||||||
mod_id: self.module_id,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -568,17 +440,14 @@ impl mir::Module {
|
|||||||
functions: &functions,
|
functions: &functions,
|
||||||
types: &types,
|
types: &types,
|
||||||
type_values: &type_values,
|
type_values: &type_values,
|
||||||
type_map: &type_map,
|
|
||||||
stack_values: HashMap::new(),
|
stack_values: HashMap::new(),
|
||||||
debug: Some(Debug {
|
debug: Some(Debug {
|
||||||
info: &debug,
|
info: &debug,
|
||||||
scope: compile_unit.clone(),
|
scope: compile_unit.clone(),
|
||||||
types: &debug_types,
|
types: &debug_types,
|
||||||
}),
|
}),
|
||||||
globals: &globals,
|
|
||||||
binops: &binops,
|
binops: &binops,
|
||||||
allocator: Rc::new(RefCell::new(allocator)),
|
allocator: Rc::new(RefCell::new(allocator)),
|
||||||
llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mir_function
|
mir_function
|
||||||
@ -612,7 +481,7 @@ impl FunctionDefinitionKind {
|
|||||||
name: String,
|
name: String,
|
||||||
is_pub: bool,
|
is_pub: bool,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
parameters: &Vec<FunctionParam>,
|
parameters: &Vec<(String, TypeKind)>,
|
||||||
return_type: &TypeKind,
|
return_type: &TypeKind,
|
||||||
ir_function: &Function,
|
ir_function: &Function,
|
||||||
debug_location: Option<DebugLocation>,
|
debug_location: Option<DebugLocation>,
|
||||||
@ -656,31 +525,57 @@ impl FunctionDefinitionKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compile actual IR part
|
// Compile actual IR part
|
||||||
for (i, p) in parameters.iter().enumerate() {
|
for (i, (p_name, p_ty)) in parameters.iter().enumerate() {
|
||||||
// Codegen actual parameters
|
// Codegen actual parameters
|
||||||
let arg_name = format!("arg.{}", p.name);
|
let arg_name = format!("arg.{}", p_name);
|
||||||
let param = scope
|
let param = scope
|
||||||
.block
|
.block
|
||||||
.build_named(format!("{}.get", arg_name), Instr::Param(i))
|
.build_named(format!("{}.get", arg_name), Instr::Param(i))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let alloca = scope.allocate(&p.meta, &p.ty).unwrap();
|
let alloca = scope.allocate(&p_name, &p_ty).unwrap();
|
||||||
|
|
||||||
scope
|
scope
|
||||||
.block
|
.block
|
||||||
.build_named(format!("{}.store", arg_name), Instr::Store(alloca, param))
|
.build_named(format!("{}.store", arg_name), Instr::Store(alloca, param))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
scope.stack_values.insert(
|
scope.stack_values.insert(
|
||||||
p.name.clone(),
|
p_name.clone(),
|
||||||
StackValue(
|
StackValue(
|
||||||
StackValueKind::mutable(p.ty.is_mutable(), alloca),
|
StackValueKind::mutable(p_ty.is_mutable(), alloca),
|
||||||
TypeKind::CodegenPtr(Box::new(p.ty.clone())),
|
TypeKind::CodegenPtr(Box::new(p_ty.clone())),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Generate debug info
|
||||||
|
// if let (Some(debug_scope), Some(location)) = (
|
||||||
|
// &debug_scope,
|
||||||
|
// mir_function.signature().into_debug(tokens, compile_unit),
|
||||||
|
// ) {
|
||||||
|
// debug.metadata(
|
||||||
|
// &location,
|
||||||
|
// DebugMetadata::ParamVar(DebugParamVariable {
|
||||||
|
// name: p_name.clone(),
|
||||||
|
// arg_idx: i as u32,
|
||||||
|
// ty: p_ty.get_debug_type_hard(
|
||||||
|
// *debug_scope,
|
||||||
|
// &debug,
|
||||||
|
// &debug_types,
|
||||||
|
// &type_values,
|
||||||
|
// &types,
|
||||||
|
// self.module_id,
|
||||||
|
// &self.tokens,
|
||||||
|
// &modules,
|
||||||
|
// ),
|
||||||
|
// always_preserve: true,
|
||||||
|
// flags: DwarfFlags,
|
||||||
|
// }),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = State::default();
|
let state = State::default();
|
||||||
if let Some(ret) = block.codegen(scope, &state, false)? {
|
if let Some(ret) = block.codegen(scope, &state)? {
|
||||||
scope.block.terminate(Term::Ret(ret.instr())).unwrap();
|
scope.block.terminate(Term::Ret(ret.instr())).unwrap();
|
||||||
} else {
|
} else {
|
||||||
if !scope.block.delete_if_unused().unwrap() {
|
if !scope.block.delete_if_unused().unwrap() {
|
||||||
@ -709,20 +604,7 @@ impl mir::Block {
|
|||||||
&self,
|
&self,
|
||||||
mut scope: &mut Scope<'ctx, 'a>,
|
mut scope: &mut Scope<'ctx, 'a>,
|
||||||
state: &State,
|
state: &State,
|
||||||
create_debug_scope: bool,
|
|
||||||
) -> Result<Option<StackValue>, ErrorKind> {
|
) -> Result<Option<StackValue>, ErrorKind> {
|
||||||
let parent_scope = if let Some(debug) = &mut scope.debug {
|
|
||||||
let parent_scope = debug.scope.clone();
|
|
||||||
if create_debug_scope {
|
|
||||||
let location = self.meta.into_debug(scope.tokens, &debug.scope).unwrap();
|
|
||||||
let scope = debug.info.lexical_scope(&debug.scope, DebugLexicalScope { location });
|
|
||||||
debug.scope = scope;
|
|
||||||
}
|
|
||||||
Some(parent_scope)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
for stmt in &self.statements {
|
for stmt in &self.statements {
|
||||||
stmt.codegen(&mut scope, state)?.map(|s| {
|
stmt.codegen(&mut scope, state)?.map(|s| {
|
||||||
if let Some(debug) = &scope.debug {
|
if let Some(debug) = &scope.debug {
|
||||||
@ -733,7 +615,7 @@ impl mir::Block {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_value = if let Some((kind, expr)) = &self.return_expression {
|
if let Some((kind, expr)) = &self.return_expression {
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
let ret = expr.codegen(&mut scope, &mut state.load(true))?;
|
let ret = expr.codegen(&mut scope, &mut state.load(true))?;
|
||||||
match kind {
|
match kind {
|
||||||
@ -756,13 +638,7 @@ impl mir::Block {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(parent_scope) = parent_scope {
|
|
||||||
scope.debug.as_mut().unwrap().scope = parent_scope;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return_value
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -774,11 +650,11 @@ impl mir::Statement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
mir::StmtKind::Let(NamedVariableRef(ty, name, meta), mutable, expression) => {
|
mir::StmtKind::Let(NamedVariableRef(ty, name, _), mutable, expression) => {
|
||||||
let value = expression.codegen(scope, &state)?.unwrap();
|
let value = expression.codegen(scope, &state)?.unwrap();
|
||||||
|
|
||||||
let alloca = scope
|
let alloca = scope
|
||||||
.allocate(meta, &value.1)
|
.allocate(name, &value.1)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.maybe_location(&mut scope.block, location.clone());
|
.maybe_location(&mut scope.block, location.clone());
|
||||||
|
|
||||||
@ -866,7 +742,7 @@ impl mir::Statement {
|
|||||||
let condition_res = condition.codegen(&mut condition_scope, state)?.unwrap();
|
let condition_res = condition.codegen(&mut condition_scope, state)?.unwrap();
|
||||||
let true_instr = condition_scope
|
let true_instr = condition_scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::Constant(ConstValueKind::Bool(true)))
|
.build(Instr::Constant(ConstValue::Bool(true)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let check = condition_scope
|
let check = condition_scope
|
||||||
.block
|
.block
|
||||||
@ -883,7 +759,7 @@ impl mir::Statement {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut condition_true_scope = scope.with_block(condition_true_block);
|
let mut condition_true_scope = scope.with_block(condition_true_block);
|
||||||
block.codegen(&mut condition_true_scope, state, true)?;
|
block.codegen(&mut condition_true_scope, state)?;
|
||||||
|
|
||||||
condition_true_scope
|
condition_true_scope
|
||||||
.block
|
.block
|
||||||
@ -1057,7 +933,7 @@ impl mir::Expression {
|
|||||||
scope.block.terminate(Term::Br(inner.value())).unwrap();
|
scope.block.terminate(Term::Br(inner.value())).unwrap();
|
||||||
|
|
||||||
let mut inner_scope = scope.with_block(inner);
|
let mut inner_scope = scope.with_block(inner);
|
||||||
let ret = if let Some(ret) = block.codegen(&mut inner_scope, state, true)? {
|
let ret = if let Some(ret) = block.codegen(&mut inner_scope, state)? {
|
||||||
Some(ret)
|
Some(ret)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -1113,7 +989,7 @@ impl mir::Expression {
|
|||||||
|
|
||||||
let first = scope
|
let first = scope
|
||||||
.block
|
.block
|
||||||
.build_named("array.zero", Instr::Constant(ConstValueKind::U32(0)))
|
.build_named("array.zero", Instr::Constant(ConstValue::U32(0)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
(
|
(
|
||||||
scope
|
scope
|
||||||
@ -1167,10 +1043,8 @@ impl mir::Expression {
|
|||||||
let load_n = format!("{}.load", array_name);
|
let load_n = format!("{}.load", array_name);
|
||||||
|
|
||||||
let array = scope
|
let array = scope
|
||||||
.allocate(
|
.block
|
||||||
&self.1,
|
.build_named(&array_name, Instr::Alloca(array_ty.clone()))
|
||||||
&TypeKind::Array(Box::new(elem_ty_kind.clone()), expressions.len() as u64),
|
|
||||||
)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.maybe_location(&mut scope.block, location.clone());
|
.maybe_location(&mut scope.block, location.clone());
|
||||||
|
|
||||||
@ -1180,11 +1054,11 @@ impl mir::Expression {
|
|||||||
|
|
||||||
let index_expr = scope
|
let index_expr = scope
|
||||||
.block
|
.block
|
||||||
.build_named(index.to_string(), Instr::Constant(ConstValueKind::U32(index as u32)))
|
.build_named(index.to_string(), Instr::Constant(ConstValue::U32(index as u32)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let first = scope
|
let first = scope
|
||||||
.block
|
.block
|
||||||
.build_named("zero", Instr::Constant(ConstValueKind::U32(0)))
|
.build_named("zero", Instr::Constant(ConstValue::U32(0)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let ptr = scope
|
let ptr = scope
|
||||||
.block
|
.block
|
||||||
@ -1209,7 +1083,7 @@ impl mir::Expression {
|
|||||||
TypeKind::Array(Box::new(elem_ty_kind), instr_list.len() as u64),
|
TypeKind::Array(Box::new(elem_ty_kind), instr_list.len() as u64),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
mir::ExprKind::Accessed(expression, type_kind, field, _) => {
|
mir::ExprKind::Accessed(expression, type_kind, field) => {
|
||||||
let struct_val = expression.codegen(scope, &state.load(false))?.unwrap();
|
let struct_val = expression.codegen(scope, &state.load(false))?.unwrap();
|
||||||
|
|
||||||
let TypeKind::CodegenPtr(inner) = &struct_val.1 else {
|
let TypeKind::CodegenPtr(inner) = &struct_val.1 else {
|
||||||
@ -1248,9 +1122,10 @@ impl mir::Expression {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::ExprKind::Struct(key, items) => {
|
mir::ExprKind::Struct(name, items) => {
|
||||||
|
let type_key = CustomTypeKey(name.clone(), scope.module_id);
|
||||||
let ty = Type::CustomType({
|
let ty = Type::CustomType({
|
||||||
let Some(a) = scope.type_values.get(&key) else {
|
let Some(a) = scope.type_values.get(&type_key) else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
*a
|
*a
|
||||||
@ -1259,20 +1134,21 @@ impl mir::Expression {
|
|||||||
let TypeDefinition {
|
let TypeDefinition {
|
||||||
kind: TypeDefinitionKind::Struct(struct_ty),
|
kind: TypeDefinitionKind::Struct(struct_ty),
|
||||||
..
|
..
|
||||||
} = scope.types.get(scope.type_values.get(&key).unwrap()).unwrap();
|
} = scope.types.get(scope.type_values.get(&type_key).unwrap()).unwrap();
|
||||||
|
|
||||||
let indices = struct_ty.0.iter().enumerate();
|
let indices = struct_ty.0.iter().enumerate();
|
||||||
|
|
||||||
let load_n = format!("{}@{}.load", key.0, key.1);
|
let load_n = format!("{}.load", name);
|
||||||
|
|
||||||
let struct_ptr = scope
|
let struct_ptr = scope
|
||||||
.allocate(&self.1, &TypeKind::CustomType(key.clone()))
|
.block
|
||||||
|
.build_named(name, Instr::Alloca(ty.clone()))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.maybe_location(&mut scope.block, location.clone());
|
.maybe_location(&mut scope.block, location.clone());
|
||||||
|
|
||||||
for (field_n, exp, _) in items {
|
for (field_n, exp) in items {
|
||||||
let gep_n = format!("{}@{}.{}.gep", key.0, key.1, field_n);
|
let gep_n = format!("{}.{}.gep", name, field_n);
|
||||||
let store_n = format!("{}@{}.{}.store", key.0, key.1, field_n);
|
let store_n = format!("{}.{}.store", name, field_n);
|
||||||
let i = indices.clone().find(|(_, f)| f.0 == *field_n).unwrap().0;
|
let i = indices.clone().find(|(_, f)| f.0 == *field_n).unwrap().0;
|
||||||
|
|
||||||
let elem_ptr = scope
|
let elem_ptr = scope
|
||||||
@ -1293,7 +1169,7 @@ impl mir::Expression {
|
|||||||
|
|
||||||
Some(StackValue(
|
Some(StackValue(
|
||||||
StackValueKind::Literal(struct_val),
|
StackValueKind::Literal(struct_val),
|
||||||
TypeKind::CustomType(key.clone()),
|
TypeKind::CustomType(type_key),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
mir::ExprKind::Borrow(expr, mutable) => {
|
mir::ExprKind::Borrow(expr, mutable) => {
|
||||||
@ -1359,45 +1235,24 @@ impl mir::Expression {
|
|||||||
if val.1 == *type_kind {
|
if val.1 == *type_kind {
|
||||||
Some(val)
|
Some(val)
|
||||||
} else {
|
} else {
|
||||||
let (ty, other) = if !state.should_load {
|
match (&val.1, type_kind) {
|
||||||
let TypeKind::CodegenPtr(inner) = &val.1 else {
|
(TypeKind::CodegenPtr(inner), TypeKind::UserPtr(_)) => match *inner.clone() {
|
||||||
panic!();
|
TypeKind::UserPtr(_) => Some(StackValue(
|
||||||
};
|
|
||||||
(*inner.clone(), TypeKind::CodegenPtr(Box::new(type_kind.clone())))
|
|
||||||
} else {
|
|
||||||
(val.1.clone(), type_kind.clone())
|
|
||||||
};
|
|
||||||
|
|
||||||
match (&ty, type_kind) {
|
|
||||||
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Some(StackValue(
|
|
||||||
val.0.derive(
|
val.0.derive(
|
||||||
scope
|
scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::BitCast(val.instr(), other.get_type(scope.type_values)))
|
.build(Instr::BitCast(
|
||||||
.unwrap(),
|
val.instr(),
|
||||||
),
|
Type::Ptr(Box::new(type_kind.get_type(scope.type_values))),
|
||||||
other.clone(),
|
|
||||||
)),
|
|
||||||
(TypeKind::Borrow(ty1, _), TypeKind::UserPtr(ty2)) => {
|
|
||||||
if let TypeKind::Array(ty1, _) = ty1.as_ref() {
|
|
||||||
if ty1 == ty2 {
|
|
||||||
Some(StackValue(
|
|
||||||
val.0.derive(
|
|
||||||
scope
|
|
||||||
.block
|
|
||||||
.build(Instr::BitCast(val.instr(), other.get_type(scope.type_values)))
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
other,
|
|
||||||
))
|
))
|
||||||
} else {
|
.unwrap(),
|
||||||
return Err(ErrorKind::Null).unwrap();
|
),
|
||||||
}
|
TypeKind::CodegenPtr(Box::new(type_kind.clone())),
|
||||||
} else {
|
)),
|
||||||
return Err(ErrorKind::Null).unwrap();
|
_ => panic!(),
|
||||||
}
|
},
|
||||||
}
|
(TypeKind::UserPtr(_), TypeKind::UserPtr(_))
|
||||||
(TypeKind::Char, TypeKind::U8)
|
| (TypeKind::Char, TypeKind::U8)
|
||||||
| (TypeKind::U8, TypeKind::Char)
|
| (TypeKind::U8, TypeKind::Char)
|
||||||
| (TypeKind::U8, TypeKind::I8) => Some(StackValue(
|
| (TypeKind::U8, TypeKind::I8) => Some(StackValue(
|
||||||
val.0.derive(
|
val.0.derive(
|
||||||
@ -1409,7 +1264,8 @@ impl mir::Expression {
|
|||||||
type_kind.clone(),
|
type_kind.clone(),
|
||||||
)),
|
)),
|
||||||
_ => {
|
_ => {
|
||||||
let cast_instr = ty
|
let cast_instr = val
|
||||||
|
.1
|
||||||
.get_type(scope.type_values)
|
.get_type(scope.type_values)
|
||||||
.cast_instruction(val.instr(), &type_kind.get_type(scope.type_values))
|
.cast_instruction(val.instr(), &type_kind.get_type(scope.type_values))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1423,33 +1279,6 @@ impl mir::Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::ExprKind::AssociatedFunctionCall(ty, call) => codegen_function_call(Some(ty), call, scope, state)?,
|
mir::ExprKind::AssociatedFunctionCall(ty, call) => codegen_function_call(Some(ty), call, scope, state)?,
|
||||||
mir::ExprKind::GlobalRef(global_name, ty) => {
|
|
||||||
let global_value = scope.globals.get(global_name).unwrap();
|
|
||||||
|
|
||||||
let value = scope.block.build(Instr::GetGlobal(global_value.clone())).unwrap();
|
|
||||||
|
|
||||||
if !state.should_load {
|
|
||||||
let allocated = scope
|
|
||||||
.block
|
|
||||||
.build(Instr::Alloca(ty.get_type(scope.type_values)))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
scope
|
|
||||||
.block
|
|
||||||
.build(Instr::Store(allocated, value))
|
|
||||||
.unwrap()
|
|
||||||
.maybe_location(&mut scope.block, location.clone());
|
|
||||||
|
|
||||||
let a = Some(StackValue(
|
|
||||||
StackValueKind::Literal(allocated),
|
|
||||||
TypeKind::CodegenPtr(Box::new(ty.clone())),
|
|
||||||
));
|
|
||||||
a
|
|
||||||
} else {
|
|
||||||
let a = Some(StackValue(StackValueKind::Literal(value), ty.clone()));
|
|
||||||
a
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
if let Some(value) = &value {
|
if let Some(value) = &value {
|
||||||
value.instr().maybe_location(&mut scope.block, location.clone());
|
value.instr().maybe_location(&mut scope.block, location.clone());
|
||||||
@ -1523,9 +1352,8 @@ fn codegen_function_call<'ctx, 'a>(
|
|||||||
|
|
||||||
let ptr = if ret_type_kind != TypeKind::Void {
|
let ptr = if ret_type_kind != TypeKind::Void {
|
||||||
let ptr = scope
|
let ptr = scope
|
||||||
.allocator
|
.block
|
||||||
.borrow_mut()
|
.build_named(&call.name, Instr::Alloca(ret_type.clone()))
|
||||||
.allocate(&call.meta, &call.return_type)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
scope
|
scope
|
||||||
.block
|
.block
|
||||||
|
|||||||
@ -1,27 +1,24 @@
|
|||||||
use std::{cell::RefCell, collections::HashMap, mem, rc::Rc};
|
use std::{cell::RefCell, collections::HashMap, mem, rc::Rc};
|
||||||
|
|
||||||
use reid_lib::{
|
use reid_lib::{
|
||||||
builder::{FunctionValue, GlobalValue, InstructionValue, TypeValue},
|
builder::{InstructionValue, TypeValue},
|
||||||
debug_information::{DebugInformation, DebugLocation, DebugScopeValue, DebugTypeValue},
|
debug_information::{DebugInformation, DebugLocation, DebugScopeValue, DebugTypeValue},
|
||||||
intrinsics::LLVMIntrinsic,
|
|
||||||
Block, Context, Function, Instr, Module,
|
Block, Context, Function, Instr, Module,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::intrinsics::LLVMIntrinsicKind,
|
|
||||||
lexer::FullToken,
|
lexer::FullToken,
|
||||||
mir::{
|
mir::{
|
||||||
self,
|
|
||||||
pass::{AssociatedFunctionKey, BinopKey},
|
pass::{AssociatedFunctionKey, BinopKey},
|
||||||
CustomTypeKey, FunctionParam, Metadata, SourceModuleId, TypeDefinition, TypeKind,
|
CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{allocator::Allocator, ErrorKind, IntrinsicFunction};
|
use super::{allocator::Allocator, ErrorKind, IntrinsicFunction, ModuleCodegen};
|
||||||
|
|
||||||
pub struct Scope<'ctx, 'scope> {
|
pub struct Scope<'ctx, 'scope> {
|
||||||
pub(super) context: &'ctx Context,
|
pub(super) context: &'ctx Context,
|
||||||
pub(super) modules: &'scope HashMap<SourceModuleId, &'ctx mir::Module>,
|
pub(super) modules: &'scope HashMap<SourceModuleId, ModuleCodegen<'ctx>>,
|
||||||
pub(super) tokens: &'ctx Vec<FullToken>,
|
pub(super) tokens: &'ctx Vec<FullToken>,
|
||||||
pub(super) module: &'ctx Module<'ctx>,
|
pub(super) module: &'ctx Module<'ctx>,
|
||||||
pub(super) module_id: SourceModuleId,
|
pub(super) module_id: SourceModuleId,
|
||||||
@ -29,15 +26,12 @@ pub struct Scope<'ctx, 'scope> {
|
|||||||
pub(super) block: Block<'ctx>,
|
pub(super) block: Block<'ctx>,
|
||||||
pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>,
|
pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>,
|
||||||
pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>,
|
pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>,
|
||||||
pub(super) type_map: &'scope HashMap<CustomTypeKey, TypeDefinition>,
|
|
||||||
pub(super) assoc_functions: &'scope HashMap<AssociatedFunctionKey, ScopeFunctionKind<'ctx>>,
|
pub(super) assoc_functions: &'scope HashMap<AssociatedFunctionKey, ScopeFunctionKind<'ctx>>,
|
||||||
pub(super) functions: &'scope HashMap<String, ScopeFunctionKind<'ctx>>,
|
pub(super) functions: &'scope HashMap<String, ScopeFunctionKind<'ctx>>,
|
||||||
pub(super) binops: &'scope HashMap<BinopKey, StackBinopDefinition<'ctx>>,
|
pub(super) binops: &'scope HashMap<BinopKey, StackBinopDefinition<'ctx>>,
|
||||||
pub(super) stack_values: HashMap<String, StackValue>,
|
pub(super) stack_values: HashMap<String, StackValue>,
|
||||||
pub(super) globals: &'scope HashMap<String, GlobalValue>,
|
|
||||||
pub(super) debug: Option<Debug<'ctx>>,
|
pub(super) debug: Option<Debug<'ctx>>,
|
||||||
pub(super) allocator: Rc<RefCell<Allocator>>,
|
pub(super) allocator: Rc<RefCell<Allocator>>,
|
||||||
pub(super) llvm_intrinsics: Rc<RefCell<HashMap<LLVMIntrinsicKind, FunctionValue>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, 'a> Scope<'ctx, 'a> {
|
impl<'ctx, 'a> Scope<'ctx, 'a> {
|
||||||
@ -54,13 +48,10 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
|
|||||||
functions: self.functions,
|
functions: self.functions,
|
||||||
types: self.types,
|
types: self.types,
|
||||||
type_values: self.type_values,
|
type_values: self.type_values,
|
||||||
type_map: self.type_map,
|
|
||||||
stack_values: self.stack_values.clone(),
|
stack_values: self.stack_values.clone(),
|
||||||
debug: self.debug.clone(),
|
debug: self.debug.clone(),
|
||||||
allocator: self.allocator.clone(),
|
allocator: self.allocator.clone(),
|
||||||
globals: self.globals,
|
|
||||||
binops: self.binops,
|
binops: self.binops,
|
||||||
llvm_intrinsics: self.llvm_intrinsics.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,51 +67,8 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
|
|||||||
self.type_values.get(key).and_then(|v| self.types.get(v))
|
self.type_values.get(key).and_then(|v| self.types.get(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate(&self, meta: &Metadata, ty: &TypeKind) -> Option<InstructionValue> {
|
pub fn allocate(&self, name: &String, ty: &TypeKind) -> Option<InstructionValue> {
|
||||||
self.allocator.borrow_mut().allocate(meta, ty)
|
self.allocator.borrow_mut().allocate(name, ty)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_intrinsic(&self, kind: LLVMIntrinsicKind) -> FunctionValue {
|
|
||||||
let mut intrinsics = self.llvm_intrinsics.borrow_mut();
|
|
||||||
if let Some(fun) = intrinsics.get(&kind) {
|
|
||||||
*fun
|
|
||||||
} else {
|
|
||||||
let intrinsic = self
|
|
||||||
.module
|
|
||||||
.intrinsic(match &kind {
|
|
||||||
LLVMIntrinsicKind::Max(ty) => LLVMIntrinsic::Max(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Min(ty) => LLVMIntrinsic::Min(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Abs(ty) => LLVMIntrinsic::Abs(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Memcpy(ty) => LLVMIntrinsic::Memcpy(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Sqrt(ty) => LLVMIntrinsic::Sqrt(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::PowI(lhs, rhs) => {
|
|
||||||
LLVMIntrinsic::PowI(lhs.get_type(self.type_values), rhs.get_type(self.type_values))
|
|
||||||
}
|
|
||||||
LLVMIntrinsicKind::Pow(ty) => LLVMIntrinsic::Pow(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Sin(ty) => LLVMIntrinsic::Sin(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Cos(ty) => LLVMIntrinsic::Cos(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Tan(ty) => LLVMIntrinsic::Tan(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::ASin(ty) => LLVMIntrinsic::ASin(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::ACos(ty) => LLVMIntrinsic::ACos(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::ATan(ty) => LLVMIntrinsic::ATan(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::ATan2(ty) => LLVMIntrinsic::ATan2(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::SinH(ty) => LLVMIntrinsic::SinH(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::CosH(ty) => LLVMIntrinsic::CosH(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::TanH(ty) => LLVMIntrinsic::TanH(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Log(ty) => LLVMIntrinsic::Log(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Log2(ty) => LLVMIntrinsic::Log2(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Log10(ty) => LLVMIntrinsic::Log10(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Copysign(ty) => LLVMIntrinsic::Copysign(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Floor(ty) => LLVMIntrinsic::Floor(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Ceil(ty) => LLVMIntrinsic::Ceil(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Trunc(ty) => LLVMIntrinsic::Trunc(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::RoundEven(ty) => LLVMIntrinsic::RoundEven(ty.get_type(self.type_values)),
|
|
||||||
LLVMIntrinsicKind::Round(ty) => LLVMIntrinsic::Round(ty.get_type(self.type_values)),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
intrinsics.insert(kind, intrinsic.clone());
|
|
||||||
intrinsic
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +129,7 @@ impl StackValueKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct StackBinopDefinition<'ctx> {
|
pub struct StackBinopDefinition<'ctx> {
|
||||||
pub(super) parameters: (FunctionParam, FunctionParam),
|
pub(super) parameters: ((String, TypeKind), (String, TypeKind)),
|
||||||
pub(super) return_ty: TypeKind,
|
pub(super) return_ty: TypeKind,
|
||||||
pub(super) kind: ScopeFunctionKind<'ctx>,
|
pub(super) kind: ScopeFunctionKind<'ctx>,
|
||||||
}
|
}
|
||||||
@ -199,14 +147,14 @@ impl<'ctx> StackBinopDefinition<'ctx> {
|
|||||||
rhs: StackValue,
|
rhs: StackValue,
|
||||||
scope: &mut Scope<'ctx, 'a>,
|
scope: &mut Scope<'ctx, 'a>,
|
||||||
) -> Result<StackValue, ErrorKind> {
|
) -> Result<StackValue, ErrorKind> {
|
||||||
let (lhs, rhs) = if lhs.1 == self.parameters.0.ty && rhs.1 == self.parameters.1.ty {
|
let (lhs, rhs) = if lhs.1 == self.parameters.0 .1 && rhs.1 == self.parameters.1 .1 {
|
||||||
(lhs, rhs)
|
(lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
(rhs, lhs)
|
(rhs, lhs)
|
||||||
};
|
};
|
||||||
let name = format!(
|
let name = format!(
|
||||||
"binop.{}.{}.{}.call",
|
"binop.{}.{}.{}.call",
|
||||||
self.parameters.0.ty, self.parameters.1.ty, self.return_ty
|
self.parameters.0 .1, self.parameters.1 .1, self.return_ty
|
||||||
);
|
);
|
||||||
self.kind.codegen(&name, &[lhs, rhs], &self.return_ty, None, scope)
|
self.kind.codegen(&name, &[lhs, rhs], &self.return_ty, None, scope)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use reid_lib::{
|
|||||||
DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocation, DebugPointerType,
|
DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocation, DebugPointerType,
|
||||||
DebugPosition, DebugScopeValue, DebugStructType, DebugTypeData, DebugTypeValue, DwarfEncoding, DwarfFlags,
|
DebugPosition, DebugScopeValue, DebugStructType, DebugTypeData, DebugTypeValue, DwarfEncoding, DwarfFlags,
|
||||||
},
|
},
|
||||||
Block, CmpPredicate, ConstValueKind, Instr, Type,
|
Block, CmpPredicate, ConstValue, Instr, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -14,7 +14,10 @@ use crate::{
|
|||||||
mir::{self, CustomTypeKey, Metadata, SourceModuleId, TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral},
|
mir::{self, CustomTypeKey, Metadata, SourceModuleId, TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::scope::{Debug, Scope};
|
use super::{
|
||||||
|
scope::{Debug, Scope},
|
||||||
|
ModuleCodegen,
|
||||||
|
};
|
||||||
|
|
||||||
impl mir::CmpOperator {
|
impl mir::CmpOperator {
|
||||||
pub(super) fn predicate(&self) -> CmpPredicate {
|
pub(super) fn predicate(&self) -> CmpPredicate {
|
||||||
@ -31,36 +34,34 @@ impl mir::CmpOperator {
|
|||||||
|
|
||||||
impl mir::Literal {
|
impl mir::Literal {
|
||||||
pub(super) fn as_const(&self, block: &mut Block) -> InstructionValue {
|
pub(super) fn as_const(&self, block: &mut Block) -> InstructionValue {
|
||||||
block
|
block.build_named(format!("{}", self), self.as_const_kind()).unwrap()
|
||||||
.build_named(format!("{}", self), Instr::Constant(self.as_const_kind()))
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn as_const_kind(&self) -> ConstValueKind {
|
pub(super) fn as_const_kind(&self) -> Instr {
|
||||||
match self.clone() {
|
Instr::Constant(match self.clone() {
|
||||||
mir::Literal::I8(val) => ConstValueKind::I8(val),
|
mir::Literal::I8(val) => ConstValue::I8(val),
|
||||||
mir::Literal::I16(val) => ConstValueKind::I16(val),
|
mir::Literal::I16(val) => ConstValue::I16(val),
|
||||||
mir::Literal::I32(val) => ConstValueKind::I32(val),
|
mir::Literal::I32(val) => ConstValue::I32(val),
|
||||||
mir::Literal::I64(val) => ConstValueKind::I64(val),
|
mir::Literal::I64(val) => ConstValue::I64(val),
|
||||||
mir::Literal::I128(val) => ConstValueKind::I128(val),
|
mir::Literal::I128(val) => ConstValue::I128(val),
|
||||||
mir::Literal::U8(val) => ConstValueKind::U8(val),
|
mir::Literal::U8(val) => ConstValue::U8(val),
|
||||||
mir::Literal::U16(val) => ConstValueKind::U16(val),
|
mir::Literal::U16(val) => ConstValue::U16(val),
|
||||||
mir::Literal::U32(val) => ConstValueKind::U32(val),
|
mir::Literal::U32(val) => ConstValue::U32(val),
|
||||||
mir::Literal::U64(val) => ConstValueKind::U64(val),
|
mir::Literal::U64(val) => ConstValue::U64(val),
|
||||||
mir::Literal::U128(val) => ConstValueKind::U128(val),
|
mir::Literal::U128(val) => ConstValue::U128(val),
|
||||||
mir::Literal::Bool(val) => ConstValueKind::Bool(val),
|
mir::Literal::Bool(val) => ConstValue::Bool(val),
|
||||||
mir::Literal::String(val) => ConstValueKind::Str(val.clone()),
|
mir::Literal::String(val) => ConstValue::Str(val.clone()),
|
||||||
mir::Literal::Vague(VagueLiteral::Number(val)) => ConstValueKind::I32(val as i32),
|
mir::Literal::Vague(VagueLiteral::Number(val)) => ConstValue::I32(val as i32),
|
||||||
mir::Literal::Vague(VagueLiteral::Decimal(val)) => ConstValueKind::F32(val as f32),
|
mir::Literal::Vague(VagueLiteral::Decimal(val)) => ConstValue::F32(val as f32),
|
||||||
mir::Literal::F16(val) => ConstValueKind::F16(val),
|
mir::Literal::F16(val) => ConstValue::F16(val),
|
||||||
mir::Literal::F32B(val) => ConstValueKind::F32B(val),
|
mir::Literal::F32B(val) => ConstValue::F32B(val),
|
||||||
mir::Literal::F32(val) => ConstValueKind::F32(val),
|
mir::Literal::F32(val) => ConstValue::F32(val),
|
||||||
mir::Literal::F64(val) => ConstValueKind::F64(val),
|
mir::Literal::F64(val) => ConstValue::F64(val),
|
||||||
mir::Literal::F80(val) => ConstValueKind::F80(val),
|
mir::Literal::F80(val) => ConstValue::F80(val),
|
||||||
mir::Literal::F128(val) => ConstValueKind::F128(val),
|
mir::Literal::F128(val) => ConstValue::F128(val),
|
||||||
mir::Literal::F128PPC(val) => ConstValueKind::F128PPC(val),
|
mir::Literal::F128PPC(val) => ConstValue::F128PPC(val),
|
||||||
mir::Literal::Char(c) => ConstValueKind::U8(c as u8),
|
mir::Literal::Char(c) => ConstValue::U8(c as u8),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +80,7 @@ impl TypeKind {
|
|||||||
TypeKind::U128 => Type::U128,
|
TypeKind::U128 => Type::U128,
|
||||||
TypeKind::Bool => Type::Bool,
|
TypeKind::Bool => Type::Bool,
|
||||||
TypeKind::F16 => Type::F16,
|
TypeKind::F16 => Type::F16,
|
||||||
TypeKind::F16B => Type::F32B,
|
TypeKind::F32B => Type::F32B,
|
||||||
TypeKind::F32 => Type::F32,
|
TypeKind::F32 => Type::F32,
|
||||||
TypeKind::F64 => Type::F64,
|
TypeKind::F64 => Type::F64,
|
||||||
TypeKind::F128 => Type::F128,
|
TypeKind::F128 => Type::F128,
|
||||||
@ -106,7 +107,8 @@ impl TypeKind {
|
|||||||
&debug.scope,
|
&debug.scope,
|
||||||
debug.info,
|
debug.info,
|
||||||
debug.types,
|
debug.types,
|
||||||
scope.type_map,
|
scope.type_values,
|
||||||
|
scope.types,
|
||||||
scope.module_id,
|
scope.module_id,
|
||||||
scope.tokens,
|
scope.tokens,
|
||||||
scope.modules,
|
scope.modules,
|
||||||
@ -118,10 +120,11 @@ impl TypeKind {
|
|||||||
scope: &DebugScopeValue,
|
scope: &DebugScopeValue,
|
||||||
debug_info: &DebugInformation,
|
debug_info: &DebugInformation,
|
||||||
debug_types: &HashMap<TypeKind, DebugTypeValue>,
|
debug_types: &HashMap<TypeKind, DebugTypeValue>,
|
||||||
type_map: &HashMap<CustomTypeKey, TypeDefinition>,
|
type_values: &HashMap<CustomTypeKey, TypeValue>,
|
||||||
|
types: &HashMap<TypeValue, TypeDefinition>,
|
||||||
local_mod: SourceModuleId,
|
local_mod: SourceModuleId,
|
||||||
tokens: &Vec<FullToken>,
|
tokens: &Vec<FullToken>,
|
||||||
modules: &HashMap<SourceModuleId, &mir::Module>,
|
modules: &HashMap<SourceModuleId, ModuleCodegen>,
|
||||||
) -> DebugTypeValue {
|
) -> DebugTypeValue {
|
||||||
if let Some(ty) = debug_types.get(self) {
|
if let Some(ty) = debug_types.get(self) {
|
||||||
return *ty;
|
return *ty;
|
||||||
@ -137,12 +140,13 @@ impl TypeKind {
|
|||||||
scope,
|
scope,
|
||||||
debug_info,
|
debug_info,
|
||||||
debug_types,
|
debug_types,
|
||||||
type_map,
|
type_values,
|
||||||
|
types,
|
||||||
local_mod,
|
local_mod,
|
||||||
tokens,
|
tokens,
|
||||||
modules,
|
modules,
|
||||||
),
|
),
|
||||||
size_bits: self.size_of(type_map),
|
size_bits: self.size_of(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
TypeKind::Array(elem_ty, len) => {
|
TypeKind::Array(elem_ty, len) => {
|
||||||
@ -150,20 +154,21 @@ impl TypeKind {
|
|||||||
scope,
|
scope,
|
||||||
debug_info,
|
debug_info,
|
||||||
debug_types,
|
debug_types,
|
||||||
type_map,
|
type_values,
|
||||||
|
types,
|
||||||
local_mod,
|
local_mod,
|
||||||
tokens,
|
tokens,
|
||||||
modules,
|
modules,
|
||||||
);
|
);
|
||||||
DebugTypeData::Array(DebugArrayType {
|
DebugTypeData::Array(DebugArrayType {
|
||||||
size_bits: self.size_of(type_map),
|
size_bits: self.size_of(),
|
||||||
align_bits: self.alignment(),
|
align_bits: self.alignment(),
|
||||||
element_type: elem_ty,
|
element_type: elem_ty,
|
||||||
length: *len,
|
length: *len,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
TypeKind::CustomType(key) => {
|
TypeKind::CustomType(key) => {
|
||||||
let typedef = type_map.get(key).unwrap();
|
let typedef = types.get(type_values.get(key).unwrap()).unwrap();
|
||||||
match &typedef.kind {
|
match &typedef.kind {
|
||||||
TypeDefinitionKind::Struct(struct_type) => {
|
TypeDefinitionKind::Struct(struct_type) => {
|
||||||
let mut fields = Vec::new();
|
let mut fields = Vec::new();
|
||||||
@ -179,20 +184,21 @@ impl TypeKind {
|
|||||||
name: field.0.clone(),
|
name: field.0.clone(),
|
||||||
scope: scope.clone(),
|
scope: scope.clone(),
|
||||||
pos: location.map(|l| l.pos),
|
pos: location.map(|l| l.pos),
|
||||||
size_bits: field.1.size_of(type_map),
|
size_bits: field.1.size_of(),
|
||||||
offset: size_bits,
|
offset: size_bits,
|
||||||
flags: DwarfFlags,
|
flags: DwarfFlags,
|
||||||
ty: field.1.get_debug_type_hard(
|
ty: field.1.get_debug_type_hard(
|
||||||
scope,
|
scope,
|
||||||
debug_info,
|
debug_info,
|
||||||
debug_types,
|
debug_types,
|
||||||
type_map,
|
type_values,
|
||||||
|
types,
|
||||||
local_mod,
|
local_mod,
|
||||||
tokens,
|
tokens,
|
||||||
modules,
|
modules,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
size_bits += field.1.size_of(type_map);
|
size_bits += field.1.size_of();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let location = if typedef.source_module != local_mod {
|
let location = if typedef.source_module != local_mod {
|
||||||
@ -214,7 +220,7 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
_ => DebugTypeData::Basic(DebugBasicType {
|
_ => DebugTypeData::Basic(DebugBasicType {
|
||||||
name,
|
name,
|
||||||
size_bits: self.size_of(type_map),
|
size_bits: self.size_of(),
|
||||||
encoding: match self {
|
encoding: match self {
|
||||||
TypeKind::Bool => DwarfEncoding::Boolean,
|
TypeKind::Bool => DwarfEncoding::Boolean,
|
||||||
TypeKind::I8 => DwarfEncoding::SignedChar,
|
TypeKind::I8 => DwarfEncoding::SignedChar,
|
||||||
@ -223,7 +229,7 @@ impl TypeKind {
|
|||||||
TypeKind::U16 | TypeKind::U32 | TypeKind::U64 | TypeKind::U128 => DwarfEncoding::Unsigned,
|
TypeKind::U16 | TypeKind::U32 | TypeKind::U64 | TypeKind::U128 => DwarfEncoding::Unsigned,
|
||||||
TypeKind::F16
|
TypeKind::F16
|
||||||
| TypeKind::F32
|
| TypeKind::F32
|
||||||
| TypeKind::F16B
|
| TypeKind::F32B
|
||||||
| TypeKind::F64
|
| TypeKind::F64
|
||||||
| TypeKind::F80
|
| TypeKind::F80
|
||||||
| TypeKind::F128
|
| TypeKind::F128
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::{Debug, Write},
|
fmt::{Debug, Write},
|
||||||
path::PathBuf,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::token_stream::{self, TokenRange},
|
ast::token_stream::{self, TokenRange},
|
||||||
codegen,
|
codegen,
|
||||||
lexer::{self, Cursor, FullToken, Position},
|
lexer::{self, Cursor, FullToken, Position},
|
||||||
mir::{self, macros, pass, typecheck, Metadata, SourceModuleId},
|
mir::{self, pass, typecheck, Metadata, SourceModuleId},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::mir::typecheck::ErrorKind as TypecheckError;
|
use crate::mir::typecheck::ErrorKind as TypecheckError;
|
||||||
@ -34,8 +33,6 @@ pub enum ErrorKind {
|
|||||||
TypeInferenceError(#[source] mir::pass::Error<TypecheckError>),
|
TypeInferenceError(#[source] mir::pass::Error<TypecheckError>),
|
||||||
#[error("{}{}", label("(Linker) "), .0.kind)]
|
#[error("{}{}", label("(Linker) "), .0.kind)]
|
||||||
LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>),
|
LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>),
|
||||||
#[error("{}{}", label("(Macro) "), .0)]
|
|
||||||
MacroError(#[from] mir::pass::Error<macros::ErrorKind>),
|
|
||||||
#[error("{}{}", label("(Codegen) "), .0)]
|
#[error("{}{}", label("(Codegen) "), .0)]
|
||||||
CodegenError(#[from] codegen::ErrorKind),
|
CodegenError(#[from] codegen::ErrorKind),
|
||||||
}
|
}
|
||||||
@ -51,7 +48,7 @@ impl ErrorKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorKind {
|
impl ErrorKind {
|
||||||
pub fn get_meta(&self) -> Metadata {
|
fn get_meta(&self) -> Metadata {
|
||||||
match &self {
|
match &self {
|
||||||
ErrorKind::LexerError(error) => error.metadata,
|
ErrorKind::LexerError(error) => error.metadata,
|
||||||
ErrorKind::ParserError(error) => error.metadata,
|
ErrorKind::ParserError(error) => error.metadata,
|
||||||
@ -61,19 +58,6 @@ impl ErrorKind {
|
|||||||
ErrorKind::CodegenError(error) => match error {
|
ErrorKind::CodegenError(error) => match error {
|
||||||
codegen::ErrorKind::Null => Default::default(),
|
codegen::ErrorKind::Null => Default::default(),
|
||||||
},
|
},
|
||||||
ErrorKind::MacroError(error) => error.metadata,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_type_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
ErrorKind::LexerError(_) => "lexer",
|
|
||||||
ErrorKind::ParserError(_) => "parser",
|
|
||||||
ErrorKind::TypeCheckError(_) => "typechecker",
|
|
||||||
ErrorKind::TypeInferenceError(_) => "type-inferrer",
|
|
||||||
ErrorKind::LinkerError(_) => "linker",
|
|
||||||
ErrorKind::MacroError(_) => "macro-pass",
|
|
||||||
ErrorKind::CodegenError(_) => "codegen",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,37 +79,13 @@ pub struct ErrorModule {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
pub struct ErrorModules {
|
pub struct ErrorModules {
|
||||||
pub(super) module_map: HashMap<mir::SourceModuleId, ErrorModule>,
|
module_map: HashMap<mir::SourceModuleId, ErrorModule>,
|
||||||
pub(super) source_id_map: HashMap<PathBuf, mir::SourceModuleId>,
|
|
||||||
module_counter: mir::SourceModuleId,
|
module_counter: mir::SourceModuleId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorModules {
|
impl ErrorModules {
|
||||||
pub fn add_module<T: Into<String>>(
|
pub fn add_module<T: Into<String>>(&mut self, name: T) -> Option<mir::SourceModuleId> {
|
||||||
&mut self,
|
let id = self.module_counter.increment();
|
||||||
name: T,
|
|
||||||
path: Option<PathBuf>,
|
|
||||||
external_module_id: Option<SourceModuleId>,
|
|
||||||
) -> Option<mir::SourceModuleId> {
|
|
||||||
let module_id = path.as_ref().and_then(|p| self.source_id_map.get(p));
|
|
||||||
|
|
||||||
if let Some(module_id) = module_id {
|
|
||||||
Some(*module_id)
|
|
||||||
} else {
|
|
||||||
let id = if let Some(module_id) = external_module_id {
|
|
||||||
self.module_counter = SourceModuleId(module_id.0.max(self.module_counter.0));
|
|
||||||
if let Some(_) = self.module_map.get(&module_id) {
|
|
||||||
panic!("Can not use external module id: Module already exists!")
|
|
||||||
}
|
|
||||||
module_id
|
|
||||||
} else {
|
|
||||||
self.module_counter.increment()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(path) = path {
|
|
||||||
self.source_id_map.insert(path, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.module_map.insert(
|
self.module_map.insert(
|
||||||
id,
|
id,
|
||||||
ErrorModule {
|
ErrorModule {
|
||||||
@ -136,7 +96,6 @@ impl ErrorModules {
|
|||||||
);
|
);
|
||||||
Some(id)
|
Some(id)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_tokens(&mut self, id: mir::SourceModuleId, tokens: Vec<FullToken>) {
|
pub fn set_tokens(&mut self, id: mir::SourceModuleId, tokens: Vec<FullToken>) {
|
||||||
if let Some(module) = self.module_map.get_mut(&id) {
|
if let Some(module) = self.module_map.get_mut(&id) {
|
||||||
@ -158,7 +117,7 @@ impl ErrorModules {
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ReidError {
|
pub struct ReidError {
|
||||||
map: ErrorModules,
|
map: ErrorModules,
|
||||||
pub errors: Vec<ErrorKind>,
|
errors: Vec<ErrorKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReidError {
|
impl ReidError {
|
||||||
@ -207,10 +166,6 @@ impl ReidError {
|
|||||||
pub fn from_kind(errors: Vec<ErrorKind>, map: ErrorModules) -> ReidError {
|
pub fn from_kind(errors: Vec<ErrorKind>, map: ErrorModules) -> ReidError {
|
||||||
ReidError { map, errors }
|
ReidError { map, errors }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend(&mut self, other: ReidError) {
|
|
||||||
self.errors.extend(other.errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for ReidError {}
|
impl std::error::Error for ReidError {}
|
||||||
@ -227,7 +182,9 @@ impl std::fmt::Display for ReidError {
|
|||||||
let module = self.map.module(&meta.source_module_id);
|
let module = self.map.module(&meta.source_module_id);
|
||||||
let position = if let Some(module) = module {
|
let position = if let Some(module) = module {
|
||||||
if let Some(tokens) = &module.tokens {
|
if let Some(tokens) = &module.tokens {
|
||||||
meta.range.into_position(tokens).or(meta.position.map(|p| (p, p)))
|
let range_tokens = meta.range.into_tokens(&tokens);
|
||||||
|
|
||||||
|
get_position(&range_tokens).or(meta.position.map(|p| (p, p)))
|
||||||
} else if let Some(position) = meta.position {
|
} else if let Some(position) = meta.position {
|
||||||
Some((position, position))
|
Some((position, position))
|
||||||
} else {
|
} else {
|
||||||
@ -277,11 +234,6 @@ impl TokenRange {
|
|||||||
.take(self.end + 1 - self.start)
|
.take(self.end + 1 - self.start)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_position<'v>(&self, tokens: &'v Vec<FullToken>) -> Option<(Position, Position)> {
|
|
||||||
let tokens = self.into_tokens(tokens);
|
|
||||||
get_position(&tokens)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_position(tokens: &Vec<&FullToken>) -> Option<(Position, Position)> {
|
fn get_position(tokens: &Vec<&FullToken>) -> Option<(Position, Position)> {
|
||||||
|
|||||||
@ -25,58 +25,38 @@ impl LDRunner {
|
|||||||
|
|
||||||
let dyn_linker_path = find_objectfile(&self.dynamic_linker);
|
let dyn_linker_path = find_objectfile(&self.dynamic_linker);
|
||||||
let crt1_path = find_objectfile("crt1.o");
|
let crt1_path = find_objectfile("crt1.o");
|
||||||
let crti_path = find_objectfile("crti.o");
|
|
||||||
let crtn_path = find_objectfile("crtn.o");
|
|
||||||
|
|
||||||
log::debug!("LDRunner: Using dynamic linker at: {:?}", dyn_linker_path);
|
println!("LDRunner: Using dynamic linker at: {:?}", dyn_linker_path);
|
||||||
|
|
||||||
let mut ld = Command::new(&self.command);
|
let mut ld = Command::new(&self.command);
|
||||||
ld.arg("-dynamic-linker")
|
ld.arg("-dynamic-linker")
|
||||||
.arg(dyn_linker_path)
|
.arg(dyn_linker_path)
|
||||||
.arg(crt1_path)
|
.arg(crt1_path);
|
||||||
.arg(crti_path);
|
|
||||||
|
|
||||||
for library in &self.libraries {
|
for library in &self.libraries {
|
||||||
ld.arg(format!("-l{}", library));
|
ld.arg(format!("-l{}", library));
|
||||||
}
|
}
|
||||||
ld.arg(crtn_path);
|
|
||||||
|
|
||||||
ld.arg(input_path.to_str().unwrap())
|
ld.arg(input_path.to_str().unwrap())
|
||||||
.arg("-o")
|
.arg("-o")
|
||||||
.arg(out_path.to_str().unwrap());
|
.arg(out_path.to_str().unwrap());
|
||||||
|
|
||||||
log::debug!("{:#?}", ld);
|
println!(
|
||||||
|
|
||||||
log::debug!(
|
|
||||||
"LDRunner: Executing linker to objfile at {:?} => {:?}",
|
"LDRunner: Executing linker to objfile at {:?} => {:?}",
|
||||||
input_path,
|
input_path, out_path
|
||||||
out_path
|
|
||||||
);
|
);
|
||||||
|
dbg!(&ld);
|
||||||
|
|
||||||
let ld_output = ld.output().expect("Unable to execute ld!");
|
ld.spawn().expect("Unable to execute ld!");
|
||||||
if !ld_output.status.success() {
|
|
||||||
let code = ld_output.status.code().unwrap_or(255);
|
|
||||||
log::error!("LD exited with code {code}");
|
|
||||||
println!("{}", unsafe { String::from_utf8_unchecked(ld_output.stderr) });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
thread::sleep(Duration::from_millis(100));
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
|
||||||
log::debug!("Setting executable bit to {:?}..", out_path);
|
println!("Setting executable bit to {:?}..", out_path);
|
||||||
|
Command::new("chmod")
|
||||||
let chmod_output = Command::new("chmod")
|
|
||||||
.arg("+x")
|
.arg("+x")
|
||||||
.arg(out_path)
|
.arg(out_path)
|
||||||
.output()
|
.spawn()
|
||||||
.expect("Unable to execute ld!");
|
.unwrap();
|
||||||
|
|
||||||
if !chmod_output.status.success() {
|
|
||||||
let code = chmod_output.status.code().unwrap_or(255);
|
|
||||||
log::error!("chmod exited with code {code}");
|
|
||||||
println!("{}", unsafe { String::from_utf8_unchecked(chmod_output.stderr) });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
thread::sleep(Duration::from_millis(100));
|
thread::sleep(Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,12 +66,6 @@ fn find_objectfile(name: &str) -> String {
|
|||||||
.arg(&name)
|
.arg(&name)
|
||||||
.output()
|
.output()
|
||||||
.expect("Unable to execute whereis");
|
.expect("Unable to execute whereis");
|
||||||
if !whereis.status.success() {
|
|
||||||
let code = whereis.status.code().unwrap_or(255);
|
|
||||||
log::error!("whereis exited with code {code}");
|
|
||||||
println!("{}", unsafe { String::from_utf8_unchecked(whereis.stderr) });
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
let whereis_output = String::from_utf8(whereis.stdout).unwrap();
|
let whereis_output = String::from_utf8(whereis.stdout).unwrap();
|
||||||
|
|
||||||
whereis_output
|
whereis_output
|
||||||
@ -104,15 +78,3 @@ fn find_objectfile(name: &str) -> String {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.to_owned()
|
.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(path: &PathBuf) -> Option<i32> {
|
|
||||||
let output = Command::new(path.clone()).output().expect("Unable to execute {path}");
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
let code = output.status.code().unwrap_or(255);
|
|
||||||
log::error!("{path:?} exited with code {code}");
|
|
||||||
println!("{}", unsafe { String::from_utf8_unchecked(output.stderr) });
|
|
||||||
}
|
|
||||||
|
|
||||||
output.status.code()
|
|
||||||
}
|
|
||||||
|
|||||||
195
reid/src/lib.rs
195
reid/src/lib.rs
@ -8,36 +8,22 @@
|
|||||||
//! Much of the syntax in Reid is directly inspired by rust, but mostly it is
|
//! Much of the syntax in Reid is directly inspired by rust, but mostly it is
|
||||||
//! driven by simplicity.
|
//! driven by simplicity.
|
||||||
//!
|
//!
|
||||||
//! Specifications and a bunch of [documentation for the language can be found
|
|
||||||
//! here](./documentation/).
|
|
||||||
//!
|
|
||||||
//! An example of a real whole program (a CPU pathtracer) can be found [in
|
|
||||||
//! examples/cpu_raytracer.reid](./examples/cpu_raytracer.reid), go have a look!
|
|
||||||
//!
|
|
||||||
//! 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,
|
//! - Do basic algebra (e.g. Add, Sub, Mult)
|
||||||
//! And, Not)
|
|
||||||
//! - Resolve complex one-liners correctly using PEDMAS (e.g. `5 + 2 * 5 - 5 *
|
//! - Resolve complex one-liners correctly using PEDMAS (e.g. `5 + 2 * 5 - 5 *
|
||||||
//! 5` is calculated correctly)
|
//! 5` is calculated correctly)
|
||||||
//! - Handle borrows/derefs, pointers.
|
|
||||||
//! - Declare and call functions with varying parameters and return types
|
//! - Declare and call functions with varying parameters and return types
|
||||||
//! - Perform type-checking and type-inference such that return-types and
|
//! - Perform type-checking and type-inference such that return-types and
|
||||||
//! parameter types must always match.
|
//! parameter types must always match.
|
||||||
//! - Do simple logic-operations (e.g. If/And/Or)
|
//! - Do simple logic-operations (e.g. If/And/Or)
|
||||||
//! - Handle, access, define and initialize structs and arrays.
|
|
||||||
//! - Define and execute For/While loops
|
|
||||||
//! - Output detailed debug information
|
|
||||||
//! - Define extern functions that can be linked to outside modules such as
|
|
||||||
//! `libc`.
|
|
||||||
//! - Define custom binary operations for any two types that hasn't been defined
|
|
||||||
//! previously (such as `u16 + u32`).
|
|
||||||
//!
|
//!
|
||||||
//!
|
//! An example program of Reid, that calculates the 5th fibonacci number (and
|
||||||
//! An example program of Reid, that calculates the 5th fibonacci number:
|
//! uses Rust for highlighting) is:
|
||||||
//! ```reid
|
//! ```reid
|
||||||
//! fn main() -> u16 {
|
//! fn main() -> u16 {
|
||||||
//! return fibonacci(5);
|
//! return fibonacci(5);
|
||||||
//! }
|
//! }
|
||||||
|
//!
|
||||||
//! fn fibonacci(n: u16) -> u16 {
|
//! fn fibonacci(n: u16) -> u16 {
|
||||||
//! if n <= 2 {
|
//! if n <= 2 {
|
||||||
//! return 1;
|
//! return 1;
|
||||||
@ -46,13 +32,16 @@
|
|||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! TODOs still (see README.md for more)
|
//! Currently missing relevant features (TODOs) are:
|
||||||
//! - Error handling
|
//! - ~~Arrays~~ (DONE)
|
||||||
//! - Lexing & parsing of whitespace and comments as well
|
//! - Structs (and custom types as such)
|
||||||
//! - LSP implementation
|
//! - ~~Extern functions~~ (DONE)
|
||||||
|
//! - ~~Strings~~ (DONE)
|
||||||
|
//! - Loops
|
||||||
|
//! - Debug Symbols
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::{path::PathBuf, thread, time::Duration};
|
||||||
|
|
||||||
use ast::{
|
use ast::{
|
||||||
lexer::{self, FullToken, Token},
|
lexer::{self, FullToken, Token},
|
||||||
@ -67,16 +56,10 @@ use mir::{
|
|||||||
};
|
};
|
||||||
use reid_lib::{compile::CompileOutput, Context};
|
use reid_lib::{compile::CompileOutput, Context};
|
||||||
|
|
||||||
use crate::{
|
use crate::ast::TopLevelStatement;
|
||||||
ast::TopLevelStatement,
|
|
||||||
mir::{
|
|
||||||
macros::{form_macros, MacroModule, MacroPass},
|
|
||||||
SourceModuleId,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub mod ast;
|
mod ast;
|
||||||
pub mod codegen;
|
mod codegen;
|
||||||
pub mod error_raporting;
|
pub mod error_raporting;
|
||||||
pub mod ld;
|
pub mod ld;
|
||||||
pub mod mir;
|
pub mod mir;
|
||||||
@ -86,11 +69,9 @@ mod util;
|
|||||||
pub fn parse_module<'map, T: Into<String>>(
|
pub fn parse_module<'map, T: Into<String>>(
|
||||||
source: &str,
|
source: &str,
|
||||||
name: T,
|
name: T,
|
||||||
path: Option<PathBuf>,
|
|
||||||
map: &'map mut ErrorModules,
|
map: &'map mut ErrorModules,
|
||||||
module_id: Option<SourceModuleId>,
|
|
||||||
) -> Result<(mir::SourceModuleId, Vec<FullToken>), ReidError> {
|
) -> Result<(mir::SourceModuleId, Vec<FullToken>), ReidError> {
|
||||||
let id = map.add_module(name.into(), path, module_id).unwrap();
|
let id = map.add_module(name.into()).unwrap();
|
||||||
map.set_source(id, source.to_owned());
|
map.set_source(id, source.to_owned());
|
||||||
|
|
||||||
let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?;
|
let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?;
|
||||||
@ -98,7 +79,7 @@ pub fn parse_module<'map, T: Into<String>>(
|
|||||||
map.set_tokens(id, tokens.clone());
|
map.set_tokens(id, tokens.clone());
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:#?}", &tokens);
|
println!("{:#?}", &tokens);
|
||||||
|
|
||||||
Ok((id, tokens))
|
Ok((id, tokens))
|
||||||
}
|
}
|
||||||
@ -109,7 +90,7 @@ pub fn compile_module<'map>(
|
|||||||
map: &'map mut ErrorModules,
|
map: &'map mut ErrorModules,
|
||||||
path: Option<PathBuf>,
|
path: Option<PathBuf>,
|
||||||
is_main: bool,
|
is_main: bool,
|
||||||
) -> Result<Result<mir::Module, (ast::Module, ReidError)>, ReidError> {
|
) -> Result<mir::Module, ReidError> {
|
||||||
let module = map.module(&module_id).cloned().unwrap();
|
let module = map.module(&module_id).cloned().unwrap();
|
||||||
|
|
||||||
let mut token_stream = TokenStream::from(&tokens);
|
let mut token_stream = TokenStream::from(&tokens);
|
||||||
@ -121,8 +102,6 @@ pub fn compile_module<'map>(
|
|||||||
statements.push(statement);
|
statements.push(statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
let errors = token_stream.errors();
|
|
||||||
|
|
||||||
drop(token_stream);
|
drop(token_stream);
|
||||||
|
|
||||||
let ast_module = ast::Module {
|
let ast_module = ast::Module {
|
||||||
@ -133,33 +112,10 @@ pub fn compile_module<'map>(
|
|||||||
is_main,
|
is_main,
|
||||||
};
|
};
|
||||||
|
|
||||||
if errors.len() > 0 {
|
|
||||||
// dbg!(&ast_module);
|
|
||||||
return Ok(Err((
|
|
||||||
ast_module,
|
|
||||||
ReidError::from_kind(
|
|
||||||
errors
|
|
||||||
.into_iter()
|
|
||||||
.map(|e| {
|
|
||||||
error_raporting::ErrorKind::from(mir::pass::Error {
|
|
||||||
metadata: mir::Metadata {
|
|
||||||
source_module_id: module_id,
|
|
||||||
range: *e.get_range().unwrap_or(&Default::default()),
|
|
||||||
position: None,
|
|
||||||
},
|
|
||||||
kind: e,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
map.clone(),
|
|
||||||
),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:#?}", &ast_module);
|
dbg!(&ast_module);
|
||||||
|
|
||||||
Ok(Ok(ast_module.process(module_id)))
|
Ok(ast_module.process(module_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform_all_passes<'map>(
|
pub fn perform_all_passes<'map>(
|
||||||
@ -167,60 +123,7 @@ pub fn perform_all_passes<'map>(
|
|||||||
module_map: &'map mut ErrorModules,
|
module_map: &'map mut ErrorModules,
|
||||||
) -> Result<(), ReidError> {
|
) -> Result<(), ReidError> {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:#?}", &context);
|
dbg!(&context);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
log::trace!("{:#}", &context);
|
|
||||||
|
|
||||||
let state = context.pass(&mut LinkerPass {
|
|
||||||
module_map,
|
|
||||||
is_lib: true,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
for module in &mut context.modules {
|
|
||||||
for intrinsic in form_intrinsics() {
|
|
||||||
module.1.functions.insert(0, intrinsic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
log::trace!("{:-^100}", "LINKER OUTPUT");
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
log::trace!("{:#}", &context);
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
log::trace!("{:#?}", &state);
|
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
|
||||||
return Err(ReidError::from_kind(
|
|
||||||
state.errors.iter().map(|e| e.clone().into()).collect(),
|
|
||||||
module_map.clone(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut macro_modules: HashMap<_, MacroModule> = HashMap::new();
|
|
||||||
for (k, v) in &context.modules {
|
|
||||||
macro_modules.insert(k.clone(), v.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut macro_pass = MacroPass {
|
|
||||||
macros: form_macros(),
|
|
||||||
module_map: macro_modules,
|
|
||||||
};
|
|
||||||
let state = context.pass(&mut macro_pass)?;
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
log::trace!("{:-^100}", "MACRO OUTPUT");
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
log::trace!("{:#}", &context);
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
log::trace!("{:#?}", &state);
|
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
|
||||||
return Err(ReidError::from_kind(
|
|
||||||
state.errors.iter().map(|e| e.clone().into()).collect(),
|
|
||||||
module_map.clone(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut binops = BinopMap::default();
|
let mut binops = BinopMap::default();
|
||||||
for module in &mut context.modules {
|
for module in &mut context.modules {
|
||||||
@ -228,11 +131,11 @@ pub fn perform_all_passes<'map>(
|
|||||||
binops
|
binops
|
||||||
.set(
|
.set(
|
||||||
mir::pass::BinopKey {
|
mir::pass::BinopKey {
|
||||||
params: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()),
|
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||||
operator: intrinsic.op,
|
operator: intrinsic.op,
|
||||||
},
|
},
|
||||||
mir::pass::ScopeBinopDef {
|
mir::pass::ScopeBinopDef {
|
||||||
hands: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()),
|
hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||||
operator: intrinsic.op,
|
operator: intrinsic.op,
|
||||||
return_ty: intrinsic.return_type.clone(),
|
return_ty: intrinsic.return_type.clone(),
|
||||||
},
|
},
|
||||||
@ -242,18 +145,46 @@ pub fn perform_all_passes<'map>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for module in &mut context.modules {
|
||||||
|
for intrinsic in form_intrinsics() {
|
||||||
|
module.1.functions.insert(0, intrinsic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
println!("{:#}", &context);
|
||||||
|
|
||||||
|
let state = context.pass(&mut LinkerPass {
|
||||||
|
module_map,
|
||||||
|
is_lib: true,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
println!("{:-^100}", "LINKER OUTPUT");
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
println!("{:#}", &context);
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
dbg!(&state);
|
||||||
|
|
||||||
|
if !state.errors.is_empty() {
|
||||||
|
return Err(ReidError::from_kind(
|
||||||
|
state.errors.iter().map(|e| e.clone().into()).collect(),
|
||||||
|
module_map.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let mut refs = TypeRefs::with_binops(binops);
|
let mut refs = TypeRefs::with_binops(binops);
|
||||||
|
|
||||||
let state = context.pass(&mut TypeInference { refs: &mut refs })?;
|
let state = context.pass(&mut TypeInference { refs: &mut refs })?;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:-^70}", "TYPE INFERRER OUTPUT");
|
println!("{:-^100}", "TYPE INFERRER OUTPUT");
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{}", &refs);
|
println!("{}", &refs);
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:#}", &context);
|
println!("{:#}", &context);
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:#?}", &state);
|
dbg!(&state);
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::from_kind(
|
return Err(ReidError::from_kind(
|
||||||
@ -269,11 +200,11 @@ pub fn perform_all_passes<'map>(
|
|||||||
let state = context.pass(&mut TypeCheck { refs: &refs })?;
|
let state = context.pass(&mut TypeCheck { refs: &refs })?;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:-^100}", "TYPECHECKER OUTPUT");
|
println!("{:-^100}", "TYPECHECKER OUTPUT");
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:#}", &context);
|
println!("{:#}", &context);
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:#?}", &state);
|
dbg!(&state);
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::from_kind(
|
return Err(ReidError::from_kind(
|
||||||
@ -302,17 +233,17 @@ pub fn compile_and_pass<'map>(
|
|||||||
let path = path.canonicalize().unwrap();
|
let path = path.canonicalize().unwrap();
|
||||||
let name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
let name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
||||||
|
|
||||||
let (id, tokens) = parse_module(source, name, Some(path.clone()), module_map, None)?;
|
let (id, tokens) = parse_module(source, name, module_map)?;
|
||||||
let module = compile_module(id, tokens, module_map, Some(path.clone()), true)?.map_err(|(_, e)| e)?;
|
let module = compile_module(id, tokens, module_map, Some(path.clone()), true)?;
|
||||||
|
|
||||||
let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned());
|
let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned());
|
||||||
|
|
||||||
perform_all_passes(&mut mir_context, module_map)?;
|
perform_all_passes(&mut mir_context, module_map)?;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:-^100}", "FINAL OUTPUT");
|
println!("{:-^100}", "FINAL OUTPUT");
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{:#}", &mir_context);
|
println!("{:#}", &mir_context);
|
||||||
|
|
||||||
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
|
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
|
||||||
let codegen_modules = match mir_context.codegen(&mut context) {
|
let codegen_modules = match mir_context.codegen(&mut context) {
|
||||||
@ -321,7 +252,7 @@ pub fn compile_and_pass<'map>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("{}", &codegen_modules.context);
|
println!("{}", &codegen_modules.context);
|
||||||
|
|
||||||
let compiled = codegen_modules.compile(cpu, features);
|
let compiled = codegen_modules.compile(cpu, features);
|
||||||
Ok((
|
Ok((
|
||||||
|
|||||||
149
reid/src/main.rs
149
reid/src/main.rs
@ -1,149 +0,0 @@
|
|||||||
use std::{fs, path::PathBuf, process};
|
|
||||||
|
|
||||||
use argh::FromArgs;
|
|
||||||
use log::*;
|
|
||||||
use reid::{
|
|
||||||
compile_simple,
|
|
||||||
ld::{execute, LDRunner},
|
|
||||||
CustomIRs,
|
|
||||||
};
|
|
||||||
use reid_lib::compile::CompileOutput;
|
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
|
||||||
/// Compile or run a Reid (.reid) file
|
|
||||||
#[argh(help_triggers("-h", "--help", "help"))]
|
|
||||||
struct Options {
|
|
||||||
#[argh(option, short = 'l', default = "log::Level::Info")]
|
|
||||||
/// log level
|
|
||||||
log_level: log::Level,
|
|
||||||
#[argh(switch, short = 't')]
|
|
||||||
/// should logs be timestamped
|
|
||||||
timestamps: bool,
|
|
||||||
#[argh(subcommand)]
|
|
||||||
command: Command,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
|
||||||
#[argh(subcommand)]
|
|
||||||
enum Command {
|
|
||||||
Build(BuildOpts),
|
|
||||||
Run(RunOpts),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
|
||||||
/// Build an executable file without running it
|
|
||||||
#[argh(subcommand, name = "build")]
|
|
||||||
struct BuildOpts {
|
|
||||||
#[argh(option, long = "lib", short = 'l')]
|
|
||||||
/// additional libraries to link against (with ld)
|
|
||||||
libraries: Vec<String>,
|
|
||||||
#[argh(positional)]
|
|
||||||
path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
|
||||||
/// Build and then execute the executable
|
|
||||||
#[argh(subcommand, name = "run")]
|
|
||||||
struct RunOpts {
|
|
||||||
#[argh(option, long = "lib", short = 'l')]
|
|
||||||
/// additional libraries to link against (with ld)
|
|
||||||
libraries: Vec<String>,
|
|
||||||
#[argh(positional)]
|
|
||||||
path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let options: Options = argh::from_env();
|
|
||||||
let mut errlog = stderrlog::new();
|
|
||||||
errlog.module(module_path!()).verbosity(options.log_level);
|
|
||||||
if options.timestamps {
|
|
||||||
errlog.timestamp(stderrlog::Timestamp::Second);
|
|
||||||
}
|
|
||||||
errlog.init().unwrap();
|
|
||||||
|
|
||||||
match &options.command {
|
|
||||||
Command::Build(BuildOpts { libraries, path }) | Command::Run(RunOpts { libraries, path }) => {
|
|
||||||
let cpu = std::env::var("CPU").unwrap_or("generic".to_owned());
|
|
||||||
let features = std::env::var("REIDFLAGS").unwrap_or("".to_owned());
|
|
||||||
|
|
||||||
let path = match path.canonicalize() {
|
|
||||||
Ok(path) => path,
|
|
||||||
Err(e) => {
|
|
||||||
error!("{e}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let parent = path.with_extension("");
|
|
||||||
let llvm_ir_path = parent.with_extension("ll");
|
|
||||||
let object_path = parent.with_extension("o");
|
|
||||||
let llir_path = parent.with_extension("llir");
|
|
||||||
let mir_path = parent.with_extension("mir");
|
|
||||||
let asm_path = parent.with_extension("asm");
|
|
||||||
let out_path = object_path.with_extension("out");
|
|
||||||
|
|
||||||
let before = std::time::SystemTime::now();
|
|
||||||
|
|
||||||
let text = match fs::read_to_string(&path) {
|
|
||||||
Ok(text) => text,
|
|
||||||
Err(e) => {
|
|
||||||
error!("Could not read file: {e}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match compile_simple(&text, PathBuf::from(&path), Some(cpu), vec![features]) {
|
|
||||||
Ok((
|
|
||||||
CompileOutput {
|
|
||||||
triple: _triple,
|
|
||||||
assembly,
|
|
||||||
obj_buffer,
|
|
||||||
llvm_ir: _llvm_ir,
|
|
||||||
},
|
|
||||||
CustomIRs { llir, mir },
|
|
||||||
)) => {
|
|
||||||
log::trace!("{}", _llvm_ir);
|
|
||||||
log::debug!("Compiled with triple: {}\n", &_triple);
|
|
||||||
log::debug!("Output LLVM IR to {:?}", llvm_ir_path);
|
|
||||||
log::debug!("Output Assembly to {:?}", asm_path);
|
|
||||||
log::debug!("Output Object-file to {:?}\n", object_path);
|
|
||||||
log::debug!("Output LLIR-file to {:?}\n", llir_path);
|
|
||||||
log::debug!("Output MIR-file to {:?}\n", mir_path);
|
|
||||||
|
|
||||||
fs::write(&llvm_ir_path, &_llvm_ir).expect("Could not write LLVM IR -file!");
|
|
||||||
fs::write(&asm_path, &assembly).expect("Could not write Assembly-file!");
|
|
||||||
fs::write(&object_path, &obj_buffer).expect("Could not write Object-file!");
|
|
||||||
fs::write(&llir_path, &llir).expect("Could not write LLIR-file!");
|
|
||||||
fs::write(&mir_path, &mir).expect("Could not write MIR-file!");
|
|
||||||
let after = std::time::SystemTime::now();
|
|
||||||
log::info!(
|
|
||||||
"Compilation took: {:.2}ms\n",
|
|
||||||
(after.duration_since(before).unwrap().as_micros() as f32) / 1000.
|
|
||||||
);
|
|
||||||
|
|
||||||
log::info!("Linking {:?}", &object_path);
|
|
||||||
|
|
||||||
let linker = std::env::var("LD").unwrap_or("ld".to_owned());
|
|
||||||
let mut linker = LDRunner::from_command(&linker).with_library("c").with_library("m");
|
|
||||||
for library in libraries {
|
|
||||||
linker = linker.with_library(&library);
|
|
||||||
}
|
|
||||||
linker.invoke(&object_path, &out_path);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{e}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match &options.command {
|
|
||||||
Command::Build(_) => {}
|
|
||||||
Command::Run(_) => {
|
|
||||||
if let Some(code) = execute(&out_path) {
|
|
||||||
process::exit(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -49,9 +49,6 @@ impl Display for Module {
|
|||||||
for typedef in &self.typedefs {
|
for typedef in &self.typedefs {
|
||||||
writeln!(inner_f, "{}", typedef)?;
|
writeln!(inner_f, "{}", typedef)?;
|
||||||
}
|
}
|
||||||
for global in &self.globals {
|
|
||||||
writeln!(inner_f, "global {} = {}", global.name, global.kind)?;
|
|
||||||
}
|
|
||||||
for (ty, fun) in &self.associated_functions {
|
for (ty, fun) in &self.associated_functions {
|
||||||
writeln!(inner_f, "(Assoc {}) {}", ty, fun)?;
|
writeln!(inner_f, "(Assoc {}) {}", ty, fun)?;
|
||||||
}
|
}
|
||||||
@ -62,33 +59,9 @@ impl Display for Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for GlobalKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
GlobalKind::Literal(literal) => Display::fmt(literal, f),
|
|
||||||
GlobalKind::Array(global_kinds) => {
|
|
||||||
f.write_char('[')?;
|
|
||||||
let mut iter = global_kinds.iter();
|
|
||||||
if let Some(global) = iter.next() {
|
|
||||||
Display::fmt(global, f)?;
|
|
||||||
while let Some(global) = iter.next() {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
Display::fmt(global, f)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.write_char(']')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Import {
|
impl Display for Import {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(f, "import {}", self.0.join("::"))
|
||||||
f,
|
|
||||||
"import {}",
|
|
||||||
self.0.iter().map(|(s, _)| s.clone()).collect::<Vec<_>>().join("::")
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,11 +71,11 @@ impl Display for BinopDefinition {
|
|||||||
f,
|
f,
|
||||||
"{}impl binop ({}: {:#}) {} ({}: {:#}) -> {:#} ",
|
"{}impl binop ({}: {:#}) {} ({}: {:#}) -> {:#} ",
|
||||||
if self.exported { "exported " } else { "" },
|
if self.exported { "exported " } else { "" },
|
||||||
self.lhs.name,
|
self.lhs.0,
|
||||||
self.lhs.ty,
|
self.lhs.1,
|
||||||
self.op,
|
self.op,
|
||||||
self.rhs.name,
|
self.rhs.0,
|
||||||
self.rhs.ty,
|
self.rhs.1,
|
||||||
self.return_type
|
self.return_type
|
||||||
)?;
|
)?;
|
||||||
Display::fmt(&self.fn_kind, f)
|
Display::fmt(&self.fn_kind, f)
|
||||||
@ -117,7 +90,7 @@ impl Display for TypeDefinition {
|
|||||||
self.name,
|
self.name,
|
||||||
self.source_module,
|
self.source_module,
|
||||||
if let Some(mod_id) = self.importer {
|
if let Some(mod_id) = self.importer {
|
||||||
format!("; imported by {}", mod_id)
|
format!("; imported to {}", mod_id)
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
}
|
}
|
||||||
@ -152,9 +125,6 @@ impl Display for StructField {
|
|||||||
|
|
||||||
impl Display for FunctionDefinition {
|
impl Display for FunctionDefinition {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
if let Some(documentation) = &self.documentation {
|
|
||||||
writeln!(f, "/// {}", documentation)?;
|
|
||||||
}
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}fn {}({}) -> {:#} ",
|
"{}fn {}({}) -> {:#} ",
|
||||||
@ -162,7 +132,7 @@ impl Display for FunctionDefinition {
|
|||||||
self.name,
|
self.name,
|
||||||
self.parameters
|
self.parameters
|
||||||
.iter()
|
.iter()
|
||||||
.map(|FunctionParam { name, ty, .. }| format!("{}: {:#}", name, ty))
|
.map(|(n, t)| format!("{}: {:#}", n, t))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", "),
|
.join(", "),
|
||||||
self.return_type
|
self.return_type
|
||||||
@ -279,16 +249,16 @@ impl Display for ExprKind {
|
|||||||
}
|
}
|
||||||
f.write_char(']')
|
f.write_char(']')
|
||||||
}
|
}
|
||||||
ExprKind::Struct(key, items) => {
|
ExprKind::Struct(name, items) => {
|
||||||
write!(f, "{:?} ", key)?;
|
write!(f, "{} ", name)?;
|
||||||
|
|
||||||
f.write_char('{')?;
|
f.write_char('{')?;
|
||||||
let mut state = Default::default();
|
let mut state = Default::default();
|
||||||
let mut inner_f = PadAdapter::wrap(f, &mut state);
|
let mut inner_f = PadAdapter::wrap(f, &mut state);
|
||||||
let mut iter = items.iter();
|
let mut iter = items.iter();
|
||||||
if let Some((name, expr, _)) = iter.next() {
|
if let Some((name, expr)) = iter.next() {
|
||||||
write!(inner_f, "\n{}: {}", name, expr)?;
|
write!(inner_f, "\n{}: {}", name, expr)?;
|
||||||
while let Some((name, expr, _)) = iter.next() {
|
while let Some((name, expr)) = iter.next() {
|
||||||
writeln!(inner_f, ",")?;
|
writeln!(inner_f, ",")?;
|
||||||
write!(inner_f, "{}: {}", name, expr)?;
|
write!(inner_f, "{}: {}", name, expr)?;
|
||||||
}
|
}
|
||||||
@ -296,7 +266,7 @@ impl Display for ExprKind {
|
|||||||
}
|
}
|
||||||
f.write_char('}')
|
f.write_char('}')
|
||||||
}
|
}
|
||||||
ExprKind::Accessed(expression, type_kind, name, _) => {
|
ExprKind::Accessed(expression, type_kind, name) => {
|
||||||
Display::fmt(&expression, f)?;
|
Display::fmt(&expression, f)?;
|
||||||
write_access(f, name)?;
|
write_access(f, name)?;
|
||||||
write!(f, "<{}>", type_kind)
|
write!(f, "<{}>", type_kind)
|
||||||
@ -310,7 +280,6 @@ impl Display for ExprKind {
|
|||||||
write!(f, "::")?;
|
write!(f, "::")?;
|
||||||
Display::fmt(function_call, f)
|
Display::fmt(function_call, f)
|
||||||
}
|
}
|
||||||
ExprKind::GlobalRef(global_value, type_kind) => write!(f, "global<{}>(${})", type_kind, global_value),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -471,7 +440,7 @@ impl Display for TypeKind {
|
|||||||
}
|
}
|
||||||
TypeKind::Vague(vague_type) => Display::fmt(vague_type, f),
|
TypeKind::Vague(vague_type) => Display::fmt(vague_type, f),
|
||||||
TypeKind::F16 => write!(f, "f16"),
|
TypeKind::F16 => write!(f, "f16"),
|
||||||
TypeKind::F16B => write!(f, "f16b"),
|
TypeKind::F32B => write!(f, "f16b"),
|
||||||
TypeKind::F32 => write!(f, "f32"),
|
TypeKind::F32 => write!(f, "f32"),
|
||||||
TypeKind::F64 => write!(f, "f64"),
|
TypeKind::F64 => write!(f, "f64"),
|
||||||
TypeKind::F128 => write!(f, "f128"),
|
TypeKind::F128 => write!(f, "f128"),
|
||||||
|
|||||||
@ -48,7 +48,7 @@ impl TypeKind {
|
|||||||
TypeKind::Borrow(..) => false,
|
TypeKind::Borrow(..) => false,
|
||||||
TypeKind::UserPtr(..) => false,
|
TypeKind::UserPtr(..) => false,
|
||||||
TypeKind::F16 => true,
|
TypeKind::F16 => true,
|
||||||
TypeKind::F16B => true,
|
TypeKind::F32B => true,
|
||||||
TypeKind::F32 => true,
|
TypeKind::F32 => true,
|
||||||
TypeKind::F64 => true,
|
TypeKind::F64 => true,
|
||||||
TypeKind::F128 => true,
|
TypeKind::F128 => true,
|
||||||
@ -57,7 +57,7 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size_of(&self, map: &HashMap<CustomTypeKey, TypeDefinition>) -> u64 {
|
pub fn size_of(&self) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
TypeKind::Bool => 1,
|
TypeKind::Bool => 1,
|
||||||
TypeKind::I8 => 8,
|
TypeKind::I8 => 8,
|
||||||
@ -72,27 +72,14 @@ impl TypeKind {
|
|||||||
TypeKind::U128 => 128,
|
TypeKind::U128 => 128,
|
||||||
TypeKind::Void => 0,
|
TypeKind::Void => 0,
|
||||||
TypeKind::Char => 8,
|
TypeKind::Char => 8,
|
||||||
TypeKind::Array(type_kind, len) => type_kind.size_of(map) * (*len as u64),
|
TypeKind::Array(type_kind, len) => type_kind.size_of() * (*len as u64),
|
||||||
TypeKind::CustomType(key) => match &map.get(key) {
|
TypeKind::CustomType(..) => 32,
|
||||||
Some(def) => match &def.kind {
|
|
||||||
TypeDefinitionKind::Struct(struct_type) => {
|
|
||||||
let mut size = 0;
|
|
||||||
for field in &struct_type.0 {
|
|
||||||
size += field.1.size_of(map)
|
|
||||||
}
|
|
||||||
size
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Easy to recognize default number. Used e.g. when sorting
|
|
||||||
// types by size
|
|
||||||
None => 404,
|
|
||||||
},
|
|
||||||
TypeKind::CodegenPtr(_) => 64,
|
TypeKind::CodegenPtr(_) => 64,
|
||||||
TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
|
TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
|
||||||
TypeKind::Borrow(..) => 64,
|
TypeKind::Borrow(..) => 64,
|
||||||
TypeKind::UserPtr(_) => 64,
|
TypeKind::UserPtr(_) => 64,
|
||||||
TypeKind::F16 => 16,
|
TypeKind::F16 => 16,
|
||||||
TypeKind::F16B => 16,
|
TypeKind::F32B => 16,
|
||||||
TypeKind::F32 => 32,
|
TypeKind::F32 => 32,
|
||||||
TypeKind::F64 => 64,
|
TypeKind::F64 => 64,
|
||||||
TypeKind::F128 => 128,
|
TypeKind::F128 => 128,
|
||||||
@ -123,7 +110,7 @@ impl TypeKind {
|
|||||||
TypeKind::Borrow(_, _) => 64,
|
TypeKind::Borrow(_, _) => 64,
|
||||||
TypeKind::UserPtr(_) => 64,
|
TypeKind::UserPtr(_) => 64,
|
||||||
TypeKind::F16 => 16,
|
TypeKind::F16 => 16,
|
||||||
TypeKind::F16B => 16,
|
TypeKind::F32B => 16,
|
||||||
TypeKind::F32 => 32,
|
TypeKind::F32 => 32,
|
||||||
TypeKind::F64 => 64,
|
TypeKind::F64 => 64,
|
||||||
TypeKind::F128 => 128,
|
TypeKind::F128 => 128,
|
||||||
@ -153,7 +140,7 @@ impl TypeKind {
|
|||||||
| TypeKind::U128
|
| TypeKind::U128
|
||||||
| TypeKind::Char => TypeCategory::Integer,
|
| TypeKind::Char => TypeCategory::Integer,
|
||||||
TypeKind::F16
|
TypeKind::F16
|
||||||
| TypeKind::F16B
|
| TypeKind::F32B
|
||||||
| TypeKind::F32
|
| TypeKind::F32
|
||||||
| TypeKind::F64
|
| TypeKind::F64
|
||||||
| TypeKind::F128
|
| TypeKind::F128
|
||||||
@ -202,36 +189,6 @@ impl TypeKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for TypeKind {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
use std::cmp::*;
|
|
||||||
|
|
||||||
let category_ord = self.category().partial_cmp(&other.category());
|
|
||||||
|
|
||||||
match category_ord {
|
|
||||||
Some(Ordering::Equal) | None => {
|
|
||||||
if !self.signed() && other.signed() {
|
|
||||||
return Ordering::Less;
|
|
||||||
}
|
|
||||||
if self.signed() && !other.signed() {
|
|
||||||
return Ordering::Greater;
|
|
||||||
}
|
|
||||||
|
|
||||||
let self_size = self.size_of(&HashMap::new());
|
|
||||||
let other_size = other.size_of(&HashMap::new());
|
|
||||||
if self_size == 32 && other_size != 32 {
|
|
||||||
return Ordering::Less;
|
|
||||||
} else if self_size != 32 && other_size == 32 {
|
|
||||||
return Ordering::Greater;
|
|
||||||
}
|
|
||||||
|
|
||||||
self_size.cmp(&self_size)
|
|
||||||
}
|
|
||||||
Some(ord) => ord,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BinaryOperator {
|
impl BinaryOperator {
|
||||||
pub fn is_commutative(&self) -> bool {
|
pub fn is_commutative(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
@ -259,28 +216,7 @@ impl BinaryOperator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TYPE_CATEGORY_ORDER: [TypeCategory; 5] = [
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
TypeCategory::Integer,
|
|
||||||
TypeCategory::Bool,
|
|
||||||
TypeCategory::Real,
|
|
||||||
TypeCategory::Other,
|
|
||||||
TypeCategory::TypeRef,
|
|
||||||
];
|
|
||||||
|
|
||||||
impl PartialOrd for TypeCategory {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
use std::cmp::*;
|
|
||||||
let self_idx = TYPE_CATEGORY_ORDER.iter().enumerate().find(|s| s.1 == self);
|
|
||||||
let other_idx = TYPE_CATEGORY_ORDER.iter().enumerate().find(|s| s.1 == other);
|
|
||||||
if let (Some(self_idx), Some(other_idx)) = (self_idx, other_idx) {
|
|
||||||
Some(self_idx.cmp(&other_idx))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Ord)]
|
|
||||||
pub enum TypeCategory {
|
pub enum TypeCategory {
|
||||||
Integer,
|
Integer,
|
||||||
Real,
|
Real,
|
||||||
@ -469,8 +405,11 @@ impl Expression {
|
|||||||
TypeKind::Array(Box::new(first.1), expressions.len() as u64),
|
TypeKind::Array(Box::new(first.1), expressions.len() as u64),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Accessed(_, type_kind, ..) => Ok((ReturnKind::Soft, type_kind.clone())),
|
Accessed(_, type_kind, _) => Ok((ReturnKind::Soft, type_kind.clone())),
|
||||||
Struct(key, _) => Ok((ReturnKind::Soft, TypeKind::CustomType(key.clone()))),
|
Struct(name, _) => Ok((
|
||||||
|
ReturnKind::Soft,
|
||||||
|
TypeKind::CustomType(CustomTypeKey(name.clone(), mod_id)),
|
||||||
|
)),
|
||||||
Borrow(expr, mutable) => {
|
Borrow(expr, mutable) => {
|
||||||
let ret_type = expr.return_type(refs, mod_id)?;
|
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)))
|
||||||
@ -490,7 +429,6 @@ impl Expression {
|
|||||||
Err(_) => Ok((ReturnKind::Soft, type_kind.clone())),
|
Err(_) => Ok((ReturnKind::Soft, type_kind.clone())),
|
||||||
},
|
},
|
||||||
AssociatedFunctionCall(_, fcall) => fcall.return_type(),
|
AssociatedFunctionCall(_, fcall) => fcall.return_type(),
|
||||||
GlobalRef(_, type_kind) => Ok((ReturnKind::Soft, type_kind.clone())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,7 +436,7 @@ impl Expression {
|
|||||||
match &self.0 {
|
match &self.0 {
|
||||||
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(expr, _) => expr.backing_var(),
|
ExprKind::Borrow(expr, _) => expr.backing_var(),
|
||||||
ExprKind::Deref(expr) => expr.backing_var(),
|
ExprKind::Deref(expr) => expr.backing_var(),
|
||||||
ExprKind::Block(block) => block.backing_var(),
|
ExprKind::Block(block) => block.backing_var(),
|
||||||
@ -510,7 +448,6 @@ impl Expression {
|
|||||||
ExprKind::If(_) => None,
|
ExprKind::If(_) => None,
|
||||||
ExprKind::CastTo(expression, _) => expression.backing_var(),
|
ExprKind::CastTo(expression, _) => expression.backing_var(),
|
||||||
ExprKind::AssociatedFunctionCall(..) => None,
|
ExprKind::AssociatedFunctionCall(..) => None,
|
||||||
ExprKind::GlobalRef(..) => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,7 +493,6 @@ impl Expression {
|
|||||||
ExprKind::Deref(_) => None,
|
ExprKind::Deref(_) => None,
|
||||||
ExprKind::CastTo(expression, _) => expression.num_value()?,
|
ExprKind::CastTo(expression, _) => expression.num_value()?,
|
||||||
ExprKind::AssociatedFunctionCall(..) => None,
|
ExprKind::AssociatedFunctionCall(..) => None,
|
||||||
ExprKind::GlobalRef(..) => None,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,8 @@ use crate::{
|
|||||||
compile_module,
|
compile_module,
|
||||||
error_raporting::{ErrorModules, ReidError},
|
error_raporting::{ErrorModules, ReidError},
|
||||||
mir::{
|
mir::{
|
||||||
pass::BinopKey, BinopDefinition, CustomTypeKey, FunctionDefinitionKind, SourceModuleId, StructType,
|
pass::BinopKey, BinopDefinition, CustomTypeKey, FunctionDefinitionKind, SourceModuleId, TypeDefinition,
|
||||||
TypeDefinition, TypeDefinitionKind, TypeKind,
|
TypeKind,
|
||||||
},
|
},
|
||||||
parse_module,
|
parse_module,
|
||||||
};
|
};
|
||||||
@ -46,19 +46,13 @@ pub enum ErrorKind {
|
|||||||
NoMainDefined,
|
NoMainDefined,
|
||||||
#[error("Main module has no main-function!")]
|
#[error("Main module has no main-function!")]
|
||||||
NoMainFunction,
|
NoMainFunction,
|
||||||
#[error("Type {0} has cyclical fields!")]
|
|
||||||
CyclicalType(String),
|
|
||||||
#[error("Type {0} is imported cyclically!")]
|
|
||||||
RecursiveTypeImport(String),
|
|
||||||
#[error("Type {} does not exist in module {}", 0.0, 0.1)]
|
|
||||||
NoSuchTypeInModule(CustomTypeKey),
|
|
||||||
#[error("Function {1} in module {0} is private!")]
|
#[error("Function {1} in module {0} is private!")]
|
||||||
FunctionIsPrivate(String, String),
|
FunctionIsPrivate(String, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_std(module_map: &mut ErrorModules) -> Result<Module, ReidError> {
|
pub fn compile_std(module_map: &mut ErrorModules) -> Result<Module, ReidError> {
|
||||||
let (id, tokens) = parse_module(STD_SOURCE, STD_NAME, None, module_map, None)?;
|
let (id, tokens) = parse_module(STD_SOURCE, STD_NAME, module_map)?;
|
||||||
let module = compile_module(id, tokens, module_map, None, false)?.map_err(|(_, e)| e)?;
|
let module = compile_module(id, tokens, module_map, None, false)?;
|
||||||
|
|
||||||
let module_id = module.module_id;
|
let module_id = module.module_id;
|
||||||
let mut mir_context = super::Context::from(vec![module], Default::default());
|
let mut mir_context = super::Context::from(vec![module], Default::default());
|
||||||
@ -76,21 +70,11 @@ pub struct LinkerPass<'map> {
|
|||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct LinkerState {
|
pub struct LinkerState {
|
||||||
foreign_types: HashMap<SourceModuleId, HashMap<CustomTypeKey, SourceModuleId>>,
|
extern_imported_types: HashMap<SourceModuleId, HashMap<String, SourceModuleId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, LinkerState, ErrorKind>;
|
type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, LinkerState, ErrorKind>;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct LinkerModule {
|
|
||||||
module: Rc<RefCell<Module>>,
|
|
||||||
// Functions imported directly from a module
|
|
||||||
function_imports: HashMap<String, (SourceModuleId, Metadata)>,
|
|
||||||
// Types imported either directly by the user or indirectly via functions.
|
|
||||||
// May contain type-imports that are again recursively imported elsewhere.
|
|
||||||
type_imports: HashMap<String, (SourceModuleId, Metadata)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'map> Pass for LinkerPass<'map> {
|
impl<'map> Pass for LinkerPass<'map> {
|
||||||
type Data = LinkerState;
|
type Data = LinkerState;
|
||||||
type TError = ErrorKind;
|
type TError = ErrorKind;
|
||||||
@ -118,56 +102,37 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut modules = HashMap::<SourceModuleId, LinkerModule>::new();
|
let mut modules = HashMap::<SourceModuleId, Rc<RefCell<_>>>::new();
|
||||||
let mut module_ids = HashMap::<String, SourceModuleId>::new();
|
let mut module_ids = HashMap::<String, SourceModuleId>::new();
|
||||||
|
|
||||||
for (mod_id, module) in context.modules.drain() {
|
for (mod_id, module) in context.modules.drain() {
|
||||||
modules.insert(
|
modules.insert(mod_id, Rc::new(RefCell::new(module)));
|
||||||
mod_id,
|
|
||||||
LinkerModule {
|
|
||||||
module: Rc::new(RefCell::new(module)),
|
|
||||||
function_imports: HashMap::new(),
|
|
||||||
type_imports: HashMap::new(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut module_queue: Vec<LinkerModule> = modules.values().cloned().collect();
|
let mut modules_to_process: Vec<Rc<RefCell<_>>> = modules.values().cloned().collect();
|
||||||
|
|
||||||
while let Some(mut importer) = module_queue.pop() {
|
let mut already_imported_types = HashSet::<CustomTypeKey>::new();
|
||||||
let importer_mod = importer.module.borrow_mut();
|
let mut already_imported_binops = HashSet::<BinopKey>::new();
|
||||||
|
|
||||||
// Gp go through all imports in this specific modulee
|
while let Some(module) = modules_to_process.pop() {
|
||||||
for import in importer_mod.imports.clone() {
|
let mut extern_types = HashMap::new();
|
||||||
|
let mut importer_module = module.borrow_mut();
|
||||||
|
|
||||||
|
for import in importer_module.imports.clone() {
|
||||||
let Import(path, _) = &import;
|
let Import(path, _) = &import;
|
||||||
if path.len() != 2 {
|
if path.len() != 2 {
|
||||||
state.ok::<_, Infallible>(Err(ErrorKind::InnerModulesNotYetSupported(import.clone())), import.1);
|
state.ok::<_, Infallible>(Err(ErrorKind::InnerModulesNotYetSupported(import.clone())), import.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cut the import statement into parts
|
let module_name = unsafe { path.get_unchecked(0) };
|
||||||
let Some((module_name, _)) = path.get(0) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let Some((import_name, _)) = path.get(1) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Actually compile or fetch the imported module
|
let mut imported = if let Some(mod_id) = module_ids.get(module_name) {
|
||||||
let imported = if let Some(mod_id) = module_ids.get(module_name) {
|
|
||||||
modules.get(mod_id).unwrap()
|
modules.get(mod_id).unwrap()
|
||||||
} else if module_name == STD_NAME {
|
} else if module_name == STD_NAME {
|
||||||
let std = compile_std(&mut self.module_map)?;
|
let std = compile_std(&mut self.module_map)?;
|
||||||
let module_id = std.module_id;
|
modules.insert(std.module_id, Rc::new(RefCell::new(compile_std(&mut self.module_map)?)));
|
||||||
modules.insert(
|
module_ids.insert(std.name, std.module_id);
|
||||||
std.module_id,
|
modules.get(&std.module_id).unwrap()
|
||||||
LinkerModule {
|
|
||||||
module: Rc::new(RefCell::new(std)),
|
|
||||||
function_imports: HashMap::new(),
|
|
||||||
type_imports: HashMap::new(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
module_ids.insert(module_name.clone(), module_id);
|
|
||||||
modules.get(&module_id).unwrap()
|
|
||||||
} else {
|
} else {
|
||||||
let file_path = PathBuf::from(&context.base.clone()).join(module_name.to_owned() + ".reid");
|
let file_path = PathBuf::from(&context.base.clone()).join(module_name.to_owned() + ".reid");
|
||||||
|
|
||||||
@ -176,13 +141,7 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let (id, tokens) = match parse_module(
|
let (id, tokens) = match parse_module(&source, module_name.clone(), &mut self.module_map) {
|
||||||
&source,
|
|
||||||
module_name.clone(),
|
|
||||||
Some(file_path.clone()),
|
|
||||||
&mut self.module_map,
|
|
||||||
None,
|
|
||||||
) {
|
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
@ -197,7 +156,6 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match compile_module(id, tokens, &mut self.module_map, Some(file_path), false) {
|
match compile_module(id, tokens, &mut self.module_map, Some(file_path), false) {
|
||||||
Ok(res) => match res {
|
|
||||||
Ok(imported_module) => {
|
Ok(imported_module) => {
|
||||||
if imported_module.is_main {
|
if imported_module.is_main {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
@ -208,29 +166,11 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
}
|
}
|
||||||
let module_id = imported_module.module_id;
|
let module_id = imported_module.module_id;
|
||||||
module_ids.insert(imported_module.name.clone(), imported_module.module_id);
|
module_ids.insert(imported_module.name.clone(), imported_module.module_id);
|
||||||
modules.insert(
|
modules.insert(module_id, Rc::new(RefCell::new(imported_module)));
|
||||||
module_id,
|
|
||||||
LinkerModule {
|
|
||||||
module: Rc::new(RefCell::new(imported_module)),
|
|
||||||
function_imports: HashMap::new(),
|
|
||||||
type_imports: HashMap::new(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let imported = modules.get_mut(&module_id).unwrap();
|
let imported = modules.get_mut(&module_id).unwrap();
|
||||||
module_queue.push(imported.clone());
|
modules_to_process.push(imported.clone());
|
||||||
imported
|
imported
|
||||||
}
|
}
|
||||||
Err((_, err)) => {
|
|
||||||
state.ok::<_, Infallible>(
|
|
||||||
Err(ErrorKind::ModuleCompilationError(
|
|
||||||
module_name.clone(),
|
|
||||||
format!("{}", err),
|
|
||||||
)),
|
|
||||||
import.1,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::ModuleCompilationError(
|
Err(ErrorKind::ModuleCompilationError(
|
||||||
@ -242,157 +182,70 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let imported_module = imported.module.borrow();
|
|
||||||
|
|
||||||
if let Some(func) = imported_module.functions.iter().find(|f| f.name == *import_name) {
|
|
||||||
// If the imported item is a function, add it to the list of imported functions
|
|
||||||
importer
|
|
||||||
.function_imports
|
|
||||||
.insert(func.name.clone(), (imported_module.module_id, import.1));
|
|
||||||
} else if let Some(ty) = imported_module.typedefs.iter().find(|t| t.name == *import_name) {
|
|
||||||
// If the imported item is a type, add it to the list of imported types
|
|
||||||
// imported_types.insert((CustomTypeKey(ty.name.clone(), ty.source_module), true));
|
|
||||||
importer
|
|
||||||
.type_imports
|
|
||||||
.insert(ty.name.clone(), (imported_module.module_id, import.1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.borrow_mut();
|
||||||
|
|
||||||
let module_id = importer_mod.module_id;
|
let import_name = unsafe { path.get_unchecked(1) };
|
||||||
drop(importer_mod);
|
|
||||||
modules.insert(module_id, importer);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (_, linker_module) in &modules {
|
let mut imported_types = Vec::new();
|
||||||
let mut importer_module = linker_module.module.borrow_mut();
|
|
||||||
|
|
||||||
let mut unresolved_types = HashMap::new();
|
if let Some(func) = imported.functions.iter_mut().find(|f| f.name == *import_name) {
|
||||||
|
let func_name = func.name.clone();
|
||||||
|
|
||||||
// 1. Import functions and find all types that are dependencies of
|
if !func.is_pub {
|
||||||
// functions
|
|
||||||
for (name, (function_source, import_meta)) in &linker_module.function_imports {
|
|
||||||
let mut function_module = modules.get(&function_source).unwrap().module.borrow_mut();
|
|
||||||
let func_module_name = function_module.name.clone();
|
|
||||||
let func_module_id = function_module.module_id;
|
|
||||||
|
|
||||||
let function = function_module.functions.iter_mut().find(|f| f.name == *name).unwrap();
|
|
||||||
|
|
||||||
// If function is not pub, error
|
|
||||||
if !function.is_pub {
|
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::FunctionIsPrivate(func_module_name, function.name.clone())),
|
Err(ErrorKind::FunctionIsPrivate(module_name.clone(), func_name.clone())),
|
||||||
import_meta.clone(),
|
import.1,
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If function already exists, error
|
func.is_imported = true;
|
||||||
if let Some(existing) = importer_module.functions.iter().find(|f| f.name == *name) {
|
|
||||||
if let Err(e) = existing.equals_as_imported(&function) {
|
if let Some(existing) = importer_module.functions.iter().find(|f| f.name == *func_name) {
|
||||||
|
if let Err(e) = existing.equals_as_imported(func) {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::FunctionImportIssue(func_module_name, name.clone(), e)),
|
Err(ErrorKind::FunctionImportIssue(
|
||||||
import_meta.clone(),
|
module_name.clone(),
|
||||||
|
func_name.clone(),
|
||||||
|
e,
|
||||||
|
)),
|
||||||
|
import.1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function.is_imported = true;
|
let types = import_type(&func.return_type, false);
|
||||||
|
let return_type = func.return_type.clone();
|
||||||
|
imported_types.extend(types);
|
||||||
|
|
||||||
for ty in import_type(&function.return_type) {
|
let mut param_tys = Vec::new();
|
||||||
unresolved_types.insert(ty, (import_meta.clone(), true));
|
for (param_name, param_ty) in &func.parameters {
|
||||||
}
|
let types = import_type(¶m_ty, false);
|
||||||
for param in &function.parameters {
|
imported_types.extend(types);
|
||||||
for ty in import_type(¶m.ty) {
|
param_tys.push((param_name.clone(), param_ty.clone()));
|
||||||
unresolved_types.insert(ty, (import_meta.clone(), true));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
importer_module.functions.push(FunctionDefinition {
|
importer_module.functions.push(FunctionDefinition {
|
||||||
name: function.name.clone(),
|
name: func_name.clone(),
|
||||||
documentation: function.documentation.clone(),
|
|
||||||
linkage_name: None,
|
linkage_name: None,
|
||||||
is_pub: false,
|
is_pub: false,
|
||||||
is_imported: false,
|
is_imported: false,
|
||||||
return_type: function.return_type.clone(),
|
return_type,
|
||||||
parameters: function.parameters.clone(),
|
parameters: param_tys,
|
||||||
kind: super::FunctionDefinitionKind::Extern(true),
|
kind: super::FunctionDefinitionKind::Extern(true),
|
||||||
source: Some(func_module_id),
|
|
||||||
signature_meta: function.signature(),
|
|
||||||
});
|
});
|
||||||
}
|
} else if let Some(ty) = imported.typedefs.iter_mut().find(|f| f.name == *import_name) {
|
||||||
|
let external_key = CustomTypeKey(ty.name.clone(), ty.source_module);
|
||||||
|
let imported_ty = TypeKind::CustomType(external_key.clone());
|
||||||
|
imported_types.push((external_key, true));
|
||||||
|
|
||||||
// 2. Add all manually imported types to the list of types that need
|
|
||||||
// to be resolved and recursed
|
|
||||||
for (name, (source_module, meta)) in &linker_module.type_imports {
|
|
||||||
let imported_ty_key = CustomTypeKey(name.clone(), source_module.clone());
|
|
||||||
|
|
||||||
let imported_ty = TypeKind::CustomType(imported_ty_key.clone());
|
|
||||||
let imported = modules.get(&imported_ty_key.1).unwrap().module.borrow();
|
|
||||||
|
|
||||||
for (ty, func) in &imported.associated_functions {
|
|
||||||
if *ty != imported_ty {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ty in import_type(&func.return_type) {
|
|
||||||
if unresolved_types.contains_key(&ty) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
unresolved_types.insert(ty, (meta.clone(), true));
|
|
||||||
}
|
|
||||||
for param in &func.parameters {
|
|
||||||
for ty in import_type(¶m.ty) {
|
|
||||||
if unresolved_types.contains_key(&ty) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
unresolved_types.insert(ty, (meta.clone(), true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unresolved_types.insert(imported_ty_key.clone(), (meta.clone(), false));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Recurse these types to find their true sources, find their
|
|
||||||
// dependencies, and list them all. Store manually imported types
|
|
||||||
// in a separate mapping for later.
|
|
||||||
let mut imported_types = HashMap::new();
|
|
||||||
let mut foreign_keys = HashSet::new();
|
|
||||||
|
|
||||||
let mut already_imported_binops = HashSet::new();
|
|
||||||
|
|
||||||
for (ty, (meta, is_dependency)) in unresolved_types {
|
|
||||||
// First deal with manually imported types
|
|
||||||
if !is_dependency {
|
|
||||||
// Add them to the list of foreign types (types that are
|
|
||||||
// later replaced in-source by name)
|
|
||||||
let imported_ty_key = match resolve_type(&ty, &modules) {
|
|
||||||
Ok(ty) => {
|
|
||||||
foreign_keys.insert(CustomTypeKey(ty.0.clone(), importer_module.module_id));
|
|
||||||
ty
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
state.note_errors(&vec![e], meta);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
imported_types.insert(CustomTypeKey(ty.0.clone(), importer_module.module_id), ty.1);
|
|
||||||
|
|
||||||
let mut imported = modules.get(&imported_ty_key.1).unwrap().module.borrow_mut();
|
|
||||||
let imported_module_name = imported.name.clone();
|
|
||||||
let imported_module_id = imported.module_id.clone();
|
|
||||||
let imported_ty = TypeKind::CustomType(imported_ty_key);
|
|
||||||
|
|
||||||
// Add all binary operators that are defined for this type
|
|
||||||
for binop in &mut imported.binop_defs {
|
for binop in &mut imported.binop_defs {
|
||||||
if binop.lhs.ty != imported_ty && binop.rhs.ty != imported_ty {
|
if binop.lhs.1 != imported_ty && binop.rhs.1 != imported_ty {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let binop_key = BinopKey {
|
let binop_key = BinopKey {
|
||||||
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||||
operator: binop.op,
|
operator: binop.op,
|
||||||
};
|
};
|
||||||
if already_imported_binops.contains(&binop_key) {
|
if already_imported_binops.contains(&binop_key) {
|
||||||
@ -417,7 +270,6 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import all functions that are associated with this type
|
|
||||||
for (ty, func) in &mut imported.associated_functions {
|
for (ty, func) in &mut imported.associated_functions {
|
||||||
if *ty != imported_ty {
|
if *ty != imported_ty {
|
||||||
continue;
|
continue;
|
||||||
@ -427,11 +279,8 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
|
|
||||||
if !func.is_pub {
|
if !func.is_pub {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::FunctionIsPrivate(
|
Err(ErrorKind::FunctionIsPrivate(module_name.clone(), func_name.clone())),
|
||||||
imported_module_name.clone(),
|
import.1,
|
||||||
func_name.clone(),
|
|
||||||
)),
|
|
||||||
meta.clone(),
|
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -446,81 +295,115 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
if let Err(e) = existing.equals_as_imported(func) {
|
if let Err(e) = existing.equals_as_imported(func) {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::FunctionImportIssue(
|
Err(ErrorKind::FunctionImportIssue(
|
||||||
imported_module_name.clone(),
|
module_name.clone(),
|
||||||
func_name.clone(),
|
func_name.clone(),
|
||||||
e,
|
e,
|
||||||
)),
|
)),
|
||||||
meta.clone(),
|
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((
|
importer_module.associated_functions.push((
|
||||||
ty.clone(),
|
ty.clone(),
|
||||||
FunctionDefinition {
|
FunctionDefinition {
|
||||||
name: func_name.clone(),
|
name: func_name.clone(),
|
||||||
documentation: func.documentation.clone(),
|
|
||||||
linkage_name: Some(format!("{}::{}", ty, func_name)),
|
linkage_name: Some(format!("{}::{}", ty, func_name)),
|
||||||
is_pub: false,
|
is_pub: false,
|
||||||
is_imported: false,
|
is_imported: false,
|
||||||
return_type: func.return_type.clone(),
|
return_type,
|
||||||
parameters: func.parameters.clone(),
|
parameters: param_tys,
|
||||||
kind: super::FunctionDefinitionKind::Extern(true),
|
kind: super::FunctionDefinitionKind::Extern(true),
|
||||||
source: Some(imported_module_id),
|
|
||||||
signature_meta: func.signature_meta,
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
match resolve_types_recursively(&TypeKind::CustomType(ty.clone()), &modules, HashSet::new()) {
|
|
||||||
Ok(resolved) => {
|
|
||||||
imported_types.extend(resolved);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
state.note_errors(&vec![e], meta);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut typedef_keys = HashMap::new();
|
|
||||||
// 4. Import all listed types.
|
|
||||||
for (importer_typekey, imported_module_id) in &imported_types {
|
|
||||||
let importee_typekey = CustomTypeKey(importer_typekey.0.clone(), *imported_module_id);
|
|
||||||
if let Some(module_id) = typedef_keys.get(&importee_typekey) {
|
|
||||||
if *module_id != importer_module.module_id {
|
|
||||||
typedef_keys.insert(importee_typekey.clone(), importer_typekey.1);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
typedef_keys.insert(importee_typekey.clone(), importer_typekey.1);
|
state.ok::<_, Infallible>(
|
||||||
}
|
Err(ErrorKind::ImportDoesNotExist(module_name.clone(), import_name.clone())),
|
||||||
|
import.1,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (typedef_key, importer_module_id) in &typedef_keys {
|
let mut seen = HashSet::new();
|
||||||
let imported_ty_module = modules.get(&typedef_key.1).unwrap().module.borrow();
|
let mut current_extern_types = HashSet::new();
|
||||||
if let Some(typedef) = imported_ty_module
|
seen.extend(imported_types.clone().iter().map(|t| t.0.clone()));
|
||||||
.typedefs
|
current_extern_types.extend(imported_types.clone().iter().filter(|t| t.1).map(|t| t.0.clone()));
|
||||||
|
for extern_type in ¤t_extern_types {
|
||||||
|
extern_types.insert(extern_type.0.clone(), extern_type.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let imported_mod_id = imported.module_id;
|
||||||
|
let imported_mod_typedefs = &mut imported.typedefs;
|
||||||
|
|
||||||
|
for typekey in imported_types.clone() {
|
||||||
|
let typedef = imported_mod_typedefs
|
||||||
.iter()
|
.iter()
|
||||||
.find(|ty| CustomTypeKey(ty.name.clone(), ty.source_module) == *typedef_key)
|
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey.0)
|
||||||
|
.unwrap();
|
||||||
|
let inner = find_inner_types(typedef, seen.clone(), imported_mod_id);
|
||||||
|
seen.extend(inner.iter().cloned());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Unable to import same-named type from multiple places..
|
||||||
|
let seen = seen
|
||||||
|
.difference(&already_imported_types)
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
.collect::<HashSet<_>>();
|
||||||
importer_module.typedefs.push(TypeDefinition {
|
|
||||||
importer: Some(*importer_module_id),
|
already_imported_types.extend(seen.clone());
|
||||||
..typedef
|
|
||||||
});
|
for typekey in &already_imported_types {
|
||||||
|
if current_extern_types.contains(typekey) {
|
||||||
|
let module_id = importer_module.module_id;
|
||||||
|
let typedef = importer_module
|
||||||
|
.typedefs
|
||||||
|
.iter_mut()
|
||||||
|
.find(|t| t.name == typekey.0 && t.source_module == typekey.1);
|
||||||
|
if let Some(typedef) = typedef {
|
||||||
|
typedef.importer = Some(module_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for typekey in seen.into_iter() {
|
||||||
|
let mut typedef = imported_mod_typedefs
|
||||||
|
.iter()
|
||||||
|
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey)
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
if current_extern_types.contains(&typekey) {
|
||||||
|
typedef = TypeDefinition {
|
||||||
|
importer: Some(importer_module.module_id),
|
||||||
|
..typedef
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
importer_module.typedefs.push(typedef);
|
||||||
|
}
|
||||||
|
}
|
||||||
state
|
state
|
||||||
.scope
|
.scope
|
||||||
.data
|
.data
|
||||||
.foreign_types
|
.extern_imported_types
|
||||||
.insert(importer_module.module_id, imported_types);
|
.insert(importer_module.module_id, extern_types);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut modules: Vec<Module> = modules
|
let mut modules: Vec<Module> = modules
|
||||||
.into_values()
|
.into_values()
|
||||||
.map(|v| Rc::into_inner(v.module).unwrap().into_inner())
|
.map(|v| Rc::into_inner(v).unwrap().into_inner())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for module in modules.drain(..) {
|
for module in modules.drain(..) {
|
||||||
@ -530,33 +413,19 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn module(&mut self, module: &mut Module, state: PassState<Self::Data, Self::TError>) -> PassResult {
|
|
||||||
let foreign_types = &state.scope.data.foreign_types.get(&module.module_id);
|
|
||||||
if let Some(foreign_types) = foreign_types {
|
|
||||||
for ty in &mut module.typedefs {
|
|
||||||
match &mut ty.kind {
|
|
||||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
|
||||||
for field in fields {
|
|
||||||
field.1 = field.1.update_imported(foreign_types);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn function(
|
fn function(
|
||||||
&mut self,
|
&mut self,
|
||||||
function: &mut FunctionDefinition,
|
function: &mut FunctionDefinition,
|
||||||
state: PassState<Self::Data, Self::TError>,
|
state: PassState<Self::Data, Self::TError>,
|
||||||
) -> PassResult {
|
) -> PassResult {
|
||||||
|
if matches!(function.kind, FunctionDefinitionKind::Local(_, _)) {
|
||||||
let mod_id = state.scope.module_id.unwrap();
|
let mod_id = state.scope.module_id.unwrap();
|
||||||
let foreign_types = &state.scope.data.foreign_types.get(&mod_id);
|
let extern_types = &state.scope.data.extern_imported_types.get(&mod_id);
|
||||||
if let Some(foreign_types) = foreign_types {
|
if let Some(extern_types) = extern_types {
|
||||||
function.return_type = function.return_type.update_imported(*foreign_types);
|
function.return_type = function.return_type.update_imported(*extern_types, mod_id);
|
||||||
for param in function.parameters.iter_mut() {
|
for param in function.parameters.iter_mut() {
|
||||||
param.ty = param.ty.update_imported(foreign_types);
|
param.1 = param.1.update_imported(extern_types, mod_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -564,11 +433,11 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
|
|
||||||
fn stmt(&mut self, stmt: &mut super::Statement, state: PassState<Self::Data, Self::TError>) -> PassResult {
|
fn stmt(&mut self, stmt: &mut super::Statement, state: PassState<Self::Data, Self::TError>) -> PassResult {
|
||||||
let mod_id = state.scope.module_id.unwrap();
|
let mod_id = state.scope.module_id.unwrap();
|
||||||
let foreign_types = &state.scope.data.foreign_types.get(&mod_id);
|
let extern_types = &state.scope.data.extern_imported_types.get(&mod_id);
|
||||||
if let Some(foreign_types) = foreign_types {
|
if let Some(extern_types) = extern_types {
|
||||||
match &mut stmt.0 {
|
match &mut stmt.0 {
|
||||||
super::StmtKind::Let(var_ref, _, _) => {
|
super::StmtKind::Let(var_ref, _, _) => {
|
||||||
var_ref.0 = var_ref.0.update_imported(foreign_types);
|
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -578,29 +447,25 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
|
|
||||||
fn expr(&mut self, expr: &mut super::Expression, state: PassState<Self::Data, Self::TError>) -> PassResult {
|
fn expr(&mut self, expr: &mut super::Expression, state: PassState<Self::Data, Self::TError>) -> PassResult {
|
||||||
let mod_id = state.scope.module_id.unwrap();
|
let mod_id = state.scope.module_id.unwrap();
|
||||||
let foreign_types = &state.scope.data.foreign_types.get(&mod_id);
|
let extern_types = &state.scope.data.extern_imported_types.get(&mod_id);
|
||||||
if let Some(foreign_types) = foreign_types {
|
if let Some(extern_types) = extern_types {
|
||||||
match &mut expr.0 {
|
match &mut expr.0 {
|
||||||
super::ExprKind::Variable(var_ref) => {
|
super::ExprKind::Variable(var_ref) => {
|
||||||
var_ref.0 = var_ref.0.update_imported(foreign_types);
|
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
|
||||||
}
|
}
|
||||||
super::ExprKind::Indexed(.., type_kind, _) => *type_kind = type_kind.update_imported(foreign_types),
|
super::ExprKind::Indexed(.., type_kind, _) => {
|
||||||
super::ExprKind::Accessed(.., type_kind, _, _) => *type_kind = type_kind.update_imported(foreign_types),
|
*type_kind = type_kind.update_imported(extern_types, mod_id)
|
||||||
super::ExprKind::BinOp(.., type_kind) => *type_kind = type_kind.update_imported(foreign_types),
|
}
|
||||||
|
super::ExprKind::Accessed(.., 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(..) => {}
|
super::ExprKind::Borrow(..) => {}
|
||||||
super::ExprKind::Deref(..) => {}
|
super::ExprKind::Deref(..) => {}
|
||||||
super::ExprKind::CastTo(_, type_kind) => *type_kind = type_kind.update_imported(foreign_types),
|
super::ExprKind::CastTo(_, type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id),
|
||||||
super::ExprKind::AssociatedFunctionCall(type_kind, fn_call) => {
|
super::ExprKind::AssociatedFunctionCall(type_kind, _) => {
|
||||||
*type_kind = type_kind.update_imported(foreign_types);
|
*type_kind = type_kind.update_imported(extern_types, mod_id)
|
||||||
fn_call.return_type = fn_call.return_type.update_imported(foreign_types);
|
|
||||||
}
|
|
||||||
super::ExprKind::Struct(key, _) => {
|
|
||||||
*key = if let Some(mod_id) = foreign_types.get(&key) {
|
|
||||||
CustomTypeKey(key.0.clone(), *mod_id)
|
|
||||||
} else {
|
|
||||||
key.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -610,103 +475,78 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
fn update_imported(&self, foreign_types: &HashMap<CustomTypeKey, SourceModuleId>) -> TypeKind {
|
fn update_imported(
|
||||||
|
&self,
|
||||||
|
extern_types: &HashMap<String, SourceModuleId>,
|
||||||
|
importer_mod_id: SourceModuleId,
|
||||||
|
) -> TypeKind {
|
||||||
match &self {
|
match &self {
|
||||||
TypeKind::Array(type_kind, len) => {
|
TypeKind::Array(type_kind, len) => {
|
||||||
TypeKind::Array(Box::new(type_kind.update_imported(foreign_types)), *len)
|
TypeKind::Array(Box::new(type_kind.update_imported(extern_types, importer_mod_id)), *len)
|
||||||
}
|
}
|
||||||
TypeKind::CustomType(custom_type_key) => {
|
TypeKind::CustomType(custom_type_key) => {
|
||||||
if let Some(mod_id) = foreign_types.get(&custom_type_key) {
|
if let Some(mod_id) = extern_types.get(&custom_type_key.0) {
|
||||||
TypeKind::CustomType(CustomTypeKey(custom_type_key.0.clone(), *mod_id))
|
TypeKind::CustomType(CustomTypeKey(custom_type_key.0.clone(), *mod_id))
|
||||||
} else {
|
} else {
|
||||||
self.clone()
|
self.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeKind::Borrow(type_kind, mutable) => {
|
TypeKind::Borrow(type_kind, mutable) => TypeKind::Borrow(
|
||||||
TypeKind::Borrow(Box::new(type_kind.update_imported(foreign_types)), *mutable)
|
Box::new(type_kind.update_imported(extern_types, importer_mod_id)),
|
||||||
|
*mutable,
|
||||||
|
),
|
||||||
|
TypeKind::UserPtr(type_kind) => {
|
||||||
|
TypeKind::UserPtr(Box::new(type_kind.update_imported(extern_types, importer_mod_id)))
|
||||||
|
}
|
||||||
|
TypeKind::CodegenPtr(type_kind) => {
|
||||||
|
TypeKind::CodegenPtr(Box::new(type_kind.update_imported(extern_types, importer_mod_id)))
|
||||||
}
|
}
|
||||||
TypeKind::UserPtr(type_kind) => TypeKind::UserPtr(Box::new(type_kind.update_imported(foreign_types))),
|
|
||||||
TypeKind::CodegenPtr(type_kind) => TypeKind::CodegenPtr(Box::new(type_kind.update_imported(foreign_types))),
|
|
||||||
_ => self.clone(),
|
_ => self.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_type(ty: &TypeKind) -> Vec<CustomTypeKey> {
|
fn import_type(ty: &TypeKind, usable_import: bool) -> Vec<(CustomTypeKey, bool)> {
|
||||||
let mut imported_types = Vec::new();
|
let mut imported_types = Vec::new();
|
||||||
match &ty {
|
match &ty {
|
||||||
TypeKind::CustomType(key) => imported_types.push(key.clone()),
|
TypeKind::CustomType(key) => imported_types.push((key.clone(), usable_import)),
|
||||||
TypeKind::Borrow(ty, _) => imported_types.extend(import_type(ty)),
|
TypeKind::Borrow(ty, _) => imported_types.extend(import_type(ty, usable_import)),
|
||||||
TypeKind::Array(ty, _) => imported_types.extend(import_type(ty)),
|
TypeKind::Array(ty, _) => imported_types.extend(import_type(ty, usable_import)),
|
||||||
TypeKind::UserPtr(ty) => imported_types.extend(import_type(ty)),
|
TypeKind::UserPtr(ty) => imported_types.extend(import_type(ty, usable_import)),
|
||||||
TypeKind::CodegenPtr(ty) => imported_types.extend(import_type(ty)),
|
TypeKind::CodegenPtr(ty) => imported_types.extend(import_type(ty, usable_import)),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
imported_types
|
imported_types
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_type(
|
fn find_inner_types(
|
||||||
ty: &CustomTypeKey,
|
typedef: &TypeDefinition,
|
||||||
modules: &HashMap<SourceModuleId, LinkerModule>,
|
|
||||||
) -> Result<CustomTypeKey, ErrorKind> {
|
|
||||||
let mut source_module_id = ty.1;
|
|
||||||
let mut seen = HashSet::new();
|
|
||||||
loop {
|
|
||||||
seen.insert(source_module_id);
|
|
||||||
let source_module = modules.get(&source_module_id).unwrap();
|
|
||||||
if let Some((new_module_id, _)) = source_module.type_imports.get(&ty.0) {
|
|
||||||
if seen.contains(new_module_id) {
|
|
||||||
return Err(ErrorKind::RecursiveTypeImport(ty.0.clone()));
|
|
||||||
}
|
|
||||||
source_module_id = *new_module_id;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(CustomTypeKey(ty.0.clone(), source_module_id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_types_recursively(
|
|
||||||
ty: &TypeKind,
|
|
||||||
modules: &HashMap<SourceModuleId, LinkerModule>,
|
|
||||||
mut seen: HashSet<CustomTypeKey>,
|
mut seen: HashSet<CustomTypeKey>,
|
||||||
) -> Result<HashMap<CustomTypeKey, SourceModuleId>, ErrorKind> {
|
mod_id: SourceModuleId,
|
||||||
let mut types = HashMap::new();
|
) -> Vec<CustomTypeKey> {
|
||||||
match ty {
|
match &typedef.kind {
|
||||||
TypeKind::CustomType(type_key) => {
|
crate::mir::TypeDefinitionKind::Struct(struct_type) => {
|
||||||
let resolved_ty = resolve_type(type_key, modules)?;
|
let typenames = struct_type
|
||||||
|
.0
|
||||||
if seen.contains(&resolved_ty) {
|
|
||||||
return Err(ErrorKind::CyclicalType(type_key.0.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
types.insert(type_key.clone(), resolved_ty.1);
|
|
||||||
seen.insert(resolved_ty.clone());
|
|
||||||
|
|
||||||
let resolved = modules
|
|
||||||
.get(&resolved_ty.1)
|
|
||||||
.unwrap()
|
|
||||||
.module
|
|
||||||
.borrow()
|
|
||||||
.typedefs
|
|
||||||
.iter()
|
.iter()
|
||||||
.find(|t| t.name == resolved_ty.0)
|
.filter(|t| matches!(t.1, TypeKind::CustomType(..)))
|
||||||
.ok_or(ErrorKind::NoSuchTypeInModule(type_key.clone()))
|
.map(|t| match &t.1 {
|
||||||
.cloned()?;
|
TypeKind::CustomType(CustomTypeKey(t, _)) => t,
|
||||||
match resolved.kind {
|
_ => panic!(),
|
||||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
})
|
||||||
for field in fields {
|
.cloned()
|
||||||
types.extend(resolve_types_recursively(&field.1, modules, seen.clone())?);
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for typename in typenames {
|
||||||
|
if seen.contains(&CustomTypeKey(typename.clone(), mod_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let inner = find_inner_types(typedef, seen.clone(), mod_id);
|
||||||
|
seen.insert(CustomTypeKey(typename, mod_id));
|
||||||
|
seen.extend(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
seen.into_iter().collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeKind::Array(type_kind, _) => types.extend(resolve_types_recursively(&type_kind, modules, seen.clone())?),
|
|
||||||
TypeKind::Borrow(type_kind, _) => types.extend(resolve_types_recursively(&type_kind, modules, seen.clone())?),
|
|
||||||
TypeKind::UserPtr(type_kind) => types.extend(resolve_types_recursively(&type_kind, modules, seen.clone())?),
|
|
||||||
TypeKind::CodegenPtr(type_kind) => types.extend(resolve_types_recursively(&type_kind, modules, seen.clone())?),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
Ok(types)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,271 +0,0 @@
|
|||||||
use std::{collections::HashMap, path::PathBuf};
|
|
||||||
|
|
||||||
use crate::mir::{
|
|
||||||
self, FunctionCall, GlobalKind, GlobalValue, IfExpression, Literal, Module, SourceModuleId, TypeKind,
|
|
||||||
WhileStatement,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::pass::{Pass, PassResult, PassState};
|
|
||||||
|
|
||||||
pub trait MacroFunction: std::fmt::Debug {
|
|
||||||
fn generate<'ctx, 'a>(
|
|
||||||
&self,
|
|
||||||
module: &MacroModule,
|
|
||||||
params: &[mir::Literal],
|
|
||||||
prefix: String,
|
|
||||||
) -> Result<(Vec<GlobalValue>, mir::ExprKind), ErrorKind>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub enum ErrorKind {
|
|
||||||
#[error("Should never be encountered!")]
|
|
||||||
Null,
|
|
||||||
#[error("No such macro {0} defined")]
|
|
||||||
NoSuchMacro(String),
|
|
||||||
#[error("Macro arguments may only be literals")]
|
|
||||||
InvalidMacroArgs,
|
|
||||||
#[error("Got {0} parameters, expected {1}")]
|
|
||||||
InvalidAmountOfParams(u32, u32),
|
|
||||||
#[error("Expected argument type of {0}, got {1}")]
|
|
||||||
InvalidArgumentType(TypeKind, TypeKind),
|
|
||||||
#[error("Error executing macro: {0}")]
|
|
||||||
MacroExecutionError(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
type MacroModuleMap = HashMap<SourceModuleId, MacroModule>;
|
|
||||||
|
|
||||||
/// Struct used to implement a type-checking pass that can be performed on the
|
|
||||||
/// MIR.
|
|
||||||
pub struct MacroPass {
|
|
||||||
pub(crate) macros: HashMap<String, Box<dyn MacroFunction>>,
|
|
||||||
pub module_map: MacroModuleMap,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MacroModule {
|
|
||||||
path: Option<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Module> for MacroModule {
|
|
||||||
fn from(value: &Module) -> Self {
|
|
||||||
MacroModule {
|
|
||||||
path: value.path.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type MacroPassState<'map, 'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
|
|
||||||
|
|
||||||
impl Pass for MacroPass {
|
|
||||||
type Data = ();
|
|
||||||
type TError = ErrorKind;
|
|
||||||
|
|
||||||
fn context(&mut self, _context: &mut mir::Context, mut _state: PassState<Self::Data, Self::TError>) -> PassResult {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn module(&mut self, module: &mut mir::Module, mut state: PassState<Self::Data, Self::TError>) -> PassResult {
|
|
||||||
for function in &mut module.functions {
|
|
||||||
let globals = match &mut function.kind {
|
|
||||||
mir::FunctionDefinitionKind::Local(block, _) => block.gen_macros(self, &mut state, &self.module_map),
|
|
||||||
_ => Vec::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
module.globals.extend(globals);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mir::Block {
|
|
||||||
fn gen_macros(&mut self, data: &MacroPass, state: &mut MacroPassState, map: &MacroModuleMap) -> Vec<GlobalValue> {
|
|
||||||
let mut globals = Vec::new();
|
|
||||||
for statement in &mut self.statements {
|
|
||||||
globals.extend(statement.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
if let Some((_, Some(return_expr))) = &mut self.return_expression {
|
|
||||||
globals.extend(return_expr.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
globals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mir::Statement {
|
|
||||||
fn gen_macros(&mut self, data: &MacroPass, state: &mut MacroPassState, map: &MacroModuleMap) -> Vec<GlobalValue> {
|
|
||||||
let mut globals = Vec::new();
|
|
||||||
match &mut self.0 {
|
|
||||||
mir::StmtKind::Let(.., expr) => {
|
|
||||||
globals.extend(expr.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
mir::StmtKind::Set(lhs, rhs) => {
|
|
||||||
globals.extend(lhs.gen_macros(data, state, map));
|
|
||||||
globals.extend(rhs.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
mir::StmtKind::Import(_) => {}
|
|
||||||
mir::StmtKind::Expression(expr) => {
|
|
||||||
globals.extend(expr.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
|
|
||||||
globals.extend(condition.gen_macros(data, state, map));
|
|
||||||
globals.extend(block.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
globals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mir::Expression {
|
|
||||||
fn gen_macros(&mut self, data: &MacroPass, state: &mut MacroPassState, map: &MacroModuleMap) -> Vec<GlobalValue> {
|
|
||||||
let mut globals = Vec::new();
|
|
||||||
match &mut self.0 {
|
|
||||||
mir::ExprKind::FunctionCall(function_call) => {
|
|
||||||
for param in &mut function_call.parameters {
|
|
||||||
globals.extend(param.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
if function_call.is_macro {
|
|
||||||
if let Some(existing_macro) = data.macros.get(&function_call.name) {
|
|
||||||
let mut literals = Vec::new();
|
|
||||||
for param in &mut function_call.parameters {
|
|
||||||
match ¶m.0 {
|
|
||||||
super::ExprKind::Literal(literal) => literals.push(literal.clone()),
|
|
||||||
_ => state.note_errors(&vec![ErrorKind::InvalidMacroArgs], param.1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let (generated_globals, expr) = state.or_else(
|
|
||||||
existing_macro
|
|
||||||
.generate(
|
|
||||||
map.get(&state.scope.module_id.unwrap()).unwrap(),
|
|
||||||
&literals,
|
|
||||||
format!(
|
|
||||||
"macro.{}.{}.{}",
|
|
||||||
function_call.name, self.1.range.start, self.1.range.end
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map(|(globals, kind)| (globals, mir::Expression(kind, self.1))),
|
|
||||||
(Vec::new(), self.clone()),
|
|
||||||
self.1,
|
|
||||||
);
|
|
||||||
globals.extend(generated_globals);
|
|
||||||
*self = expr;
|
|
||||||
} else {
|
|
||||||
state.note_errors(
|
|
||||||
&vec![ErrorKind::NoSuchMacro(function_call.name.clone())],
|
|
||||||
function_call.meta,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mir::ExprKind::Variable(_) => {}
|
|
||||||
mir::ExprKind::Indexed(expression, _, expression1) => {
|
|
||||||
globals.extend(expression.gen_macros(data, state, map));
|
|
||||||
globals.extend(expression1.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
mir::ExprKind::Accessed(expression, ..) => {
|
|
||||||
globals.extend(expression.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
mir::ExprKind::Array(expressions) => {
|
|
||||||
for expression in expressions {
|
|
||||||
globals.extend(expression.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mir::ExprKind::Struct(_, items) => {
|
|
||||||
for item in items {
|
|
||||||
globals.extend(item.1.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mir::ExprKind::Literal(_) => {}
|
|
||||||
mir::ExprKind::BinOp(_, expression, expression1, _) => {
|
|
||||||
globals.extend(expression.gen_macros(data, state, map));
|
|
||||||
globals.extend(expression1.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
mir::ExprKind::AssociatedFunctionCall(_, FunctionCall { parameters, .. }) => {
|
|
||||||
for expression in parameters {
|
|
||||||
globals.extend(expression.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mir::ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
|
||||||
globals.extend(cond.gen_macros(data, state, map));
|
|
||||||
globals.extend(lhs.gen_macros(data, state, map));
|
|
||||||
if let Some(rhs) = rhs.as_mut() {
|
|
||||||
globals.extend(rhs.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mir::ExprKind::Block(block) => {
|
|
||||||
globals.extend(block.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
mir::ExprKind::Borrow(expression, _) => {
|
|
||||||
globals.extend(expression.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
mir::ExprKind::Deref(expression) => {
|
|
||||||
globals.extend(expression.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
mir::ExprKind::CastTo(expression, _) => {
|
|
||||||
globals.extend(expression.gen_macros(data, state, map));
|
|
||||||
}
|
|
||||||
mir::ExprKind::GlobalRef(..) => {}
|
|
||||||
}
|
|
||||||
globals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn form_macros() -> HashMap<String, Box<dyn MacroFunction>> {
|
|
||||||
let mut macros: HashMap<String, Box<dyn MacroFunction>> = HashMap::new();
|
|
||||||
|
|
||||||
macros.insert("include_bytes".to_owned(), Box::new(IncludeBytes));
|
|
||||||
|
|
||||||
macros
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct IncludeBytes;
|
|
||||||
impl MacroFunction for IncludeBytes {
|
|
||||||
fn generate<'ctx, 'a>(
|
|
||||||
&self,
|
|
||||||
module: &MacroModule,
|
|
||||||
literals: &[mir::Literal],
|
|
||||||
global_name: String,
|
|
||||||
) -> Result<(Vec<GlobalValue>, mir::ExprKind), ErrorKind> {
|
|
||||||
if literals.len() != 1 {
|
|
||||||
return Err(ErrorKind::InvalidAmountOfParams(literals.len() as u32, 1));
|
|
||||||
}
|
|
||||||
let literal = literals.get(0).unwrap();
|
|
||||||
let Literal::String(path) = literal else {
|
|
||||||
return Err(ErrorKind::InvalidArgumentType(
|
|
||||||
literal.as_type(),
|
|
||||||
TypeKind::UserPtr(Box::new(TypeKind::Char)),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
let path = module
|
|
||||||
.path
|
|
||||||
.as_ref()
|
|
||||||
.expect("Module has no path!")
|
|
||||||
.parent()
|
|
||||||
.expect("Module path has no parent!")
|
|
||||||
.join(path);
|
|
||||||
|
|
||||||
let contents = match std::fs::read(path) {
|
|
||||||
Ok(content) => content,
|
|
||||||
Err(e) => return Err(ErrorKind::MacroExecutionError(format!("{}", e))),
|
|
||||||
};
|
|
||||||
|
|
||||||
let literals = contents
|
|
||||||
.iter()
|
|
||||||
.map(|c| GlobalKind::Literal(Literal::U8(*c)))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let len = literals.len();
|
|
||||||
|
|
||||||
let global = GlobalValue {
|
|
||||||
name: global_name.clone(),
|
|
||||||
kind: GlobalKind::Array(literals),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
vec![global.clone()],
|
|
||||||
mir::ExprKind::GlobalRef(
|
|
||||||
global_name,
|
|
||||||
TypeKind::Borrow(Box::new(TypeKind::Array(Box::new(TypeKind::U8), len as u64)), false),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -13,7 +13,6 @@ use crate::{
|
|||||||
mod fmt;
|
mod fmt;
|
||||||
pub mod implement;
|
pub mod implement;
|
||||||
pub mod linker;
|
pub mod linker;
|
||||||
pub mod macros;
|
|
||||||
pub mod pass;
|
pub mod pass;
|
||||||
pub mod typecheck;
|
pub mod typecheck;
|
||||||
|
|
||||||
@ -41,40 +40,15 @@ impl Metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_positions(&self, tokens: &Vec<FullToken>) -> Option<(Position, Position)> {
|
pub fn into_positions(&self, tokens: &Vec<FullToken>) -> Option<(Position, Position)> {
|
||||||
self.range.into_position(tokens)
|
let mut iter = tokens
|
||||||
}
|
.iter()
|
||||||
|
.skip(self.range.start)
|
||||||
pub fn is_after(&self, token_idx: usize) -> bool {
|
.take(self.range.end - self.range.start);
|
||||||
return token_idx < self.range.start;
|
if let Some(first) = iter.next() {
|
||||||
}
|
let last = iter.last().unwrap_or(first);
|
||||||
|
Some((first.position, last.position.add(last.token.len() as u32)))
|
||||||
pub fn is_before(&self, token_idx: usize) -> bool {
|
} else {
|
||||||
return token_idx > self.range.end;
|
None
|
||||||
}
|
|
||||||
|
|
||||||
pub fn contains(&self, token_idx: usize) -> bool {
|
|
||||||
return token_idx >= self.range.start && token_idx <= self.range.end;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn after(&self, cutoff: usize) -> Metadata {
|
|
||||||
Metadata {
|
|
||||||
source_module_id: self.source_module_id,
|
|
||||||
range: TokenRange {
|
|
||||||
start: cutoff.max(self.range.start),
|
|
||||||
end: cutoff.max(self.range.end),
|
|
||||||
},
|
|
||||||
position: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn before(&self, cutoff: usize) -> Metadata {
|
|
||||||
Metadata {
|
|
||||||
source_module_id: self.source_module_id,
|
|
||||||
range: TokenRange {
|
|
||||||
start: cutoff.min(self.range.start),
|
|
||||||
end: cutoff.min(self.range.end),
|
|
||||||
},
|
|
||||||
position: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,7 +79,7 @@ impl TokenRange {
|
|||||||
#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
pub struct CustomTypeKey(pub String, pub SourceModuleId);
|
pub struct CustomTypeKey(pub String, pub SourceModuleId);
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum TypeKind {
|
pub enum TypeKind {
|
||||||
Bool,
|
Bool,
|
||||||
I8,
|
I8,
|
||||||
@ -120,7 +94,7 @@ pub enum TypeKind {
|
|||||||
U128,
|
U128,
|
||||||
Void,
|
Void,
|
||||||
F16,
|
F16,
|
||||||
F16B,
|
F32B,
|
||||||
F32,
|
F32,
|
||||||
F64,
|
F64,
|
||||||
F128,
|
F128,
|
||||||
@ -220,7 +194,7 @@ impl Literal {
|
|||||||
Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Integer),
|
Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Integer),
|
||||||
Literal::Vague(VagueLiteral::Decimal(_)) => TypeKind::Vague(VagueType::Decimal),
|
Literal::Vague(VagueLiteral::Decimal(_)) => TypeKind::Vague(VagueType::Decimal),
|
||||||
Literal::F16(_) => TypeKind::F16,
|
Literal::F16(_) => TypeKind::F16,
|
||||||
Literal::F32B(_) => TypeKind::F16B,
|
Literal::F32B(_) => TypeKind::F32B,
|
||||||
Literal::F32(_) => TypeKind::F32,
|
Literal::F32(_) => TypeKind::F32,
|
||||||
Literal::F64(_) => TypeKind::F64,
|
Literal::F64(_) => TypeKind::F64,
|
||||||
Literal::F80(_) => TypeKind::F80,
|
Literal::F80(_) => TypeKind::F80,
|
||||||
@ -278,15 +252,15 @@ pub enum ReturnKind {
|
|||||||
pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
|
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, Metadata)>, pub Metadata);
|
pub struct Import(pub Vec<String>, pub Metadata);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[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>),
|
||||||
Accessed(Box<Expression>, TypeKind, String, Metadata),
|
Accessed(Box<Expression>, TypeKind, String),
|
||||||
Array(Vec<Expression>),
|
Array(Vec<Expression>),
|
||||||
Struct(CustomTypeKey, Vec<(String, Expression, Metadata)>),
|
Struct(String, Vec<(String, Expression)>),
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
BinOp(BinaryOperator, Box<Expression>, Box<Expression>, TypeKind),
|
BinOp(BinaryOperator, Box<Expression>, Box<Expression>, TypeKind),
|
||||||
FunctionCall(FunctionCall),
|
FunctionCall(FunctionCall),
|
||||||
@ -296,7 +270,6 @@ pub enum ExprKind {
|
|||||||
Borrow(Box<Expression>, bool),
|
Borrow(Box<Expression>, bool),
|
||||||
Deref(Box<Expression>),
|
Deref(Box<Expression>),
|
||||||
CastTo(Box<Expression>, TypeKind),
|
CastTo(Box<Expression>, TypeKind),
|
||||||
GlobalRef(String, TypeKind),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -311,41 +284,20 @@ pub struct FunctionCall {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub return_type: TypeKind,
|
pub return_type: TypeKind,
|
||||||
pub parameters: Vec<Expression>,
|
pub parameters: Vec<Expression>,
|
||||||
pub is_macro: bool,
|
|
||||||
pub meta: Metadata,
|
pub meta: Metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionDefinition {
|
pub struct FunctionDefinition {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub documentation: Option<String>,
|
|
||||||
pub linkage_name: Option<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
|
||||||
pub is_imported: bool,
|
pub is_imported: bool,
|
||||||
pub return_type: TypeKind,
|
pub return_type: TypeKind,
|
||||||
pub parameters: Vec<FunctionParam>,
|
pub parameters: Vec<(String, TypeKind)>,
|
||||||
pub kind: FunctionDefinitionKind,
|
pub kind: FunctionDefinitionKind,
|
||||||
pub source: Option<SourceModuleId>,
|
|
||||||
pub signature_meta: Metadata,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
|
||||||
pub struct FunctionParam {
|
|
||||||
pub name: String,
|
|
||||||
pub ty: TypeKind,
|
|
||||||
pub meta: Metadata,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FunctionParam {
|
|
||||||
pub fn from<T: Into<String>>(name: T, ty: TypeKind) -> FunctionParam {
|
|
||||||
FunctionParam {
|
|
||||||
name: name.into(),
|
|
||||||
ty: ty,
|
|
||||||
meta: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum SelfKind {
|
pub enum SelfKind {
|
||||||
@ -374,7 +326,11 @@ impl FunctionDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn signature(&self) -> Metadata {
|
pub fn signature(&self) -> Metadata {
|
||||||
self.signature_meta
|
match &self.kind {
|
||||||
|
FunctionDefinitionKind::Local(_, metadata) => metadata.clone(),
|
||||||
|
FunctionDefinitionKind::Extern(_) => Metadata::default(),
|
||||||
|
FunctionDefinitionKind::Intrinsic(_) => Metadata::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,9 +378,9 @@ pub enum TypeDefinitionKind {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BinopDefinition {
|
pub struct BinopDefinition {
|
||||||
pub lhs: FunctionParam,
|
pub lhs: (String, TypeKind),
|
||||||
pub op: BinaryOperator,
|
pub op: BinaryOperator,
|
||||||
pub rhs: FunctionParam,
|
pub rhs: (String, TypeKind),
|
||||||
pub return_type: TypeKind,
|
pub return_type: TypeKind,
|
||||||
pub fn_kind: FunctionDefinitionKind,
|
pub fn_kind: FunctionDefinitionKind,
|
||||||
pub meta: Metadata,
|
pub meta: Metadata,
|
||||||
@ -455,24 +411,11 @@ pub struct Module {
|
|||||||
pub functions: Vec<FunctionDefinition>,
|
pub functions: Vec<FunctionDefinition>,
|
||||||
pub typedefs: Vec<TypeDefinition>,
|
pub typedefs: Vec<TypeDefinition>,
|
||||||
pub binop_defs: Vec<BinopDefinition>,
|
pub binop_defs: Vec<BinopDefinition>,
|
||||||
pub globals: Vec<GlobalValue>,
|
|
||||||
pub path: Option<PathBuf>,
|
pub path: Option<PathBuf>,
|
||||||
pub tokens: Vec<FullToken>,
|
pub tokens: Vec<FullToken>,
|
||||||
pub is_main: bool,
|
pub is_main: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct GlobalValue {
|
|
||||||
pub name: String,
|
|
||||||
pub kind: GlobalKind,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum GlobalKind {
|
|
||||||
Literal(Literal),
|
|
||||||
Array(Vec<GlobalKind>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type ModuleMap = HashMap<SourceModuleId, Module>;
|
pub type ModuleMap = HashMap<SourceModuleId, Module>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@ -187,7 +187,7 @@ impl<Data: Clone + Default> Scope<Data> {
|
|||||||
key.clone(),
|
key.clone(),
|
||||||
ScopeFunction {
|
ScopeFunction {
|
||||||
ret: func.return_type,
|
ret: func.return_type,
|
||||||
params: func.parameters.iter().map(|p| p.ty.clone()).collect(),
|
params: func.parameters.iter().map(|(_, p)| p.clone()).collect(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -369,11 +369,11 @@ impl Context {
|
|||||||
.binops
|
.binops
|
||||||
.set(
|
.set(
|
||||||
BinopKey {
|
BinopKey {
|
||||||
params: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()),
|
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||||
operator: intrinsic.op,
|
operator: intrinsic.op,
|
||||||
},
|
},
|
||||||
ScopeBinopDef {
|
ScopeBinopDef {
|
||||||
hands: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()),
|
hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||||
operator: intrinsic.op,
|
operator: intrinsic.op,
|
||||||
return_ty: intrinsic.return_type.clone(),
|
return_ty: intrinsic.return_type.clone(),
|
||||||
},
|
},
|
||||||
@ -407,11 +407,11 @@ impl Module {
|
|||||||
.binops
|
.binops
|
||||||
.set(
|
.set(
|
||||||
BinopKey {
|
BinopKey {
|
||||||
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||||
operator: binop.op,
|
operator: binop.op,
|
||||||
},
|
},
|
||||||
ScopeBinopDef {
|
ScopeBinopDef {
|
||||||
hands: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
hands: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||||
operator: binop.op,
|
operator: binop.op,
|
||||||
return_ty: binop.return_type.clone(),
|
return_ty: binop.return_type.clone(),
|
||||||
},
|
},
|
||||||
@ -426,7 +426,7 @@ impl Module {
|
|||||||
function.name.clone(),
|
function.name.clone(),
|
||||||
ScopeFunction {
|
ScopeFunction {
|
||||||
ret: function.return_type.clone(),
|
ret: function.return_type.clone(),
|
||||||
params: function.parameters.iter().cloned().map(|v| v.ty).collect(),
|
params: function.parameters.iter().cloned().map(|v| v.1).collect(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
@ -439,7 +439,7 @@ impl Module {
|
|||||||
AssociatedFunctionKey(ty.clone(), function.name.clone()),
|
AssociatedFunctionKey(ty.clone(), function.name.clone()),
|
||||||
ScopeFunction {
|
ScopeFunction {
|
||||||
ret: function.return_type.clone(),
|
ret: function.return_type.clone(),
|
||||||
params: function.parameters.iter().cloned().map(|v| v.ty).collect(),
|
params: function.parameters.iter().cloned().map(|v| v.1).collect(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
@ -450,10 +450,6 @@ impl Module {
|
|||||||
for function in &mut self.functions {
|
for function in &mut self.functions {
|
||||||
function.pass(pass, state, &mut scope.inner(), self.module_id)?;
|
function.pass(pass, state, &mut scope.inner(), self.module_id)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_, function) in &mut self.associated_functions {
|
|
||||||
function.pass(pass, state, &mut scope.inner(), self.module_id)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,9 +466,9 @@ impl FunctionDefinition {
|
|||||||
scope
|
scope
|
||||||
.variables
|
.variables
|
||||||
.set(
|
.set(
|
||||||
param.name.clone(),
|
param.0.clone(),
|
||||||
ScopeVariable {
|
ScopeVariable {
|
||||||
ty: param.ty.clone(),
|
ty: param.1.clone(),
|
||||||
mutable: false,
|
mutable: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -507,10 +503,6 @@ impl Block {
|
|||||||
statement.pass(pass, state, &mut scope, mod_id)?;
|
statement.pass(pass, state, &mut scope, mod_id)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((_, Some(return_expr))) = &mut self.return_expression {
|
|
||||||
return_expr.pass(pass, state, &mut scope, mod_id)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
pass.block(self, PassState::from(state, &mut scope, Some(mod_id)))
|
pass.block(self, PassState::from(state, &mut scope, Some(mod_id)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,7 +581,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Struct(_, items) => {
|
ExprKind::Struct(_, items) => {
|
||||||
for (_, expr, _) in items {
|
for (_, expr) in items {
|
||||||
expr.pass(pass, state, scope, mod_id)?;
|
expr.pass(pass, state, scope, mod_id)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -619,7 +611,6 @@ impl Expression {
|
|||||||
ExprKind::Borrow(expression, _) => expression.pass(pass, state, scope, mod_id)?,
|
ExprKind::Borrow(expression, _) => expression.pass(pass, state, scope, mod_id)?,
|
||||||
ExprKind::Deref(expression) => expression.pass(pass, state, scope, mod_id)?,
|
ExprKind::Deref(expression) => expression.pass(pass, state, scope, mod_id)?,
|
||||||
ExprKind::CastTo(expression, _) => expression.pass(pass, state, scope, mod_id)?,
|
ExprKind::CastTo(expression, _) => expression.pass(pass, state, scope, mod_id)?,
|
||||||
ExprKind::GlobalRef(..) => {}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,8 +88,6 @@ pub enum ErrorKind {
|
|||||||
InvalidBinop(BinaryOperator, TypeKind, TypeKind),
|
InvalidBinop(BinaryOperator, TypeKind, TypeKind),
|
||||||
#[error("Could not infer type for {0:?}. Try adding type annotations.")]
|
#[error("Could not infer type for {0:?}. Try adding type annotations.")]
|
||||||
CouldNotInferType(String),
|
CouldNotInferType(String),
|
||||||
#[error("Arguments for a macro-function may only contain literals")]
|
|
||||||
MacroMustBeLiterals,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
@ -141,7 +139,7 @@ impl TypeKind {
|
|||||||
| TypeKind::U64
|
| TypeKind::U64
|
||||||
| TypeKind::U128
|
| TypeKind::U128
|
||||||
| TypeKind::F16
|
| TypeKind::F16
|
||||||
| TypeKind::F16B
|
| TypeKind::F32B
|
||||||
| TypeKind::F32
|
| TypeKind::F32
|
||||||
| TypeKind::F64
|
| TypeKind::F64
|
||||||
| TypeKind::F80
|
| TypeKind::F80
|
||||||
@ -153,7 +151,7 @@ impl TypeKind {
|
|||||||
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Decimal)),
|
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Decimal)),
|
||||||
TypeKind::Vague(Vague::Decimal) => Ok(TypeKind::Vague(Vague::Decimal)),
|
TypeKind::Vague(Vague::Decimal) => Ok(TypeKind::Vague(Vague::Decimal)),
|
||||||
TypeKind::F16
|
TypeKind::F16
|
||||||
| TypeKind::F16B
|
| TypeKind::F32B
|
||||||
| TypeKind::F32
|
| TypeKind::F32
|
||||||
| TypeKind::F64
|
| TypeKind::F64
|
||||||
| TypeKind::F80
|
| TypeKind::F80
|
||||||
@ -207,7 +205,7 @@ impl TypeKind {
|
|||||||
},
|
},
|
||||||
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => match other {
|
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => match other {
|
||||||
TypeKind::F16
|
TypeKind::F16
|
||||||
| TypeKind::F16B
|
| TypeKind::F32B
|
||||||
| TypeKind::F32
|
| TypeKind::F32
|
||||||
| TypeKind::F64
|
| TypeKind::F64
|
||||||
| TypeKind::F80
|
| TypeKind::F80
|
||||||
@ -256,16 +254,6 @@ impl TypeKind {
|
|||||||
let other_cat = other.category();
|
let other_cat = other.category();
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Ok(other.clone()),
|
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Ok(other.clone()),
|
||||||
(TypeKind::Borrow(ty1, _), TypeKind::UserPtr(ty2)) => match *ty1.clone() {
|
|
||||||
TypeKind::Array(ty1, _) => {
|
|
||||||
if ty1 == *ty2 {
|
|
||||||
Ok(other.clone())
|
|
||||||
} else {
|
|
||||||
Err(ErrorKind::NotCastableTo(self.clone(), other.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(ErrorKind::NotCastableTo(self.clone(), other.clone())),
|
|
||||||
},
|
|
||||||
(TypeKind::Char, TypeKind::U8) => Ok(other.clone()),
|
(TypeKind::Char, TypeKind::U8) => Ok(other.clone()),
|
||||||
(TypeKind::U8, TypeKind::Char) => Ok(other.clone()),
|
(TypeKind::U8, TypeKind::Char) => Ok(other.clone()),
|
||||||
_ => match (&self_cat, &other_cat) {
|
_ => match (&self_cat, &other_cat) {
|
||||||
@ -333,7 +321,7 @@ impl TypeKind {
|
|||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.ok_or(ErrorKind::NoSuchType(
|
.ok_or(ErrorKind::NoSuchType(
|
||||||
custom_type_key.0.clone(),
|
custom_type_key.0.clone(),
|
||||||
custom_type_key.1.clone(),
|
state.module_id.unwrap(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
TypeKind::Borrow(type_kind, _) => type_kind.is_known(state),
|
TypeKind::Borrow(type_kind, _) => type_kind.is_known(state),
|
||||||
|
|||||||
@ -84,7 +84,7 @@ impl<'t> Pass for TypeCheck<'t> {
|
|||||||
fn check_typedefs_for_recursion<'a, 'b>(
|
fn check_typedefs_for_recursion<'a, 'b>(
|
||||||
defmap: &'b HashMap<&'a String, &'b TypeDefinition>,
|
defmap: &'b HashMap<&'a String, &'b TypeDefinition>,
|
||||||
typedef: &'b TypeDefinition,
|
typedef: &'b TypeDefinition,
|
||||||
seen: HashSet<String>,
|
mut seen: HashSet<String>,
|
||||||
state: &mut TypecheckPassState,
|
state: &mut TypecheckPassState,
|
||||||
) {
|
) {
|
||||||
match &typedef.kind {
|
match &typedef.kind {
|
||||||
@ -97,10 +97,9 @@ fn check_typedefs_for_recursion<'a, 'b>(
|
|||||||
typedef.meta,
|
typedef.meta,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
seen.insert(name.clone());
|
||||||
if let Some(inner_typedef) = defmap.get(name) {
|
if let Some(inner_typedef) = defmap.get(name) {
|
||||||
let mut inner_seen = seen.clone();
|
check_typedefs_for_recursion(defmap, inner_typedef, seen.clone(), state)
|
||||||
inner_seen.insert(name.clone());
|
|
||||||
check_typedefs_for_recursion(defmap, inner_typedef, inner_seen.clone(), state)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +112,7 @@ impl BinopDefinition {
|
|||||||
fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> {
|
fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> {
|
||||||
for param in vec![&self.lhs, &self.rhs] {
|
for param in vec![&self.lhs, &self.rhs] {
|
||||||
let param_t = state.or_else(
|
let param_t = state.or_else(
|
||||||
param.ty.assert_known(state),
|
param.1.assert_known(state),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
self.signature(),
|
self.signature(),
|
||||||
);
|
);
|
||||||
@ -121,13 +120,13 @@ impl BinopDefinition {
|
|||||||
.scope
|
.scope
|
||||||
.variables
|
.variables
|
||||||
.set(
|
.set(
|
||||||
param.name.clone(),
|
param.0.clone(),
|
||||||
ScopeVariable {
|
ScopeVariable {
|
||||||
ty: param_t.clone(),
|
ty: param_t.clone(),
|
||||||
mutable: param_t.is_mutable(),
|
mutable: param_t.is_mutable(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.name.clone())));
|
.or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
|
||||||
state.ok(res, self.signature());
|
state.ok(res, self.signature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +150,7 @@ impl FunctionDefinition {
|
|||||||
fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> {
|
fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> {
|
||||||
for param in &self.parameters {
|
for param in &self.parameters {
|
||||||
let param_t = state.or_else(
|
let param_t = state.or_else(
|
||||||
param.ty.assert_known(state),
|
param.1.assert_known(state),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
self.signature(),
|
self.signature(),
|
||||||
);
|
);
|
||||||
@ -159,13 +158,13 @@ impl FunctionDefinition {
|
|||||||
.scope
|
.scope
|
||||||
.variables
|
.variables
|
||||||
.set(
|
.set(
|
||||||
param.name.clone(),
|
param.0.clone(),
|
||||||
ScopeVariable {
|
ScopeVariable {
|
||||||
ty: param_t.clone(),
|
ty: param_t.clone(),
|
||||||
mutable: param_t.is_mutable(),
|
mutable: param_t.is_mutable(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.name.clone())));
|
.or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
|
||||||
state.ok(res, self.signature());
|
state.ok(res, self.signature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +193,7 @@ impl FunctionDefinitionKind {
|
|||||||
block.typecheck(&mut state.inner(), &typerefs, hint.into())
|
block.typecheck(&mut state.inner(), &typerefs, hint.into())
|
||||||
}
|
}
|
||||||
FunctionDefinitionKind::Extern(_) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
|
FunctionDefinitionKind::Extern(_) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
|
||||||
FunctionDefinitionKind::Intrinsic(_) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
|
FunctionDefinitionKind::Intrinsic(..) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -597,7 +596,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Accessed(expression, type_kind, field_name, _) => {
|
ExprKind::Accessed(expression, type_kind, field_name) => {
|
||||||
// Resolve expected type
|
// Resolve expected type
|
||||||
let expected_ty = type_kind.resolve_ref(typerefs);
|
let expected_ty = type_kind.resolve_ref(typerefs);
|
||||||
|
|
||||||
@ -621,31 +620,32 @@ impl Expression {
|
|||||||
// Update possibly resolved type
|
// Update possibly resolved type
|
||||||
Ok(true_ty)
|
Ok(true_ty)
|
||||||
} else {
|
} else {
|
||||||
Err(ErrorKind::NoSuchField(key.0.clone()))
|
Err(ErrorKind::NoSuchField(field_name.clone()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ErrorKind::TriedAccessingNonStruct(expr_ty))
|
Err(ErrorKind::TriedAccessingNonStruct(expr_ty))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Struct(struct_key, items) => {
|
ExprKind::Struct(struct_name, items) => {
|
||||||
|
let type_key = CustomTypeKey(struct_name.clone(), state.module_id.unwrap());
|
||||||
let struct_def = state
|
let struct_def = state
|
||||||
.scope
|
.scope
|
||||||
.get_struct_type(&struct_key)
|
.get_struct_type(&type_key)
|
||||||
.ok_or(ErrorKind::NoSuchType(struct_key.0.clone(), struct_key.1))?
|
.ok_or(ErrorKind::NoSuchType(struct_name.clone(), type_key.1))?
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let mut expected_fields = if let Some(struct_ty) = state.scope.get_struct_type(&struct_key) {
|
let mut expected_fields = if let Some(struct_ty) = state.scope.get_struct_type(&type_key) {
|
||||||
struct_ty.0.iter().map(|f| f.0.clone()).collect()
|
struct_ty.0.iter().map(|f| f.0.clone()).collect()
|
||||||
} else {
|
} else {
|
||||||
HashSet::new()
|
HashSet::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
for (field_name, field_expr, _) in items {
|
for (field_name, field_expr) in items {
|
||||||
// Get expected type, or error if field does not exist
|
// Get expected type, or error if field does not exist
|
||||||
let expected_ty = state.or_else(
|
let expected_ty = state.or_else(
|
||||||
struct_def
|
struct_def
|
||||||
.get_field_ty(field_name)
|
.get_field_ty(field_name)
|
||||||
.ok_or(ErrorKind::NoSuchField(format!("{:?}.{}", struct_key, field_name))),
|
.ok_or(ErrorKind::NoSuchField(format!("{}.{}", struct_name, field_name))),
|
||||||
&TypeKind::Vague(VagueType::Unknown),
|
&TypeKind::Vague(VagueType::Unknown),
|
||||||
field_expr.1,
|
field_expr.1,
|
||||||
);
|
);
|
||||||
@ -667,7 +667,7 @@ impl Expression {
|
|||||||
self.1,
|
self.1,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(TypeKind::CustomType(struct_key.clone()))
|
Ok(TypeKind::CustomType(type_key))
|
||||||
}
|
}
|
||||||
ExprKind::Borrow(expr, mutable) => {
|
ExprKind::Borrow(expr, mutable) => {
|
||||||
let hint_t = if let HintKind::Coerce(hint_t) = hint_t {
|
let hint_t = if let HintKind::Coerce(hint_t) = hint_t {
|
||||||
@ -720,19 +720,15 @@ impl Expression {
|
|||||||
expr.resolve_ref(typerefs).cast_into(type_kind)
|
expr.resolve_ref(typerefs).cast_into(type_kind)
|
||||||
}
|
}
|
||||||
ExprKind::AssociatedFunctionCall(type_kind, function_call) => {
|
ExprKind::AssociatedFunctionCall(type_kind, function_call) => {
|
||||||
*type_kind = type_kind.or_default()?;
|
|
||||||
let true_function = state
|
let true_function = state
|
||||||
.scope
|
.scope
|
||||||
.get_associated_function(&pass::AssociatedFunctionKey(
|
.get_associated_function(&pass::AssociatedFunctionKey(
|
||||||
type_kind.clone(),
|
type_kind.clone(),
|
||||||
function_call.name.clone(),
|
function_call.name.clone(),
|
||||||
))
|
))
|
||||||
.ok_or(ErrorKind::AssocFunctionNotDefined(
|
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()));
|
||||||
function_call.name.clone(),
|
|
||||||
type_kind.clone(),
|
|
||||||
));
|
|
||||||
|
|
||||||
if let Some(f) = state.ok(true_function, function_call.meta) {
|
if let Some(f) = state.ok(true_function, self.1) {
|
||||||
let param_len_given = function_call.parameters.len();
|
let param_len_given = function_call.parameters.len();
|
||||||
let param_len_expected = f.params.len();
|
let param_len_expected = f.params.len();
|
||||||
|
|
||||||
@ -771,10 +767,6 @@ impl Expression {
|
|||||||
Ok(function_call.return_type.clone().resolve_ref(typerefs))
|
Ok(function_call.return_type.clone().resolve_ref(typerefs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::GlobalRef(..) => Ok(self
|
|
||||||
.return_type(typerefs, state.scope.module_id.unwrap())
|
|
||||||
.map(|r| r.1)
|
|
||||||
.unwrap()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -806,14 +798,14 @@ impl Literal {
|
|||||||
(L::Vague(VagueL::Number(v)), TypeKind::U128) => L::U128(v as u128),
|
(L::Vague(VagueL::Number(v)), TypeKind::U128) => L::U128(v as u128),
|
||||||
(L::Vague(VagueL::Number(v)), TypeKind::F16) => L::F16(v as f32),
|
(L::Vague(VagueL::Number(v)), TypeKind::F16) => L::F16(v as f32),
|
||||||
(L::Vague(VagueL::Number(v)), TypeKind::F32) => L::F32(v as f32),
|
(L::Vague(VagueL::Number(v)), TypeKind::F32) => L::F32(v as f32),
|
||||||
(L::Vague(VagueL::Number(v)), TypeKind::F16B) => L::F32B(v as f32),
|
(L::Vague(VagueL::Number(v)), TypeKind::F32B) => L::F32B(v as f32),
|
||||||
(L::Vague(VagueL::Number(v)), TypeKind::F64) => L::F64(v as f64),
|
(L::Vague(VagueL::Number(v)), TypeKind::F64) => L::F64(v as f64),
|
||||||
(L::Vague(VagueL::Number(v)), TypeKind::F80) => L::F80(v as f64),
|
(L::Vague(VagueL::Number(v)), TypeKind::F80) => L::F80(v as f64),
|
||||||
(L::Vague(VagueL::Number(v)), TypeKind::F128) => L::F128(v as f64),
|
(L::Vague(VagueL::Number(v)), TypeKind::F128) => L::F128(v as f64),
|
||||||
(L::Vague(VagueL::Number(v)), TypeKind::F128PPC) => L::F128PPC(v as f64),
|
(L::Vague(VagueL::Number(v)), TypeKind::F128PPC) => L::F128PPC(v as f64),
|
||||||
(L::Vague(VagueL::Decimal(v)), TypeKind::F16) => L::F16(v as f32),
|
(L::Vague(VagueL::Decimal(v)), TypeKind::F16) => L::F16(v as f32),
|
||||||
(L::Vague(VagueL::Decimal(v)), TypeKind::F32) => L::F32(v as f32),
|
(L::Vague(VagueL::Decimal(v)), TypeKind::F32) => L::F32(v as f32),
|
||||||
(L::Vague(VagueL::Decimal(v)), TypeKind::F16B) => L::F32B(v as f32),
|
(L::Vague(VagueL::Decimal(v)), TypeKind::F32B) => L::F32B(v as f32),
|
||||||
(L::Vague(VagueL::Decimal(v)), TypeKind::F64) => L::F64(v as f64),
|
(L::Vague(VagueL::Decimal(v)), TypeKind::F64) => L::F64(v as f64),
|
||||||
(L::Vague(VagueL::Decimal(v)), TypeKind::F80) => L::F80(v as f64),
|
(L::Vague(VagueL::Decimal(v)), TypeKind::F80) => L::F80(v as f64),
|
||||||
(L::Vague(VagueL::Decimal(v)), TypeKind::F128) => L::F128(v as f64),
|
(L::Vague(VagueL::Decimal(v)), TypeKind::F128) => L::F128(v as f64),
|
||||||
|
|||||||
@ -12,10 +12,9 @@ use std::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mir::{
|
mir::{
|
||||||
implement::TypeCategory,
|
|
||||||
pass::{AssociatedFunctionKey, ScopeVariable},
|
pass::{AssociatedFunctionKey, ScopeVariable},
|
||||||
BinopDefinition, Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression, Module,
|
BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
|
||||||
ReturnKind, StmtKind, TypeKind, VagueType, WhileStatement,
|
IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
|
||||||
},
|
},
|
||||||
util::try_all,
|
util::try_all,
|
||||||
};
|
};
|
||||||
@ -88,16 +87,16 @@ impl<'t> Pass for TypeInference<'t> {
|
|||||||
let mut seen_binops = HashSet::new();
|
let mut seen_binops = HashSet::new();
|
||||||
for binop in &module.binop_defs {
|
for binop in &module.binop_defs {
|
||||||
let binop_key = BinopKey {
|
let binop_key = BinopKey {
|
||||||
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||||
operator: binop.op,
|
operator: binop.op,
|
||||||
};
|
};
|
||||||
if seen_binops.contains(&binop_key) || (binop.lhs == binop.rhs && binop.lhs.ty.category().is_simple_maths())
|
if seen_binops.contains(&binop_key) || (binop.lhs == binop.rhs && binop.lhs.1.category().is_simple_maths())
|
||||||
{
|
{
|
||||||
state.note_errors(
|
state.note_errors(
|
||||||
&vec![ErrorKind::BinaryOpAlreadyDefined(
|
&vec![ErrorKind::BinaryOpAlreadyDefined(
|
||||||
binop.op,
|
binop.op,
|
||||||
binop.lhs.ty.clone(),
|
binop.lhs.1.clone(),
|
||||||
binop.rhs.ty.clone(),
|
binop.rhs.1.clone(),
|
||||||
)],
|
)],
|
||||||
binop.signature(),
|
binop.signature(),
|
||||||
);
|
);
|
||||||
@ -108,7 +107,7 @@ impl<'t> Pass for TypeInference<'t> {
|
|||||||
.set(
|
.set(
|
||||||
binop_key,
|
binop_key,
|
||||||
crate::mir::pass::ScopeBinopDef {
|
crate::mir::pass::ScopeBinopDef {
|
||||||
hands: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
hands: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||||
operator: binop.op,
|
operator: binop.op,
|
||||||
return_ty: binop.return_type.clone(),
|
return_ty: binop.return_type.clone(),
|
||||||
},
|
},
|
||||||
@ -139,20 +138,20 @@ impl BinopDefinition {
|
|||||||
fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> {
|
fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> {
|
||||||
let scope_hints = ScopeTypeRefs::from(type_refs);
|
let scope_hints = ScopeTypeRefs::from(type_refs);
|
||||||
|
|
||||||
let lhs_ty = state.or_else(self.lhs.ty.assert_unvague(), Vague(Unknown), self.signature());
|
let lhs_ty = state.or_else(self.lhs.1.assert_unvague(), Vague(Unknown), self.signature());
|
||||||
state.ok(
|
state.ok(
|
||||||
scope_hints
|
scope_hints
|
||||||
.new_var(self.lhs.name.clone(), false, &lhs_ty)
|
.new_var(self.lhs.0.clone(), false, &lhs_ty)
|
||||||
.or(Err(ErrorKind::VariableAlreadyDefined(self.lhs.name.clone()))),
|
.or(Err(ErrorKind::VariableAlreadyDefined(self.lhs.0.clone()))),
|
||||||
self.signature(),
|
self.signature(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let rhs_ty = state.or_else(self.rhs.ty.assert_unvague(), Vague(Unknown), self.signature());
|
let rhs_ty = state.or_else(self.rhs.1.assert_unvague(), Vague(Unknown), self.signature());
|
||||||
|
|
||||||
state.ok(
|
state.ok(
|
||||||
scope_hints
|
scope_hints
|
||||||
.new_var(self.rhs.name.clone(), false, &rhs_ty)
|
.new_var(self.rhs.0.clone(), false, &rhs_ty)
|
||||||
.or(Err(ErrorKind::VariableAlreadyDefined(self.rhs.name.clone()))),
|
.or(Err(ErrorKind::VariableAlreadyDefined(self.rhs.0.clone()))),
|
||||||
self.signature(),
|
self.signature(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -171,11 +170,10 @@ impl FunctionDefinition {
|
|||||||
fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> {
|
fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> {
|
||||||
let scope_refs = ScopeTypeRefs::from(type_refs);
|
let scope_refs = ScopeTypeRefs::from(type_refs);
|
||||||
for param in &self.parameters {
|
for param in &self.parameters {
|
||||||
let param_t = state.or_else(param.ty.assert_unvague(), Vague(Unknown), self.signature());
|
let param_t = state.or_else(param.1.assert_unvague(), Vague(Unknown), self.signature());
|
||||||
let mutable = matches!(param_t, TypeKind::Borrow(_, true));
|
|
||||||
let res = scope_refs
|
let res = scope_refs
|
||||||
.new_var(param.name.clone(), mutable, ¶m_t)
|
.new_var(param.0.clone(), false, ¶m_t)
|
||||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.name.clone())));
|
.or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
|
||||||
state.ok(res, self.signature());
|
state.ok(res, self.signature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,7 +381,6 @@ impl Expression {
|
|||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
if binops.len() > 0 {
|
if binops.len() > 0 {
|
||||||
let binop = unsafe { binops.get_unchecked(0) };
|
let binop = unsafe { binops.get_unchecked(0) };
|
||||||
let mut widened_lhs = binop.hands.0.clone();
|
let mut widened_lhs = binop.hands.0.clone();
|
||||||
@ -393,6 +390,9 @@ impl Expression {
|
|||||||
widened_rhs = widened_rhs.widen_into(&binop.hands.1);
|
widened_rhs = widened_rhs.widen_into(&binop.hands.1);
|
||||||
}
|
}
|
||||||
let binop_res = type_refs.from_binop(*op, &lhs_ref, &rhs_ref);
|
let binop_res = type_refs.from_binop(*op, &lhs_ref, &rhs_ref);
|
||||||
|
// dbg!(&return_ty);
|
||||||
|
// dbg!(&binop_res);
|
||||||
|
// dbg!(&lhs_ref, &rhs_ref, &binops, &widened_lhs, &widened_rhs);
|
||||||
lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap());
|
lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap());
|
||||||
rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap());
|
rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap());
|
||||||
*return_ty = binop_res.as_type();
|
*return_ty = binop_res.as_type();
|
||||||
@ -526,7 +526,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Accessed(expression, type_kind, field_name, _) => {
|
ExprKind::Accessed(expression, type_kind, field_name) => {
|
||||||
let expr_ty = expression.infer_types(state, type_refs)?;
|
let expr_ty = expression.infer_types(state, type_refs)?;
|
||||||
|
|
||||||
// Check that the resolved type is at least a struct, no
|
// Check that the resolved type is at least a struct, no
|
||||||
@ -545,17 +545,18 @@ impl Expression {
|
|||||||
*type_kind = elem_ty.as_type().clone();
|
*type_kind = elem_ty.as_type().clone();
|
||||||
Ok(elem_ty)
|
Ok(elem_ty)
|
||||||
}
|
}
|
||||||
None => Ok(type_refs.from_type(&TypeKind::Vague(VagueType::Unknown)).unwrap()),
|
None => Err(ErrorKind::NoSuchField(field_name.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Ok(type_refs.from_type(&TypeKind::Vague(VagueType::Unknown)).unwrap()),
|
_ => Err(ErrorKind::TriedAccessingNonStruct(kind)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Struct(struct_key, fields) => {
|
ExprKind::Struct(struct_name, fields) => {
|
||||||
|
let type_key = CustomTypeKey(struct_name.clone(), state.module_id.unwrap());
|
||||||
let expected_struct_ty = state
|
let expected_struct_ty = state
|
||||||
.scope
|
.scope
|
||||||
.get_struct_type(&struct_key)
|
.get_struct_type(&type_key)
|
||||||
.ok_or(ErrorKind::NoSuchType(struct_key.0.clone(), state.module_id.unwrap()))?
|
.ok_or(ErrorKind::NoSuchType(struct_name.clone(), state.module_id.unwrap()))?
|
||||||
.clone();
|
.clone();
|
||||||
for field in fields {
|
for field in fields {
|
||||||
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
||||||
@ -565,12 +566,12 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::NoSuchField(format!("{:?}.{}", struct_key, field.0))),
|
Err(ErrorKind::NoSuchField(format!("{}.{}", struct_name, field.0))),
|
||||||
field.1 .1,
|
field.1 .1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(type_refs.from_type(&TypeKind::CustomType(struct_key.clone())).unwrap())
|
Ok(type_refs.from_type(&TypeKind::CustomType(type_key.clone())).unwrap())
|
||||||
}
|
}
|
||||||
ExprKind::Borrow(expr, mutable) => {
|
ExprKind::Borrow(expr, mutable) => {
|
||||||
// Find variable type
|
// Find variable type
|
||||||
@ -604,7 +605,7 @@ impl Expression {
|
|||||||
.parameters
|
.parameters
|
||||||
.get_mut(0)
|
.get_mut(0)
|
||||||
.expect("Unknown-type associated function NEEDS to always have at least one parameter!");
|
.expect("Unknown-type associated function NEEDS to always have at least one parameter!");
|
||||||
let param_ty = first_param.infer_types(state, type_refs)?.resolve_deep();
|
let param_ty = first_param.infer_types(state, type_refs).unwrap().resolve_deep();
|
||||||
*type_kind = state
|
*type_kind = state
|
||||||
.or_else(
|
.or_else(
|
||||||
param_ty.ok_or(ErrorKind::CouldNotInferType(format!("{}", first_param))),
|
param_ty.ok_or(ErrorKind::CouldNotInferType(format!("{}", first_param))),
|
||||||
@ -612,45 +613,25 @@ impl Expression {
|
|||||||
first_param.1,
|
first_param.1,
|
||||||
)
|
)
|
||||||
.resolve_ref(type_refs.types);
|
.resolve_ref(type_refs.types);
|
||||||
let backing_var = first_param.backing_var();
|
let backing_var = first_param.backing_var().expect("todo").1.clone();
|
||||||
let is_mutable = if let Some(backing_var) = first_param.backing_var() {
|
|
||||||
if let Some((mutable, _)) = type_refs.find_var(&backing_var.1) {
|
|
||||||
mutable
|
|
||||||
} else {
|
|
||||||
return Err(ErrorKind::VariableNotDefined(backing_var.1.clone()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
if backing_var.is_some() {
|
|
||||||
if let TypeKind::Borrow(inner, _) = type_kind {
|
if let TypeKind::Borrow(inner, _) = type_kind {
|
||||||
let ty_cat = inner.category();
|
|
||||||
if let TypeKind::Borrow(..) = *inner.clone() {
|
if let TypeKind::Borrow(..) = *inner.clone() {
|
||||||
*type_kind = type_kind.unroll_borrow();
|
*type_kind = type_kind.unroll_borrow();
|
||||||
let ExprKind::Borrow(val, _) = &first_param.0 else {
|
let ExprKind::Borrow(val, _) = &first_param.0 else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
*first_param = *val.clone();
|
*first_param = *val.clone();
|
||||||
} else if ty_cat == TypeCategory::Integer || ty_cat == TypeCategory::Real {
|
|
||||||
if let ExprKind::Borrow(val, _) = &first_param.0 {
|
|
||||||
*first_param = *val.clone();
|
|
||||||
}
|
|
||||||
*type_kind = *inner.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if let ExprKind::Borrow(val, _) = &first_param.0 {
|
|
||||||
*first_param = *val.clone();
|
|
||||||
}
|
|
||||||
if let TypeKind::Borrow(inner_ty, _) = type_kind {
|
|
||||||
*type_kind = *inner_ty.clone();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !is_mutable {
|
if let Some((mutable, _)) = type_refs.find_var(&backing_var) {
|
||||||
|
if !mutable {
|
||||||
first_param.remove_borrow_mutability();
|
first_param.remove_borrow_mutability();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ErrorKind::VariableNotDefined(backing_var));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -661,13 +642,9 @@ impl Expression {
|
|||||||
.ok_or(ErrorKind::AssocFunctionNotDefined(
|
.ok_or(ErrorKind::AssocFunctionNotDefined(
|
||||||
function_call.name.clone(),
|
function_call.name.clone(),
|
||||||
type_kind.clone(),
|
type_kind.clone(),
|
||||||
))
|
))?
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let Ok(fn_call) = fn_call else {
|
|
||||||
return Ok(type_refs.from_type(&Vague(Unknown)).unwrap());
|
|
||||||
};
|
|
||||||
|
|
||||||
// Infer param expression types and narrow them to the
|
// Infer param expression types and narrow them to the
|
||||||
// expected function parameters (or Unknown types if too
|
// expected function parameters (or Unknown types if too
|
||||||
// many were provided)
|
// many were provided)
|
||||||
@ -683,10 +660,6 @@ impl Expression {
|
|||||||
// Provide function return type
|
// Provide function return type
|
||||||
Ok(type_refs.from_type(&fn_call.ret).unwrap())
|
Ok(type_refs.from_type(&fn_call.ret).unwrap())
|
||||||
}
|
}
|
||||||
ExprKind::GlobalRef(..) => Ok(self
|
|
||||||
.return_type(type_refs.types, state.scope.module_id.unwrap())
|
|
||||||
.map(|r| type_refs.from_type(&r.1).unwrap())
|
|
||||||
.unwrap()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -97,9 +97,6 @@ pub struct TypeRefs {
|
|||||||
/// Indirect ID-references, referring to hints-vec
|
/// Indirect ID-references, referring to hints-vec
|
||||||
pub(super) type_refs: RefCell<Vec<TypeIdRef>>,
|
pub(super) type_refs: RefCell<Vec<TypeIdRef>>,
|
||||||
pub(super) binop_types: BinopMap,
|
pub(super) binop_types: BinopMap,
|
||||||
/// Used when the real typerefs are not available, and any TypeRefs need to
|
|
||||||
/// be resolved as Unknown.
|
|
||||||
pub unknown_typerefs: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for TypeRefs {
|
impl std::fmt::Display for TypeRefs {
|
||||||
@ -125,14 +122,6 @@ impl TypeRefs {
|
|||||||
hints: Default::default(),
|
hints: Default::default(),
|
||||||
type_refs: Default::default(),
|
type_refs: Default::default(),
|
||||||
binop_types: binops,
|
binop_types: binops,
|
||||||
unknown_typerefs: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unknown() -> TypeRefs {
|
|
||||||
TypeRefs {
|
|
||||||
unknown_typerefs: true,
|
|
||||||
..Default::default()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,12 +177,8 @@ impl TypeRefs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn retrieve_typeref(&self, idx: usize) -> Option<TypeRefKind> {
|
pub fn retrieve_typeref(&self, idx: usize) -> Option<TypeRefKind> {
|
||||||
if !self.unknown_typerefs {
|
|
||||||
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
|
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
|
||||||
self.hints.borrow().get(inner_idx).cloned()
|
self.hints.borrow().get(inner_idx).cloned()
|
||||||
} else {
|
|
||||||
Some(TypeRefKind::Direct(TypeKind::Vague(VagueType::Unknown)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retrieve_wide_type(&self, idx: usize, seen: &mut HashSet<usize>) -> Option<TypeKind> {
|
pub fn retrieve_wide_type(&self, idx: usize, seen: &mut HashSet<usize>) -> Option<TypeKind> {
|
||||||
@ -308,23 +293,12 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
|||||||
let lhs_resolved = lhs.resolve_ref(self.types);
|
let lhs_resolved = lhs.resolve_ref(self.types);
|
||||||
let rhs_resolved = rhs.resolve_ref(self.types);
|
let rhs_resolved = rhs.resolve_ref(self.types);
|
||||||
|
|
||||||
let mut binops = self
|
let binops = self
|
||||||
.types
|
.types
|
||||||
.binop_types
|
.binop_types
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|b| b.1.operator == op && b.1.return_ty == *ty)
|
.filter(|b| b.1.operator == op && b.1.return_ty == *ty)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Sort binops by lhs and then rhs
|
|
||||||
binops.sort_by(|a, b| {
|
|
||||||
let lhs = a.1.hands.0.cmp(&b.1.hands.0);
|
|
||||||
let rhs = a.1.hands.1.cmp(&b.1.hands.1);
|
|
||||||
match lhs {
|
|
||||||
std::cmp::Ordering::Equal => rhs,
|
|
||||||
_ => lhs,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for binop in binops {
|
for binop in binops {
|
||||||
if let (Ok(lhs_narrow), Ok(rhs_narrow)) = (
|
if let (Ok(lhs_narrow), Ok(rhs_narrow)) = (
|
||||||
lhs_resolved.narrow_into(&binop.1.hands.0),
|
lhs_resolved.narrow_into(&binop.1.hands.0),
|
||||||
@ -498,17 +472,6 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort binops by lhs and then rhs
|
|
||||||
applying_binops.sort_by(|a, b| {
|
|
||||||
let lhs = a.hands.0.cmp(&b.hands.0);
|
|
||||||
let rhs = a.hands.1.cmp(&b.hands.1);
|
|
||||||
match lhs {
|
|
||||||
std::cmp::Ordering::Equal => rhs,
|
|
||||||
_ => lhs,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
applying_binops
|
applying_binops
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,17 +6,17 @@ use reid::{
|
|||||||
mir::{self},
|
mir::{self},
|
||||||
parse_module, perform_all_passes,
|
parse_module, perform_all_passes,
|
||||||
};
|
};
|
||||||
use reid_lib::{compile::CompileOutput, Context};
|
use reid_lib::Context;
|
||||||
use util::assert_err;
|
use util::assert_err;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
fn test_compile(source: &str, name: &str) -> CompileOutput {
|
fn test(source: &str, name: &str, expected_exit_code: Option<i32>) {
|
||||||
assert_err(assert_err(std::panic::catch_unwind(|| {
|
assert_err(assert_err(std::panic::catch_unwind(|| {
|
||||||
let mut map = Default::default();
|
let mut map = Default::default();
|
||||||
let (id, tokens) = assert_err(parse_module(source, name, None, &mut map, None));
|
let (id, tokens) = assert_err(parse_module(source, name, &mut map));
|
||||||
|
|
||||||
let module = assert_err(assert_err(compile_module(id, tokens, &mut map, None, true)).map_err(|(_, e)| e));
|
let module = assert_err(compile_module(id, tokens, &mut map, None, true));
|
||||||
let mut mir_context = mir::Context::from(vec![module], Default::default());
|
let mut mir_context = mir::Context::from(vec![module], Default::default());
|
||||||
assert_err(perform_all_passes(&mut mir_context, &mut map));
|
assert_err(perform_all_passes(&mut mir_context, &mut map));
|
||||||
|
|
||||||
@ -24,14 +24,7 @@ fn test_compile(source: &str, name: &str) -> CompileOutput {
|
|||||||
|
|
||||||
let codegen = assert_err(mir_context.codegen(&context));
|
let codegen = assert_err(mir_context.codegen(&context));
|
||||||
|
|
||||||
Ok::<_, ()>(codegen.compile(None, Vec::new()).output())
|
let output = codegen.compile(None, Vec::new()).output();
|
||||||
})))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test(source: &str, name: &str, expected_exit_code: Option<i32>) {
|
|
||||||
assert_err(assert_err(std::panic::catch_unwind(|| {
|
|
||||||
let output = test_compile(source, name);
|
|
||||||
|
|
||||||
let time = SystemTime::now();
|
let time = SystemTime::now();
|
||||||
let in_path = PathBuf::from(format!(
|
let in_path = PathBuf::from(format!(
|
||||||
"/tmp/temp-{}.o",
|
"/tmp/temp-{}.o",
|
||||||
@ -156,21 +149,6 @@ fn associated_functions() {
|
|||||||
test(
|
test(
|
||||||
include_str!("../../examples/associated_functions.reid"),
|
include_str!("../../examples/associated_functions.reid"),
|
||||||
"test",
|
"test",
|
||||||
Some(4),
|
Some(32),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn mutable_inner_functions() {
|
|
||||||
test(include_str!("../../examples/mutable_inner.reid"), "test", Some(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cpu_raytracer_compiles() {
|
|
||||||
test_compile(include_str!("../../examples/cpu_raytracer.reid"), "test");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn loop_edge_case_functions() {
|
|
||||||
test(include_str!("../../examples/loop_edge_case.reid"), "test", Some(0));
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user