Compare commits
9 Commits
cb2604dc22
...
ce2278ce45
Author | SHA1 | Date | |
---|---|---|---|
ce2278ce45 | |||
0f782dcb96 | |||
6dfd98eba3 | |||
df4febf1ef | |||
9d1b18f083 | |||
ce7c4bfb52 | |||
f0e47a5d57 | |||
64e34ecf13 | |||
e2dc1a3f85 |
156
Cargo.lock
generated
156
Cargo.lock
generated
@ -4,36 +4,48 @@ version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
version = "1.2.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
version = "0.2.174"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||
|
||||
[[package]]
|
||||
name = "llvm-sys"
|
||||
version = "160.1.3"
|
||||
version = "160.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf51981ac0622b10fe4790763e3de1f3d68a0ee4222e03accaaab6731bd508d"
|
||||
checksum = "e73861901245d32e1c3d8b35b639cf100859b4cd0c9da56fe0273040acbb3ea4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"lazy_static",
|
||||
@ -44,33 +56,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
version = "2.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.32"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.9.1"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@ -80,9 +92,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.3.4"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@ -91,14 +103,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.4"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "reid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"colored",
|
||||
"llvm-sys",
|
||||
"reid-lib",
|
||||
"thiserror",
|
||||
@ -114,15 +127,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.18"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
|
||||
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.28"
|
||||
version = "2.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
|
||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -131,18 +150,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.44"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.44"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -151,6 +170,79 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
@ -5,9 +5,17 @@ edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
[features]
|
||||
default = ["color"]
|
||||
|
||||
color = ["colored"]
|
||||
|
||||
[dependencies]
|
||||
## LLVM Bindings
|
||||
llvm-sys = "160"
|
||||
## Make it easier to generate errors
|
||||
thiserror = "1.0.44"
|
||||
reid-lib = { path = "../reid-llvm-lib" }
|
||||
reid-lib = { path = "../reid-llvm-lib" }
|
||||
|
||||
colored = {version = "3.0.0", optional = true}
|
@ -1,6 +1,6 @@
|
||||
use std::{env, error::Error, fs, path::PathBuf};
|
||||
use std::{env, fs, path::PathBuf};
|
||||
|
||||
use reid::compile;
|
||||
use reid::compile_simple;
|
||||
use reid_lib::compile::CompileOutput;
|
||||
|
||||
fn main() -> Result<(), std::io::Error> {
|
||||
@ -15,7 +15,7 @@ fn main() -> Result<(), std::io::Error> {
|
||||
let before = std::time::SystemTime::now();
|
||||
|
||||
let text = fs::read_to_string(&path)?;
|
||||
match compile(&text, PathBuf::from(&path)) {
|
||||
match compile_simple(&text, PathBuf::from(&path)) {
|
||||
Ok(CompileOutput {
|
||||
triple,
|
||||
assembly,
|
||||
|
@ -161,6 +161,7 @@ fn main() {
|
||||
let mir_context = mir::Context {
|
||||
modules: vec![Module {
|
||||
name: "test module".to_owned(),
|
||||
module_id: SourceModuleId::default(),
|
||||
imports: vec![],
|
||||
functions: vec![fibonacci, main],
|
||||
typedefs: Vec::new(),
|
||||
|
@ -39,7 +39,7 @@ impl Parse for Type {
|
||||
"u64" => TypeKind::U64,
|
||||
"u128" => TypeKind::U128,
|
||||
"string" => TypeKind::String,
|
||||
_ => Err(stream.expected_err("known type identifier")?)?,
|
||||
_ => TypeKind::Custom(ident),
|
||||
}
|
||||
} else {
|
||||
return Err(stream.expected_err("type identifier")?)?;
|
||||
@ -128,7 +128,7 @@ impl Parse for PrimaryExpression {
|
||||
stream.expect(Token::BracketClose)?;
|
||||
Expression(Kind::Array(expressions), stream.get_range().unwrap())
|
||||
}
|
||||
_ => Err(stream.expected_err("identifier, constant, parentheses or brackets")?)?,
|
||||
_ => Err(stream.expected_err("expression")?)?,
|
||||
}
|
||||
} else {
|
||||
Err(stream.expected_err("expression")?)?
|
||||
@ -391,7 +391,8 @@ impl Parse for Block {
|
||||
// Special list of expressions that are simply not warned about,
|
||||
// if semicolon is missing.
|
||||
if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) {
|
||||
println!("Oh no, does this statement lack ;");
|
||||
// In theory could ignore the missing semicolon..
|
||||
return Err(stream.expected_err("expected semicolon to complete statement")?);
|
||||
}
|
||||
|
||||
statements.push(BlockLevelStatement::Expression(e));
|
||||
@ -445,7 +446,7 @@ impl<T: Parse + std::fmt::Debug> Parse for NamedFieldList<T> {
|
||||
stream.next();
|
||||
} // Consume comma
|
||||
Some(Token::BraceClose) => break,
|
||||
Some(_) | None => Err(stream.expected_err("another field or closing brace")?)?,
|
||||
Some(_) | None => Err(stream.expecting_err("another field or closing brace")?)?,
|
||||
}
|
||||
}
|
||||
Ok(NamedFieldList(fields))
|
||||
@ -478,7 +479,7 @@ impl Parse for ValueIndex {
|
||||
match stream.peek() {
|
||||
Some(Token::BracketOpen) => Ok(ValueIndex::Array(stream.parse()?)),
|
||||
Some(Token::Dot) => Ok(ValueIndex::Struct(stream.parse()?)),
|
||||
_ => Err(stream.expected_err("value or struct index")?),
|
||||
_ => Err(stream.expecting_err("value or struct index")?),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -534,7 +535,7 @@ impl Parse for BlockLevelStatement {
|
||||
Stmt::Return(ReturnType::Soft, e)
|
||||
}
|
||||
} else {
|
||||
Err(stream.expected_err("expression")?)?
|
||||
Err(stream.expecting_err("expression")?)?
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -605,7 +606,7 @@ impl Parse for TopLevelStatement {
|
||||
range,
|
||||
})
|
||||
}
|
||||
_ => Err(stream.expected_err("import or fn")?)?,
|
||||
_ => Err(stream.expecting_err("import or fn")?)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
ast::{self},
|
||||
mir::{self, NamedVariableRef, StmtKind, StructField, StructType},
|
||||
mir::{self, NamedVariableRef, SourceModuleId, StmtKind, StructField, StructType},
|
||||
};
|
||||
|
||||
impl mir::Context {
|
||||
@ -12,7 +12,7 @@ impl mir::Context {
|
||||
}
|
||||
|
||||
impl ast::Module {
|
||||
pub fn process(&self) -> mir::Module {
|
||||
pub fn process(&self, module_id: SourceModuleId) -> mir::Module {
|
||||
let mut imports = Vec::new();
|
||||
let mut functions = Vec::new();
|
||||
let mut typedefs = Vec::new();
|
||||
@ -21,7 +21,7 @@ impl ast::Module {
|
||||
for stmt in &self.top_level_statements {
|
||||
match stmt {
|
||||
Import(import) => {
|
||||
imports.push(mir::Import(import.0.clone(), import.1.into()));
|
||||
imports.push(mir::Import(import.0.clone(), import.1.as_meta(module_id)));
|
||||
}
|
||||
FunctionDefinition(ast::FunctionDefinition(signature, is_pub, block, range)) => {
|
||||
let def = mir::FunctionDefinition {
|
||||
@ -39,7 +39,10 @@ impl ast::Module {
|
||||
.cloned()
|
||||
.map(|p| (p.0, p.1.into()))
|
||||
.collect(),
|
||||
kind: mir::FunctionDefinitionKind::Local(block.into_mir(), (*range).into()),
|
||||
kind: mir::FunctionDefinitionKind::Local(
|
||||
block.into_mir(module_id),
|
||||
(*range).as_meta(module_id),
|
||||
),
|
||||
};
|
||||
functions.push(def);
|
||||
}
|
||||
@ -75,14 +78,14 @@ impl ast::Module {
|
||||
StructField(
|
||||
s.name.clone(),
|
||||
s.ty.clone().into(),
|
||||
s.range.into(),
|
||||
s.range.as_meta(module_id),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
},
|
||||
meta: (*range).into(),
|
||||
meta: (*range).as_meta(module_id),
|
||||
};
|
||||
typedefs.push(def);
|
||||
}
|
||||
@ -91,6 +94,7 @@ impl ast::Module {
|
||||
|
||||
mir::Module {
|
||||
name: self.name.clone(),
|
||||
module_id: module_id,
|
||||
imports,
|
||||
functions,
|
||||
path: self.path.clone(),
|
||||
@ -101,7 +105,7 @@ impl ast::Module {
|
||||
}
|
||||
|
||||
impl ast::Block {
|
||||
pub fn into_mir(&self) -> mir::Block {
|
||||
pub fn into_mir(&self, module_id: SourceModuleId) -> mir::Block {
|
||||
let mut mir_statements = Vec::new();
|
||||
|
||||
for statement in &self.0 {
|
||||
@ -115,27 +119,31 @@ impl ast::Block {
|
||||
.map(|t| t.0.into())
|
||||
.unwrap_or(mir::TypeKind::Vague(mir::VagueType::Unknown)),
|
||||
s_let.0.clone(),
|
||||
s_let.4.into(),
|
||||
s_let.4.as_meta(module_id),
|
||||
),
|
||||
s_let.2,
|
||||
s_let.3.process(),
|
||||
s_let.3.process(module_id),
|
||||
),
|
||||
s_let.4,
|
||||
),
|
||||
ast::BlockLevelStatement::Set(var_ref, expression, range) => (
|
||||
StmtKind::Set(var_ref.process(), expression.process()),
|
||||
StmtKind::Set(var_ref.process(module_id), expression.process(module_id)),
|
||||
*range,
|
||||
),
|
||||
ast::BlockLevelStatement::Import { _i } => todo!(),
|
||||
ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process()), e.1),
|
||||
ast::BlockLevelStatement::Return(_, e) => (StmtKind::Expression(e.process()), e.1),
|
||||
ast::BlockLevelStatement::Expression(e) => {
|
||||
(StmtKind::Expression(e.process(module_id)), e.1)
|
||||
}
|
||||
ast::BlockLevelStatement::Return(_, e) => {
|
||||
(StmtKind::Expression(e.process(module_id)), e.1)
|
||||
}
|
||||
};
|
||||
|
||||
mir_statements.push(mir::Statement(kind, range.into()));
|
||||
mir_statements.push(mir::Statement(kind, range.as_meta(module_id)));
|
||||
}
|
||||
|
||||
let return_expression = if let Some(r) = &self.1 {
|
||||
Some((r.0.into(), Box::new(r.1.process())))
|
||||
Some((r.0.into(), Box::new(r.1.process(module_id))))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -143,7 +151,7 @@ impl ast::Block {
|
||||
mir::Block {
|
||||
statements: mir_statements,
|
||||
return_expression,
|
||||
meta: self.2.into(),
|
||||
meta: self.2.as_meta(module_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,61 +166,67 @@ impl From<ast::ReturnType> for mir::ReturnKind {
|
||||
}
|
||||
|
||||
impl ast::Expression {
|
||||
fn process(&self) -> mir::Expression {
|
||||
fn process(&self, module_id: SourceModuleId) -> mir::Expression {
|
||||
let kind = match &self.0 {
|
||||
ast::ExpressionKind::VariableName(name) => mir::ExprKind::Variable(NamedVariableRef(
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
name.clone(),
|
||||
self.1.into(),
|
||||
self.1.as_meta(module_id),
|
||||
)),
|
||||
ast::ExpressionKind::Literal(literal) => mir::ExprKind::Literal(literal.mir()),
|
||||
ast::ExpressionKind::Binop(binary_operator, lhs, rhs) => mir::ExprKind::BinOp(
|
||||
binary_operator.mir(),
|
||||
Box::new(lhs.process()),
|
||||
Box::new(rhs.process()),
|
||||
Box::new(lhs.process(module_id)),
|
||||
Box::new(rhs.process(module_id)),
|
||||
),
|
||||
ast::ExpressionKind::FunctionCall(fn_call_expr) => {
|
||||
mir::ExprKind::FunctionCall(mir::FunctionCall {
|
||||
name: fn_call_expr.0.clone(),
|
||||
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
parameters: fn_call_expr.1.iter().map(|e| e.process()).collect(),
|
||||
parameters: fn_call_expr
|
||||
.1
|
||||
.iter()
|
||||
.map(|e| e.process(module_id))
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
ast::ExpressionKind::BlockExpr(block) => mir::ExprKind::Block(block.into_mir()),
|
||||
ast::ExpressionKind::BlockExpr(block) => {
|
||||
mir::ExprKind::Block(block.into_mir(module_id))
|
||||
}
|
||||
ast::ExpressionKind::IfExpr(if_expression) => {
|
||||
let cond = if_expression.0.process();
|
||||
let then_block = if_expression.1.into_mir();
|
||||
let cond = if_expression.0.process(module_id);
|
||||
let then_block = if_expression.1.into_mir(module_id);
|
||||
let else_block = if let Some(el) = &if_expression.2 {
|
||||
Some(el.into_mir())
|
||||
Some(el.into_mir(module_id))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
mir::ExprKind::If(mir::IfExpression(Box::new(cond), then_block, else_block))
|
||||
}
|
||||
ast::ExpressionKind::Array(expressions) => {
|
||||
mir::ExprKind::Array(expressions.iter().map(|e| e.process()).collect())
|
||||
mir::ExprKind::Array(expressions.iter().map(|e| e.process(module_id)).collect())
|
||||
}
|
||||
ast::ExpressionKind::Indexed(expression, idx_expr) => mir::ExprKind::Indexed(
|
||||
Box::new(expression.process()),
|
||||
Box::new(expression.process(module_id)),
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
Box::new(idx_expr.process()),
|
||||
Box::new(idx_expr.process(module_id)),
|
||||
),
|
||||
ast::ExpressionKind::StructExpression(struct_init) => mir::ExprKind::Struct(
|
||||
struct_init.name.clone(),
|
||||
struct_init
|
||||
.fields
|
||||
.iter()
|
||||
.map(|(n, e)| (n.clone(), e.process()))
|
||||
.map(|(n, e)| (n.clone(), e.process(module_id)))
|
||||
.collect(),
|
||||
),
|
||||
ast::ExpressionKind::Accessed(expression, name) => mir::ExprKind::Accessed(
|
||||
Box::new(expression.process()),
|
||||
Box::new(expression.process(module_id)),
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
name.clone(),
|
||||
),
|
||||
};
|
||||
|
||||
mir::Expression(kind, self.1.into())
|
||||
mir::Expression(kind, self.1.as_meta(module_id))
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,7 +275,7 @@ impl From<ast::TypeKind> for mir::TypeKind {
|
||||
mir::TypeKind::Array(Box::new(mir::TypeKind::from(*type_kind.clone())), *length)
|
||||
}
|
||||
ast::TypeKind::String => mir::TypeKind::StringPtr,
|
||||
ast::TypeKind::Custom(_) => todo!("Add processing for custom types"),
|
||||
ast::TypeKind::Custom(name) => mir::TypeKind::CustomType(name.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,24 +68,6 @@ pub enum StackValueKind {
|
||||
Any(InstructionValue),
|
||||
}
|
||||
|
||||
impl StackValueKind {
|
||||
unsafe fn get_instr(&self) -> &InstructionValue {
|
||||
match self {
|
||||
StackValueKind::Immutable(val) => val,
|
||||
StackValueKind::Mutable(val) => val,
|
||||
StackValueKind::Any(val) => val,
|
||||
}
|
||||
}
|
||||
|
||||
fn with_instr(&self, instr: InstructionValue) -> StackValueKind {
|
||||
match self {
|
||||
StackValueKind::Immutable(_) => StackValueKind::Immutable(instr),
|
||||
StackValueKind::Mutable(_) => StackValueKind::Mutable(instr),
|
||||
StackValueKind::Any(_) => StackValueKind::Any(instr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx, 'a> Scope<'ctx, 'a> {
|
||||
fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> {
|
||||
Scope {
|
||||
|
335
reid/src/error_raporting.rs
Normal file
335
reid/src/error_raporting.rs
Normal file
@ -0,0 +1,335 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::{Debug, Write},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
lexer::{self, Cursor, FullToken, Position},
|
||||
mir::{self, pass, Metadata, SourceModuleId},
|
||||
token_stream::{self, TokenRange},
|
||||
};
|
||||
|
||||
impl<T: std::error::Error + std::fmt::Display> pass::Error<T> {
|
||||
fn fmt_simple(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.kind, f)
|
||||
}
|
||||
}
|
||||
|
||||
fn label(text: &str) -> &str {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
return text;
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
""
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ErrorKind {
|
||||
#[error("{}{}", label("(Lexing) "), .0.kind)]
|
||||
LexerError(#[from] mir::pass::Error<lexer::Error>),
|
||||
#[error("{}{}", label("(Parsing) "), .0.kind)]
|
||||
ParserError(#[from] mir::pass::Error<token_stream::Error>),
|
||||
#[error("{}{}", label("(TypeCheck) "), .0.kind)]
|
||||
TypeCheckError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>),
|
||||
#[error("{}{}", label("(TypeInference) "), .0.kind)]
|
||||
TypeInferenceError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>),
|
||||
#[error("{}{}", label("(Linker) "), .0.kind)]
|
||||
LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>),
|
||||
}
|
||||
|
||||
impl ErrorKind {
|
||||
pub fn from_typecheck(err: mir::pass::Error<mir::typecheck::ErrorKind>) -> ErrorKind {
|
||||
ErrorKind::TypeCheckError(err)
|
||||
}
|
||||
|
||||
pub fn from_typeinference(err: mir::pass::Error<mir::typecheck::ErrorKind>) -> ErrorKind {
|
||||
ErrorKind::TypeInferenceError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl ErrorKind {
|
||||
fn get_meta(&self) -> Metadata {
|
||||
match &self {
|
||||
ErrorKind::LexerError(error) => error.metadata,
|
||||
ErrorKind::ParserError(error) => error.metadata,
|
||||
ErrorKind::TypeCheckError(error) => error.metadata,
|
||||
ErrorKind::TypeInferenceError(error) => error.metadata,
|
||||
ErrorKind::LinkerError(error) => error.metadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ErrorKind {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.get_meta()
|
||||
.source_module_id
|
||||
.partial_cmp(&other.get_meta().source_module_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ErrorKind {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.get_meta().cmp(&other.get_meta())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ErrModule {
|
||||
pub name: String,
|
||||
pub tokens: Option<Vec<FullToken>>,
|
||||
pub source: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct ModuleMap {
|
||||
module_map: HashMap<mir::SourceModuleId, ErrModule>,
|
||||
module_counter: mir::SourceModuleId,
|
||||
}
|
||||
|
||||
impl ModuleMap {
|
||||
pub fn add_module<T: Into<String>>(&mut self, name: T) -> Option<mir::SourceModuleId> {
|
||||
let id = self.module_counter.increment();
|
||||
self.module_map.insert(
|
||||
id,
|
||||
ErrModule {
|
||||
name: name.into(),
|
||||
tokens: None,
|
||||
source: None,
|
||||
},
|
||||
);
|
||||
Some(id)
|
||||
}
|
||||
|
||||
pub fn set_tokens(&mut self, id: mir::SourceModuleId, tokens: Vec<FullToken>) {
|
||||
if let Some(module) = self.module_map.get_mut(&id) {
|
||||
module.tokens = Some(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_source(&mut self, id: mir::SourceModuleId, source: String) {
|
||||
if let Some(module) = self.module_map.get_mut(&id) {
|
||||
module.source = Some(source);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_module(&self, id: &mir::SourceModuleId) -> Option<&ErrModule> {
|
||||
self.module_map.get(id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ReidError {
|
||||
map: ModuleMap,
|
||||
errors: Vec<ErrorKind>,
|
||||
}
|
||||
|
||||
impl ReidError {
|
||||
pub fn from_lexer<U>(
|
||||
result: Result<U, lexer::Error>,
|
||||
map: ModuleMap,
|
||||
module: SourceModuleId,
|
||||
) -> Result<U, ReidError> {
|
||||
result.map_err(|error| {
|
||||
let pass_err = pass::Error {
|
||||
metadata: Metadata {
|
||||
source_module_id: module,
|
||||
range: Default::default(),
|
||||
position: Some(*error.get_position()),
|
||||
},
|
||||
kind: error,
|
||||
};
|
||||
ReidError {
|
||||
map,
|
||||
errors: vec![ErrorKind::LexerError(pass_err)],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_parser<U>(
|
||||
result: Result<U, token_stream::Error>,
|
||||
map: ModuleMap,
|
||||
module: SourceModuleId,
|
||||
) -> Result<U, ReidError> {
|
||||
result.map_err(|error| {
|
||||
let pass_err = pass::Error {
|
||||
metadata: Metadata {
|
||||
source_module_id: module,
|
||||
range: *error.get_range().unwrap_or(&Default::default()),
|
||||
position: None,
|
||||
},
|
||||
kind: error,
|
||||
};
|
||||
ReidError {
|
||||
map,
|
||||
errors: vec![ErrorKind::ParserError(pass_err)],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_kind<U>(errors: Vec<ErrorKind>, map: ModuleMap) -> ReidError {
|
||||
ReidError { map, errors }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ReidError {}
|
||||
|
||||
impl std::fmt::Display for ReidError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut sorted_errors = self.errors.clone();
|
||||
sorted_errors.sort_by(|a, b| a.cmp(&b));
|
||||
sorted_errors.dedup();
|
||||
|
||||
let mut curr_module = None;
|
||||
for error in sorted_errors {
|
||||
let meta = error.get_meta();
|
||||
let module = self.map.get_module(&meta.source_module_id).unwrap();
|
||||
let position = if let Some(tokens) = &module.tokens {
|
||||
let range_tokens = meta.range.into_tokens(&tokens);
|
||||
|
||||
dbg!(&error);
|
||||
dbg!(&meta.range, &tokens[meta.range.start]);
|
||||
get_position(&range_tokens).or(meta.position.map(|p| (p, p)))
|
||||
} else if let Some(position) = meta.position {
|
||||
Some((position, position))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if curr_module != Some(meta.source_module_id) {
|
||||
curr_module = Some(meta.source_module_id);
|
||||
writeln!(
|
||||
f,
|
||||
"Errors in module {}:",
|
||||
color_err(format!(
|
||||
"{}",
|
||||
self.map
|
||||
.module_map
|
||||
.get(&meta.source_module_id)
|
||||
.unwrap()
|
||||
.name
|
||||
))?
|
||||
)?;
|
||||
}
|
||||
writeln!(f)?;
|
||||
write!(f, " Error: ")?;
|
||||
writeln!(f, "{}", color_err(format!("{}", error))?)?;
|
||||
write!(
|
||||
f,
|
||||
"{:>20}{}",
|
||||
color_warn("At: ")?,
|
||||
position
|
||||
.map(|p| fmt_positions(p))
|
||||
.unwrap_or(String::from("{unknown}")),
|
||||
)?;
|
||||
if let (Some(position), Some(source)) = (position, &module.source) {
|
||||
writeln!(f, "{}", fmt_lines(source, position, 6)?)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl TokenRange {
|
||||
pub fn into_tokens<'v>(&self, tokens: &'v Vec<FullToken>) -> Vec<&'v FullToken> {
|
||||
tokens
|
||||
.iter()
|
||||
.skip(self.start)
|
||||
.by_ref()
|
||||
.take(self.end + 1 - self.start)
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_position(tokens: &Vec<&FullToken>) -> Option<(Position, Position)> {
|
||||
if let Some(first) = tokens.first() {
|
||||
let last = tokens.last().unwrap();
|
||||
Some((first.position, last.position.add(last.token.len() as u32)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn into_full_lines<'v>((start, end): (Position, Position)) -> (Position, Position) {
|
||||
(Position(0, start.1), Position(u32::MAX, end.1))
|
||||
}
|
||||
|
||||
fn fmt_lines(
|
||||
source: &String,
|
||||
(highlight_start, highlight_end): (Position, Position),
|
||||
ident: usize,
|
||||
) -> Result<String, std::fmt::Error> {
|
||||
let (line_start, line_end) = into_full_lines((highlight_start, highlight_end));
|
||||
let mut cursor = Cursor {
|
||||
position: Position(0, 1),
|
||||
char_stream: source.chars(),
|
||||
};
|
||||
|
||||
let mut text = String::new();
|
||||
|
||||
while let Some(c) = cursor.next() {
|
||||
if cursor.position.1 > line_end.1 {
|
||||
break;
|
||||
}
|
||||
if cursor.position.1 >= line_start.1 {
|
||||
if c == '\n' {
|
||||
write!(text, "\n{}", " ".repeat(ident))?;
|
||||
} else {
|
||||
if cursor.position > highlight_start && cursor.position <= highlight_end {
|
||||
write!(text, "{}", color_highlight(c)?)?;
|
||||
} else {
|
||||
text.write_char(c)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(text)
|
||||
}
|
||||
|
||||
fn fmt_positions((start, end): (Position, Position)) -> String {
|
||||
if start == end {
|
||||
format!("ln {}, col {}", start.1, start.0)
|
||||
} else if start.1 == end.1 {
|
||||
format!("ln {}, col {}-{}", start.1, start.0, end.0)
|
||||
} else {
|
||||
format!("{}:{} - {}:{}", start.1, start.0, end.1, end.0)
|
||||
}
|
||||
}
|
||||
|
||||
fn color_err(elem: impl std::fmt::Display) -> Result<String, std::fmt::Error> {
|
||||
let mut text = format!("{}", elem);
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
{
|
||||
use colored::Colorize;
|
||||
text = format!("{}", text.bright_red())
|
||||
}
|
||||
|
||||
Ok(text)
|
||||
}
|
||||
|
||||
fn color_warn(elem: impl std::fmt::Display) -> Result<String, std::fmt::Error> {
|
||||
let mut text = format!("{}", elem);
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
{
|
||||
use colored::Colorize;
|
||||
text = format!("{}", text.bright_yellow())
|
||||
}
|
||||
|
||||
Ok(text)
|
||||
}
|
||||
|
||||
fn color_highlight(elem: impl std::fmt::Display) -> Result<String, std::fmt::Error> {
|
||||
let mut text = format!("{}", elem);
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
{
|
||||
use colored::Colorize;
|
||||
text = format!("{}", text.bright_yellow().underline())
|
||||
}
|
||||
|
||||
Ok(text)
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
use std::{fmt::Debug, str::Chars};
|
||||
use std::{
|
||||
fmt::{Debug, Write},
|
||||
str::Chars,
|
||||
};
|
||||
|
||||
static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
#[derive(Debug, Eq, PartialEq, Clone, PartialOrd, Ord)]
|
||||
pub enum Token {
|
||||
/// Values
|
||||
Identifier(String),
|
||||
@ -99,8 +102,56 @@ impl From<Token> for String {
|
||||
}
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub fn len(&self) -> usize {
|
||||
self.to_string().len()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for Token {
|
||||
fn to_string(&self) -> String {
|
||||
match &self {
|
||||
Token::Identifier(ident) => ident.clone(),
|
||||
Token::DecimalValue(val) => val.to_string(),
|
||||
Token::StringLit(lit) => format!("\"{}\"", lit),
|
||||
Token::LetKeyword => String::from("let"),
|
||||
Token::MutKeyword => String::from("mut"),
|
||||
Token::ImportKeyword => String::from("import"),
|
||||
Token::ReturnKeyword => String::from("return"),
|
||||
Token::FnKeyword => String::from("fn"),
|
||||
Token::PubKeyword => String::from("pub"),
|
||||
Token::Arrow => String::from("=>"),
|
||||
Token::If => String::from("if"),
|
||||
Token::Else => String::from("else"),
|
||||
Token::True => String::from("true"),
|
||||
Token::False => String::from("false"),
|
||||
Token::Extern => String::from("extern"),
|
||||
Token::Struct => String::from("struct"),
|
||||
Token::Semi => String::from(';'),
|
||||
Token::Equals => String::from('='),
|
||||
Token::Colon => String::from(':'),
|
||||
Token::Plus => String::from('+'),
|
||||
Token::Times => String::from('*'),
|
||||
Token::Minus => String::from('-'),
|
||||
Token::GreaterThan => String::from('>'),
|
||||
Token::LessThan => String::from('<'),
|
||||
Token::Et => String::from('&'),
|
||||
Token::Exclamation => String::from('!'),
|
||||
Token::ParenOpen => String::from('('),
|
||||
Token::ParenClose => String::from(')'),
|
||||
Token::BraceOpen => String::from('{'),
|
||||
Token::BraceClose => String::from('}'),
|
||||
Token::BracketOpen => String::from('['),
|
||||
Token::BracketClose => String::from(']'),
|
||||
Token::Comma => String::from(','),
|
||||
Token::Dot => String::from('.'),
|
||||
Token::Eof => String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A token with a position
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct FullToken {
|
||||
pub token: Token,
|
||||
pub position: Position,
|
||||
@ -115,15 +166,37 @@ impl Debug for FullToken {
|
||||
}
|
||||
}
|
||||
|
||||
pub type Position = (u32, u32);
|
||||
/// (Column, Line)
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Ord)]
|
||||
pub struct Position(pub u32, pub u32);
|
||||
|
||||
struct Cursor<'a> {
|
||||
impl Position {
|
||||
pub fn add(&self, num: u32) -> Position {
|
||||
Position(self.0 + num, self.1)
|
||||
}
|
||||
|
||||
pub fn sub(&self, num: u32) -> Position {
|
||||
Position(self.0 - num, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Position {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
match self.1.partial_cmp(&other.1) {
|
||||
Some(core::cmp::Ordering::Equal) => {}
|
||||
ord => return ord,
|
||||
}
|
||||
self.0.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Cursor<'a> {
|
||||
pub position: Position,
|
||||
char_stream: Chars<'a>,
|
||||
pub char_stream: Chars<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Cursor<'a> {
|
||||
fn next(&mut self) -> Option<char> {
|
||||
pub fn next(&mut self) -> Option<char> {
|
||||
let next = self.char_stream.next();
|
||||
if let Some('\n') = next {
|
||||
self.position.1 += 1;
|
||||
@ -153,14 +226,14 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
||||
let to_tokenize = to_tokenize.into();
|
||||
let mut cursor = Cursor {
|
||||
char_stream: to_tokenize.chars(),
|
||||
position: (0, 1),
|
||||
position: Position(0, 1),
|
||||
};
|
||||
|
||||
let mut tokens = Vec::new();
|
||||
|
||||
while let Some(character) = &cursor.next() {
|
||||
// Save "current" token first character position
|
||||
let position = (cursor.position.0 - 1, cursor.position.1);
|
||||
let position = cursor.position.sub(1);
|
||||
|
||||
let variant = match character {
|
||||
// Whitespace
|
||||
@ -273,10 +346,19 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Error {
|
||||
#[error("Invalid token '{}' at Ln {}, Col {}", .0, (.1).1, (.1).0)]
|
||||
#[error("Invalid token '{}' ", .0)]
|
||||
InvalidToken(char, Position),
|
||||
#[error("String literal that starts at Ln {}, Col {} is never finished!", (.0).1, (.0).0)]
|
||||
#[error("String literal is never finished!")]
|
||||
MissingQuotation(Position),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn get_position(&self) -> &Position {
|
||||
match self {
|
||||
Error::InvalidToken(_, pos) => pos,
|
||||
Error::MissingQuotation(pos) => pos,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
115
reid/src/lib.rs
115
reid/src/lib.rs
@ -41,10 +41,13 @@
|
||||
//! - Debug Symbols
|
||||
//! ```
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::{convert::Infallible, path::PathBuf};
|
||||
|
||||
use error_raporting::{ErrorKind as ErrorRapKind, ModuleMap, ReidError};
|
||||
use lexer::FullToken;
|
||||
use mir::{
|
||||
linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
|
||||
SourceModuleId,
|
||||
};
|
||||
use reid_lib::{compile::CompileOutput, Context};
|
||||
|
||||
@ -52,64 +55,74 @@ use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream};
|
||||
|
||||
mod ast;
|
||||
mod codegen;
|
||||
mod error_raporting;
|
||||
mod lexer;
|
||||
pub mod mir;
|
||||
mod pad_adapter;
|
||||
mod token_stream;
|
||||
mod util;
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
pub enum ReidError {
|
||||
#[error(transparent)]
|
||||
LexerError(#[from] lexer::Error),
|
||||
#[error(transparent)]
|
||||
ParserError(#[from] token_stream::Error),
|
||||
#[error("Errors during typecheck: {0:?}")]
|
||||
TypeCheckErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>),
|
||||
#[error("Errors during type inference: {0:?}")]
|
||||
TypeInferenceErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>),
|
||||
#[error("Errors during linking: {0:?}")]
|
||||
LinkerErrors(Vec<mir::pass::Error<mir::linker::ErrorKind>>),
|
||||
}
|
||||
|
||||
pub fn compile_module(
|
||||
pub fn parse_module<'map, T: Into<String>>(
|
||||
source: &str,
|
||||
name: String,
|
||||
path: Option<PathBuf>,
|
||||
is_main: bool,
|
||||
) -> Result<mir::Module, ReidError> {
|
||||
let tokens = lexer::tokenize(source)?;
|
||||
name: T,
|
||||
map: &'map mut ModuleMap,
|
||||
) -> Result<(mir::SourceModuleId, Vec<FullToken>), ReidError> {
|
||||
let id = map.add_module(name.into()).unwrap();
|
||||
map.set_source(id, source.to_owned());
|
||||
|
||||
let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?;
|
||||
|
||||
map.set_tokens(id, tokens.clone());
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(&tokens);
|
||||
|
||||
Ok((id, tokens))
|
||||
}
|
||||
|
||||
pub fn compile_module<'map>(
|
||||
module_id: mir::SourceModuleId,
|
||||
tokens: &Vec<FullToken>,
|
||||
map: &'map mut ModuleMap,
|
||||
path: Option<PathBuf>,
|
||||
is_main: bool,
|
||||
) -> Result<mir::Module, ReidError> {
|
||||
let module = map.get_module(&module_id).cloned().unwrap();
|
||||
|
||||
let mut token_stream = TokenStream::from(&tokens);
|
||||
|
||||
let mut statements = Vec::new();
|
||||
|
||||
while !matches!(token_stream.peek().unwrap_or(Token::Eof), Token::Eof) {
|
||||
let statement = token_stream.parse::<TopLevelStatement>()?;
|
||||
let statement = ReidError::from_parser(
|
||||
token_stream.parse::<TopLevelStatement>(),
|
||||
map.clone(),
|
||||
module_id,
|
||||
)?;
|
||||
statements.push(statement);
|
||||
}
|
||||
|
||||
let ast_module = ast::Module {
|
||||
name,
|
||||
name: module.name,
|
||||
top_level_statements: statements,
|
||||
path,
|
||||
is_main,
|
||||
};
|
||||
|
||||
Ok(ast_module.process())
|
||||
Ok(ast_module.process(module_id))
|
||||
}
|
||||
|
||||
pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
||||
pub fn perform_all_passes<'map>(
|
||||
context: &mut mir::Context,
|
||||
module_map: &'map mut ModuleMap,
|
||||
) -> Result<(), ReidError> {
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(&context);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &context);
|
||||
|
||||
let state = context.pass(&mut LinkerPass);
|
||||
let state = context.pass(&mut LinkerPass { module_map });
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &context);
|
||||
@ -117,7 +130,10 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
||||
dbg!(&state);
|
||||
|
||||
if !state.errors.is_empty() {
|
||||
return Err(ReidError::LinkerErrors(state.errors));
|
||||
return Err(ReidError::from_kind::<()>(
|
||||
state.errors.iter().map(|e| e.clone().into()).collect(),
|
||||
module_map.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
let refs = TypeRefs::default();
|
||||
@ -132,7 +148,14 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
||||
dbg!(&state);
|
||||
|
||||
if !state.errors.is_empty() {
|
||||
return Err(ReidError::TypeInferenceErrors(state.errors));
|
||||
return Err(ReidError::from_kind::<()>(
|
||||
state
|
||||
.errors
|
||||
.iter()
|
||||
.map(|e| ErrorRapKind::TypeInferenceError(e.clone()))
|
||||
.collect::<Vec<_>>(),
|
||||
module_map.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
let state = context.pass(&mut TypeCheck { refs: &refs });
|
||||
@ -143,7 +166,14 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
||||
dbg!(&state);
|
||||
|
||||
if !state.errors.is_empty() {
|
||||
return Err(ReidError::TypeCheckErrors(state.errors));
|
||||
return Err(ReidError::from_kind::<()>(
|
||||
state
|
||||
.errors
|
||||
.iter()
|
||||
.map(|e| ErrorRapKind::TypeCheckError(e.clone()))
|
||||
.collect::<Vec<_>>(),
|
||||
module_map.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -152,20 +182,20 @@ pub fn perform_all_passes(context: &mut mir::Context) -> Result<(), ReidError> {
|
||||
/// Takes in a bit of source code, parses and compiles it and produces `hello.o`
|
||||
/// and `hello.asm` from it, which can be linked using `ld` to produce an
|
||||
/// executable file.
|
||||
pub fn compile(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError> {
|
||||
pub fn compile_and_pass<'map>(
|
||||
source: &str,
|
||||
path: PathBuf,
|
||||
module_map: &'map mut ModuleMap,
|
||||
) -> Result<CompileOutput, ReidError> {
|
||||
let path = path.canonicalize().unwrap();
|
||||
let name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
||||
|
||||
let mut mir_context = mir::Context::from(
|
||||
vec![compile_module(
|
||||
source,
|
||||
path.file_name().unwrap().to_str().unwrap().to_owned(),
|
||||
Some(path.clone()),
|
||||
true,
|
||||
)?],
|
||||
path.parent().unwrap().to_owned(),
|
||||
);
|
||||
let (id, tokens) = parse_module(source, name, module_map).unwrap();
|
||||
let module = compile_module(id, &tokens, module_map, Some(path.clone()), true)?;
|
||||
|
||||
perform_all_passes(&mut mir_context)?;
|
||||
let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned());
|
||||
|
||||
perform_all_passes(&mut mir_context, module_map)?;
|
||||
|
||||
let mut context = Context::new();
|
||||
let codegen_modules = mir_context.codegen(&mut context);
|
||||
@ -176,3 +206,8 @@ pub fn compile(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError>
|
||||
let compiled = codegen_modules.compile();
|
||||
Ok(compiled.output())
|
||||
}
|
||||
|
||||
pub fn compile_simple(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError> {
|
||||
let mut map = ModuleMap::default();
|
||||
compile_and_pass(source, path, &mut map)
|
||||
}
|
||||
|
@ -289,7 +289,13 @@ impl Display for CmpOperator {
|
||||
|
||||
impl Display for Metadata {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.range)
|
||||
write!(f, "{:?} ({})", self.range, self.source_module_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SourceModuleId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Mod {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,7 +279,7 @@ impl TypeKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, thiserror::Error)]
|
||||
#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum EqualsIssue {
|
||||
#[error("Function is already defined locally at {:?}", (.0).range)]
|
||||
ExistsLocally(Metadata),
|
||||
|
@ -2,30 +2,29 @@ use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
convert::Infallible,
|
||||
fmt::Error,
|
||||
fs::{self},
|
||||
path::PathBuf,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use crate::{compile_module, ReidError};
|
||||
use crate::{compile_module, error_raporting::ModuleMap, lexer::FullToken, parse_module};
|
||||
|
||||
use super::{
|
||||
pass::{Pass, PassState},
|
||||
r#impl::EqualsIssue,
|
||||
Context, FunctionDefinition, Import, Metadata, Module,
|
||||
Context, FunctionDefinition, Import, Metadata, Module, SourceModuleId,
|
||||
};
|
||||
|
||||
pub static STD_SOURCE: &str = include_str!("../../lib/std.reid");
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum ErrorKind {
|
||||
#[error("Unable to import inner modules, not yet supported: {0}")]
|
||||
InnerModulesNotYetSupported(Import),
|
||||
#[error("No such module: {0}")]
|
||||
ModuleNotFound(String),
|
||||
#[error("Error while compiling module {0}: {1}")]
|
||||
ModuleCompilationError(String, ReidError),
|
||||
ModuleCompilationError(String, String),
|
||||
#[error("No such function {0} found in module {1}")]
|
||||
NoSuchFunctionInModule(String, String),
|
||||
#[error("Importing function {0}::{1} not possible: {2}")]
|
||||
@ -42,22 +41,25 @@ pub enum ErrorKind {
|
||||
FunctionIsPrivate(String, String),
|
||||
}
|
||||
|
||||
pub fn compile_std() -> super::Module {
|
||||
let module = compile_module(STD_SOURCE, "standard_library".to_owned(), None, false).unwrap();
|
||||
pub fn compile_std(module_map: &mut ModuleMap) -> (super::Module, Vec<FullToken>) {
|
||||
let (id, tokens) = parse_module(STD_SOURCE, "standard_library", module_map).unwrap();
|
||||
let module = compile_module(id, &tokens, module_map, None, false).unwrap();
|
||||
|
||||
let mut mir_context = super::Context::from(vec![module], Default::default());
|
||||
|
||||
let std_compiled = mir_context.modules.remove(0);
|
||||
std_compiled
|
||||
(std_compiled, tokens)
|
||||
}
|
||||
|
||||
/// Struct used to implement a type-checking pass that can be performed on the
|
||||
/// MIR.
|
||||
pub struct LinkerPass;
|
||||
pub struct LinkerPass<'map> {
|
||||
pub module_map: &'map mut ModuleMap,
|
||||
}
|
||||
|
||||
type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
|
||||
|
||||
impl Pass for LinkerPass {
|
||||
impl<'map> Pass for LinkerPass<'map> {
|
||||
type Data = ();
|
||||
type TError = ErrorKind;
|
||||
fn context(&mut self, context: &mut Context, mut state: LinkerPassState) {
|
||||
@ -80,20 +82,31 @@ impl Pass for LinkerPass {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut modules = HashMap::<String, Rc<RefCell<Module>>>::new();
|
||||
let mut modules = HashMap::<String, Rc<RefCell<_>>>::new();
|
||||
|
||||
for module in context.modules.drain(..) {
|
||||
modules.insert(module.name.clone(), Rc::new(RefCell::new(module)));
|
||||
let tokens = self
|
||||
.module_map
|
||||
.get_module(&module.module_id)
|
||||
.unwrap()
|
||||
.tokens
|
||||
.clone()
|
||||
.unwrap();
|
||||
modules.insert(module.name.clone(), Rc::new(RefCell::new((module, tokens))));
|
||||
}
|
||||
|
||||
modules.insert("std".to_owned(), Rc::new(RefCell::new(compile_std())));
|
||||
modules.insert(
|
||||
"std".to_owned(),
|
||||
Rc::new(RefCell::new(compile_std(&mut self.module_map))),
|
||||
);
|
||||
|
||||
let mut modules_to_process: Vec<Rc<RefCell<Module>>> = modules.values().cloned().collect();
|
||||
let mut modules_to_process: Vec<Rc<RefCell<(Module, Vec<FullToken>)>>> =
|
||||
modules.values().cloned().collect();
|
||||
|
||||
while let Some(module) = modules_to_process.pop() {
|
||||
let mut importer_module = module.borrow_mut();
|
||||
|
||||
for import in importer_module.imports.clone() {
|
||||
for import in importer_module.0.imports.clone() {
|
||||
let Import(path, _) = &import;
|
||||
if path.len() != 2 {
|
||||
state.ok::<_, Infallible>(
|
||||
@ -118,7 +131,23 @@ impl Pass for LinkerPass {
|
||||
continue;
|
||||
};
|
||||
|
||||
match compile_module(&source, module_name.clone(), Some(file_path), false) {
|
||||
let (id, tokens) =
|
||||
match parse_module(&source, module_name.clone(), &mut self.module_map) {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::ModuleCompilationError(
|
||||
module_name.clone(),
|
||||
format!("{}", err),
|
||||
)),
|
||||
import.1,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match compile_module(id, &tokens, &mut self.module_map, Some(file_path), false)
|
||||
{
|
||||
Ok(imported_module) => {
|
||||
if imported_module.is_main {
|
||||
state.ok::<_, Infallible>(
|
||||
@ -130,7 +159,7 @@ impl Pass for LinkerPass {
|
||||
let module_name = imported_module.name.clone();
|
||||
modules.insert(
|
||||
module_name.clone(),
|
||||
Rc::new(RefCell::new(imported_module)),
|
||||
Rc::new(RefCell::new((imported_module, tokens))),
|
||||
);
|
||||
let imported = modules.get_mut(&module_name).unwrap();
|
||||
modules_to_process.push(imported.clone());
|
||||
@ -138,7 +167,10 @@ impl Pass for LinkerPass {
|
||||
}
|
||||
Err(err) => {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::ModuleCompilationError(module_name.clone(), err)),
|
||||
Err(ErrorKind::ModuleCompilationError(
|
||||
module_name.clone(),
|
||||
format!("{}", err),
|
||||
)),
|
||||
import.1,
|
||||
);
|
||||
continue;
|
||||
@ -149,7 +181,11 @@ impl Pass for LinkerPass {
|
||||
|
||||
let func_name = unsafe { path.get_unchecked(1) };
|
||||
|
||||
let Some(func) = imported.functions.iter_mut().find(|f| f.name == *func_name)
|
||||
let Some(func) = imported
|
||||
.0
|
||||
.functions
|
||||
.iter_mut()
|
||||
.find(|f| f.name == *func_name)
|
||||
else {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::NoSuchFunctionInModule(
|
||||
@ -175,6 +211,7 @@ impl Pass for LinkerPass {
|
||||
func.is_imported = true;
|
||||
|
||||
if let Some(existing) = importer_module
|
||||
.0
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.name == *func_name)
|
||||
@ -191,7 +228,7 @@ impl Pass for LinkerPass {
|
||||
}
|
||||
}
|
||||
|
||||
importer_module.functions.push(FunctionDefinition {
|
||||
importer_module.0.functions.push(FunctionDefinition {
|
||||
name: func.name.clone(),
|
||||
is_pub: false,
|
||||
is_imported: false,
|
||||
@ -204,7 +241,7 @@ impl Pass for LinkerPass {
|
||||
|
||||
context.modules = modules
|
||||
.into_values()
|
||||
.map(|v| Rc::into_inner(v).unwrap().into_inner())
|
||||
.map(|v| Rc::into_inner(v).unwrap().into_inner().0)
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use crate::token_stream::TokenRange;
|
||||
use crate::{
|
||||
lexer::{FullToken, Position},
|
||||
token_stream::TokenRange,
|
||||
};
|
||||
|
||||
mod display;
|
||||
pub mod r#impl;
|
||||
@ -14,28 +17,54 @@ pub mod typecheck;
|
||||
pub mod typeinference;
|
||||
pub mod typerefs;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
|
||||
pub struct SourceModuleId(u32);
|
||||
|
||||
impl SourceModuleId {
|
||||
pub fn increment(&mut self) -> SourceModuleId {
|
||||
self.0 += 1;
|
||||
SourceModuleId(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Metadata {
|
||||
pub source_module_id: SourceModuleId,
|
||||
pub range: TokenRange,
|
||||
pub position: Option<Position>,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub fn complete_overlap(&self, other: &Metadata) -> bool {
|
||||
(self.range.start >= other.range.start && self.range.end <= other.range.end)
|
||||
|| (other.range.start >= self.range.start && other.range.end <= self.range.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Add for Metadata {
|
||||
type Output = Metadata;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
assert!(self.source_module_id == rhs.source_module_id);
|
||||
Metadata {
|
||||
range: self.range + rhs.range,
|
||||
source_module_id: self.source_module_id,
|
||||
position: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TokenRange> for Metadata {
|
||||
fn from(value: TokenRange) -> Self {
|
||||
Metadata { range: value }
|
||||
impl TokenRange {
|
||||
pub fn as_meta(self, module: SourceModuleId) -> Metadata {
|
||||
Metadata {
|
||||
range: self,
|
||||
source_module_id: module,
|
||||
position: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, PartialOrd, Ord)]
|
||||
pub enum TypeKind {
|
||||
#[error("bool")]
|
||||
Bool,
|
||||
@ -73,7 +102,7 @@ pub enum TypeKind {
|
||||
Vague(#[from] VagueType),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error, PartialOrd, Ord)]
|
||||
pub enum VagueType {
|
||||
#[error("Unknown")]
|
||||
Unknown,
|
||||
@ -109,7 +138,7 @@ impl TypeKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Literal {
|
||||
I8(i8),
|
||||
I16(i16),
|
||||
@ -126,7 +155,7 @@ pub enum Literal {
|
||||
Vague(VagueLiteral),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum VagueLiteral {
|
||||
Number(u64),
|
||||
}
|
||||
@ -188,7 +217,7 @@ pub enum ReturnKind {
|
||||
#[derive(Debug)]
|
||||
pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Import(pub Vec<String>, pub Metadata);
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -240,14 +269,14 @@ pub enum FunctionDefinitionKind {
|
||||
impl FunctionDefinition {
|
||||
fn block_meta(&self) -> Metadata {
|
||||
match &self.kind {
|
||||
FunctionDefinitionKind::Local(block, _) => block.meta,
|
||||
FunctionDefinitionKind::Local(block, _) => block.meta.clone(),
|
||||
FunctionDefinitionKind::Extern(_) => Metadata::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn signature(&self) -> Metadata {
|
||||
match &self.kind {
|
||||
FunctionDefinitionKind::Local(_, metadata) => *metadata,
|
||||
FunctionDefinitionKind::Local(_, metadata) => metadata.clone(),
|
||||
FunctionDefinitionKind::Extern(_) => Metadata::default(),
|
||||
}
|
||||
}
|
||||
@ -288,6 +317,7 @@ pub enum TypeDefinitionKind {
|
||||
#[derive(Debug)]
|
||||
pub struct Module {
|
||||
pub name: String,
|
||||
pub module_id: SourceModuleId,
|
||||
pub imports: Vec<Import>,
|
||||
pub functions: Vec<FunctionDefinition>,
|
||||
pub typedefs: Vec<TypeDefinition>,
|
||||
|
@ -15,10 +15,10 @@ pub enum SimplePassError {
|
||||
VariableAlreadyDefined(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Eq, PartialOrd, Ord)]
|
||||
pub struct Error<TErr: STDError> {
|
||||
metadata: Metadata,
|
||||
kind: TErr,
|
||||
pub metadata: Metadata,
|
||||
pub kind: TErr,
|
||||
}
|
||||
|
||||
impl<TErr: STDError> std::fmt::Display for Error<TErr> {
|
||||
@ -33,6 +33,12 @@ impl<TErr: STDError> STDError for Error<TErr> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<TErr: STDError + PartialEq> PartialEq for Error<TErr> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.kind == other.kind && self.metadata.complete_overlap(&other.metadata)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct State<TErr: STDError> {
|
||||
pub errors: Vec<Error<TErr>>,
|
||||
|
@ -6,11 +6,11 @@ use crate::{mir::*, util::try_all};
|
||||
use VagueType as Vague;
|
||||
|
||||
use super::{
|
||||
pass::{Pass, PassState, ScopeFunction, ScopeVariable, Storage},
|
||||
pass::{Pass, PassState, ScopeFunction, ScopeVariable},
|
||||
typerefs::TypeRefs,
|
||||
};
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum ErrorKind {
|
||||
#[error("NULL error, should never occur!")]
|
||||
Null,
|
||||
|
@ -24,11 +24,31 @@ 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<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> {
|
||||
let next_token = self.previous().unwrap_or(Token::Eof);
|
||||
Ok(Error::Expected(
|
||||
expected.into(),
|
||||
self.peek().unwrap_or(Token::Eof),
|
||||
self.get_next_position()?,
|
||||
next_token,
|
||||
TokenRange {
|
||||
start: self.position - 1,
|
||||
end: self.position - 1,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns expected-error for the previous token that was already consumed.
|
||||
/// Useful in conjunction with [`TokenStream::next`]
|
||||
pub fn expecting_err<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> {
|
||||
let next_token = self.peek().unwrap_or(Token::Eof);
|
||||
Ok(Error::Expected(
|
||||
expected.into(),
|
||||
next_token,
|
||||
TokenRange {
|
||||
start: self.position,
|
||||
end: self.position,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
@ -38,10 +58,10 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
||||
self.position += 1;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(self.expected_err(token)?)
|
||||
Err(self.expecting_err(token)?)
|
||||
}
|
||||
} else {
|
||||
Err(self.expected_err(token)?)
|
||||
Err(self.expecting_err(token)?)
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,6 +75,14 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
||||
value
|
||||
}
|
||||
|
||||
pub fn previous(&mut self) -> Option<Token> {
|
||||
if (self.position as i32 - 1) < 0 {
|
||||
None
|
||||
} else {
|
||||
Some(self.tokens[self.position - 1].token.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peek(&mut self) -> Option<Token> {
|
||||
if self.tokens.len() < self.position {
|
||||
None
|
||||
@ -147,11 +175,11 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_next_position(&self) -> Result<Position, Error> {
|
||||
fn get_position(&self, offset: usize) -> Result<Position, Error> {
|
||||
if self.tokens.is_empty() {
|
||||
Err(Error::FileEmpty)
|
||||
} else {
|
||||
let token_idx = self.position.min(self.tokens.len() - 1);
|
||||
let token_idx = (self.position - 1).min(self.tokens.len() - 1);
|
||||
Ok(self.tokens[token_idx].position)
|
||||
}
|
||||
}
|
||||
@ -162,13 +190,6 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
||||
end: self.position,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_one_token_range(&self) -> TokenRange {
|
||||
TokenRange {
|
||||
start: self.position - 1,
|
||||
end: self.position,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TokenStream<'_, '_> {
|
||||
@ -181,7 +202,7 @@ impl Drop for TokenStream<'_, '_> {
|
||||
|
||||
/// Index-range that can be used with the original array of [`FullToken`]s to
|
||||
/// retrieve the precise location of a failure.
|
||||
#[derive(Default, Clone, Copy)]
|
||||
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct TokenRange {
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
@ -214,10 +235,10 @@ impl std::iter::Sum for TokenRange {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Error {
|
||||
#[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)]
|
||||
Expected(String, Token, Position),
|
||||
#[error("Expected {} got {:?}", .0, .1)]
|
||||
Expected(String, Token, TokenRange),
|
||||
#[error("Source file contains no tokens")]
|
||||
FileEmpty,
|
||||
/// Only use this error in situations where the error never ends up for the end-user!
|
||||
@ -227,3 +248,14 @@ pub enum Error {
|
||||
#[error("Condition failed for parse-if. Should never be returned to end-user.")]
|
||||
IfFailed,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn get_range(&self) -> Option<&TokenRange> {
|
||||
match self {
|
||||
Error::Expected(_, _, pos) => Some(pos),
|
||||
Error::FileEmpty => None,
|
||||
Error::Undefined => None,
|
||||
Error::IfFailed => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,74 +1,71 @@
|
||||
use reid::{
|
||||
compile_module,
|
||||
mir::{self},
|
||||
perform_all_passes,
|
||||
parse_module, perform_all_passes,
|
||||
};
|
||||
use util::assert_err;
|
||||
|
||||
mod util;
|
||||
|
||||
fn test(source: &str, name: &str) {
|
||||
let mut map = Default::default();
|
||||
let (id, tokens) = assert_err(parse_module(source, name, &mut map));
|
||||
let module = assert_err(compile_module(id, &tokens, &mut map, None, true));
|
||||
|
||||
assert_err(perform_all_passes(
|
||||
&mut mir::Context {
|
||||
modules: vec![module],
|
||||
base: Default::default(),
|
||||
},
|
||||
&mut map,
|
||||
));
|
||||
}
|
||||
|
||||
pub static ARRAY: &str = include_str!("../../reid_src/array.reid");
|
||||
pub static FIBONACCI: &str = include_str!("../../reid_src/fibonacci.reid");
|
||||
pub static HELLO_WORLD: &str = include_str!("../../reid_src/hello_world.reid");
|
||||
pub static MUTABLE: &str = include_str!("../../reid_src/mutable.reid");
|
||||
pub static STRINGS: &str = include_str!("../../reid_src/strings.reid");
|
||||
pub static ARRAYS: &str = include_str!("../../reid_src/array.reid");
|
||||
pub static STRUCTS: &str = include_str!("../../reid_src/struct.reid");
|
||||
pub static ARRAY_STRUCTS: &str = include_str!("../../reid_src/array_structs.reid");
|
||||
|
||||
#[test]
|
||||
fn array_compiles_well() {
|
||||
let module = assert_err(compile_module(ARRAY, "array".to_owned(), None, true));
|
||||
|
||||
assert_err(perform_all_passes(&mut mir::Context {
|
||||
modules: vec![module],
|
||||
base: Default::default(),
|
||||
}));
|
||||
test(ARRAY, "array");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fibonacci_compiles_well() {
|
||||
let module = assert_err(compile_module(
|
||||
FIBONACCI,
|
||||
"fibonacci".to_owned(),
|
||||
None,
|
||||
true,
|
||||
));
|
||||
|
||||
assert_err(perform_all_passes(&mut mir::Context {
|
||||
modules: vec![module],
|
||||
base: Default::default(),
|
||||
}));
|
||||
test(FIBONACCI, "fibonacci");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hello_world_compiles_well() {
|
||||
let module = assert_err(compile_module(
|
||||
HELLO_WORLD,
|
||||
"hello_world".to_owned(),
|
||||
None,
|
||||
true,
|
||||
));
|
||||
|
||||
assert_err(perform_all_passes(&mut mir::Context {
|
||||
modules: vec![module],
|
||||
base: Default::default(),
|
||||
}));
|
||||
test(HELLO_WORLD, "hello_world");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mutable_compiles_well() {
|
||||
let module = assert_err(compile_module(MUTABLE, "mutable".to_owned(), None, true));
|
||||
|
||||
assert_err(perform_all_passes(&mut mir::Context {
|
||||
modules: vec![module],
|
||||
base: Default::default(),
|
||||
}));
|
||||
test(MUTABLE, "mutable");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strings_compiles_well() {
|
||||
let module = assert_err(compile_module(STRINGS, "strings".to_owned(), None, true));
|
||||
|
||||
assert_err(perform_all_passes(&mut mir::Context {
|
||||
modules: vec![module],
|
||||
base: Default::default(),
|
||||
}));
|
||||
test(STRINGS, "strings");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arrays_compiles_well() {
|
||||
test(ARRAY, "array");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn struct_compiles_well() {
|
||||
test(STRUCTS, "struct");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_structs_compiles_well() {
|
||||
test(ARRAY_STRUCTS, "array_structs");
|
||||
}
|
||||
|
@ -8,18 +8,22 @@ mod util;
|
||||
|
||||
#[test]
|
||||
fn compiles() {
|
||||
let _ = compile_std();
|
||||
let _ = compile_std(&mut Default::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn passes_all_passes() {
|
||||
let mut std = compile_std();
|
||||
let mut map = Default::default();
|
||||
let (mut std, _) = compile_std(&mut map);
|
||||
|
||||
// Needed to pass linker-pass
|
||||
std.is_main = true;
|
||||
|
||||
assert_err(perform_all_passes(&mut mir::Context {
|
||||
modules: vec![std],
|
||||
base: Default::default(),
|
||||
}));
|
||||
assert_err(perform_all_passes(
|
||||
&mut mir::Context {
|
||||
modules: vec![std],
|
||||
base: Default::default(),
|
||||
},
|
||||
&mut map,
|
||||
));
|
||||
}
|
||||
|
@ -5,11 +5,16 @@ struct Test {
|
||||
second: [u32; 4]
|
||||
}
|
||||
|
||||
fn main() -> u32 {
|
||||
let mut value = [Test {
|
||||
fn test() -> [Test; 1] {
|
||||
let value = [Test {
|
||||
field: 5,
|
||||
second: [6, 3, 17, 8],
|
||||
second: [6, 3, 4, 8],
|
||||
}];
|
||||
return value;
|
||||
}
|
||||
|
||||
fn main() -> u32 {
|
||||
let mut value = test();
|
||||
|
||||
let val1 = 0;
|
||||
let val2 = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user