working on adding generics
This commit is contained in:
114
Cargo.lock
generated
114
Cargo.lock
generated
@@ -72,19 +72,12 @@ name = "boring-lang"
|
|||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"inkwell",
|
|
||||||
"lalrpop",
|
"lalrpop",
|
||||||
"lalrpop-util",
|
"lalrpop-util",
|
||||||
"regex",
|
"regex",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.67"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -196,39 +189,6 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "inkwell"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "git+https://github.com/TheDan64/inkwell?branch=llvm7-0#ef1f5e491fd599d84ba67f82b87e55cb7be4b0b8"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"inkwell_internals",
|
|
||||||
"libc",
|
|
||||||
"llvm-sys",
|
|
||||||
"once_cell",
|
|
||||||
"parking_lot",
|
|
||||||
"regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "inkwell_internals"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "git+https://github.com/TheDan64/inkwell?branch=llvm7-0#ef1f5e491fd599d84ba67f82b87e55cb7be4b0b8"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "instant"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
@@ -282,28 +242,6 @@ version = "0.2.88"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
|
checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "llvm-sys"
|
|
||||||
version = "70.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "673300127ec17878e6f7fee4e851ba6fd36b08c26b2d6258732d699d1b3e3fcd"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"regex",
|
|
||||||
"semver",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lock_api"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
|
|
||||||
dependencies = [
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.14"
|
version = "0.4.14"
|
||||||
@@ -331,31 +269,6 @@ version = "1.7.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot"
|
|
||||||
version = "0.11.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
|
||||||
dependencies = [
|
|
||||||
"instant",
|
|
||||||
"lock_api",
|
|
||||||
"parking_lot_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot_core"
|
|
||||||
version = "0.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"instant",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall",
|
|
||||||
"smallvec",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "petgraph"
|
name = "petgraph"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@@ -448,39 +361,12 @@ version = "1.0.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
|
checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "semver"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
|
||||||
dependencies = [
|
|
||||||
"semver-parser",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "semver-parser"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1"
|
checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "string_cache"
|
name = "string_cache"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ features = ["lexer"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
lalrpop-util = "0.19.6"
|
lalrpop-util = "0.19.6"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm7-0" }
|
# inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm7-0" }
|
||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
|
|||||||
27
examples/generics.bl
Normal file
27
examples/generics.bl
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
type MyTrait trait {}
|
||||||
|
|
||||||
|
type Pair[K, V: MyTrait] struct {
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Value struct {
|
||||||
|
value: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MyTrait for Value {}
|
||||||
|
|
||||||
|
|
||||||
|
impl [K, V: MyTrait] Pair[K, V] {
|
||||||
|
fn get_value[T](self: Self, a: T): V {
|
||||||
|
return self.v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main(): i64 {
|
||||||
|
let a = Pair{
|
||||||
|
k: 4,
|
||||||
|
v: Value{value: 6},
|
||||||
|
};
|
||||||
|
return a.get_value(999);
|
||||||
|
}
|
||||||
17
src/ast.rs
17
src/ast.rs
@@ -1,17 +1,19 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct IdGenerator {
|
pub struct IdGenerator {
|
||||||
|
id_key: String,
|
||||||
counter: RefCell<i64>,
|
counter: RefCell<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdGenerator {
|
impl IdGenerator {
|
||||||
pub fn new() -> Self {
|
pub fn new(key: &str) -> Self {
|
||||||
IdGenerator { counter: RefCell::new(0) }
|
IdGenerator { id_key: key.to_string(), counter: RefCell::new(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&self) -> String {
|
pub fn next(&self) -> String {
|
||||||
*self.counter.borrow_mut() += 1;
|
*self.counter.borrow_mut() += 1;
|
||||||
("S".to_owned() + &self.counter.borrow().to_string()).to_string()
|
(self.id_key.to_owned() + &self.counter.borrow().to_string()).to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,11 +70,18 @@ pub struct UnknownTypeUsage {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum NamespaceTypeUsage {
|
||||||
|
Type(NamedTypeUsage)
|
||||||
|
// Module
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum TypeUsage {
|
pub enum TypeUsage {
|
||||||
Function(FunctionTypeUsage),
|
Function(FunctionTypeUsage),
|
||||||
Named(NamedTypeUsage),
|
Named(NamedTypeUsage),
|
||||||
Unknown(UnknownTypeUsage),
|
Unknown(UnknownTypeUsage),
|
||||||
|
Namespace(NamespaceTypeUsage)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeUsage {
|
impl TypeUsage {
|
||||||
@@ -200,8 +209,8 @@ pub struct Operation {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct VariableUsage {
|
pub struct VariableUsage {
|
||||||
pub type_parameters: GenericUsage,
|
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
|
pub type_parameters: GenericUsage,
|
||||||
pub type_: TypeUsage,
|
pub type_: TypeUsage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1
src/builtins.rs
Normal file
1
src/builtins.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
@@ -47,6 +47,14 @@ pub enum TypingError {
|
|||||||
},
|
},
|
||||||
#[error("cannot use type as an expression")]
|
#[error("cannot use type as an expression")]
|
||||||
TypeIsNotAnExpression { type_name: ast::Identifier },
|
TypeIsNotAnExpression { type_name: ast::Identifier },
|
||||||
|
#[error("wrong number of type parameters")]
|
||||||
|
WrongNumberOfTypeParameters {
|
||||||
|
// TODO: add position
|
||||||
|
},
|
||||||
|
#[error("invalid use of alias")]
|
||||||
|
InvalidUseofAlias,
|
||||||
|
#[error("type cannot be used for generic")]
|
||||||
|
InvalidTypeForGeneric,
|
||||||
#[error("multiple errors")]
|
#[error("multiple errors")]
|
||||||
MultipleErrors { errors: Vec<TypingError> },
|
MultipleErrors { errors: Vec<TypingError> },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ pub StructGetter: ast::StructGetter = {
|
|||||||
|
|
||||||
pub VariableUsage: ast::VariableUsage = {
|
pub VariableUsage: ast::VariableUsage = {
|
||||||
<identifier:SpannedIdentifier> <gu:GenericUsage?> => match gu {
|
<identifier:SpannedIdentifier> <gu:GenericUsage?> => match gu {
|
||||||
Some(tp) => ast::VariableUsage{type_parameters: tp, name: identifier, type_: ast::TypeUsage::new_unknown(&id_generator)},
|
Some(tp) => ast::VariableUsage{name: identifier, type_parameters: tp.clone(), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
None => ast::VariableUsage{type_parameters: ast::GenericUsage::Unknown, name: identifier, type_: ast::TypeUsage::new_unknown(&id_generator)},
|
None => ast::VariableUsage{name: identifier, type_parameters: ast::GenericUsage::Unknown, type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
13
src/main.rs
13
src/main.rs
@@ -37,11 +37,18 @@ fn main() {
|
|||||||
let _output = matches.value_of("OUTPUT").unwrap_or(default_output);
|
let _output = matches.value_of("OUTPUT").unwrap_or(default_output);
|
||||||
|
|
||||||
let contents = fs::read_to_string(input).expect("input file not found");
|
let contents = fs::read_to_string(input).expect("input file not found");
|
||||||
let unknown_id_gen = ast::IdGenerator::new();
|
let unknown_id_gen = ast::IdGenerator::new("S");
|
||||||
let module_ast = grammar::ModuleParser::new().parse(&unknown_id_gen, &contents).unwrap(); //TODO: convert to error
|
let module_ast = grammar::ModuleParser::new().parse(&unknown_id_gen, &contents).unwrap(); //TODO: convert to error
|
||||||
// println!("ast: {:#?}", &module_ast);
|
// println!("ast: {:#?}", &module_ast);
|
||||||
let alias_resolver = type_alias_resolution::TypeAliasResolver {};
|
let alias_resolver = type_alias_resolution::TypeAliasResolver {};
|
||||||
let resolved_ast = alias_resolver.with_module(&module_ast);
|
let resolved_ast = match alias_resolver.with_module(&module_ast) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(err) => {
|
||||||
|
println!("type checking error: {:#?}", &err);
|
||||||
|
panic!("bad alias");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// println!("resolved ast: {:#?}", &resolved_ast);
|
// println!("resolved ast: {:#?}", &resolved_ast);
|
||||||
let trait_checker = trait_checking::TraitChecker {};
|
let trait_checker = trait_checking::TraitChecker {};
|
||||||
match trait_checker.with_module(&resolved_ast) {
|
match trait_checker.with_module(&resolved_ast) {
|
||||||
@@ -76,7 +83,7 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn grammar() {
|
fn grammar() {
|
||||||
let id_gen = ast::IdGenerator::new();
|
let id_gen = ast::IdGenerator::new("S");
|
||||||
assert!(grammar::LiteralIntParser::new().parse(&id_gen, "22").is_ok());
|
assert!(grammar::LiteralIntParser::new().parse(&id_gen, "22").is_ok());
|
||||||
assert!(grammar::IdentifierParser::new().parse(&id_gen, "foo").is_ok());
|
assert!(grammar::IdentifierParser::new().parse(&id_gen, "foo").is_ok());
|
||||||
assert!(grammar::LiteralIntParser::new().parse(&id_gen, "2a").is_err());
|
assert!(grammar::LiteralIntParser::new().parse(&id_gen, "2a").is_err());
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::ast;
|
use crate::ast;
|
||||||
|
use crate::errors;
|
||||||
|
|
||||||
|
pub type Result<T, E = errors::TypingError> = std::result::Result<T, E>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
struct Context {
|
struct Context {
|
||||||
@@ -26,19 +29,38 @@ fn resolve_type(ctx: &Context, type_: &ast::NamedTypeUsage) -> ast::TypeUsage {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_type(ctx: &Context, type_: &ast::TypeUsage) -> ast::TypeUsage {
|
fn process_type(ctx: &Context, type_: &ast::TypeUsage) -> Result<ast::TypeUsage> {
|
||||||
match type_ {
|
match type_ {
|
||||||
ast::TypeUsage::Named(named) => {
|
ast::TypeUsage::Named(named) => {
|
||||||
return resolve_type(ctx, named);
|
return Ok(resolve_type(ctx, named));
|
||||||
}
|
}
|
||||||
ast::TypeUsage::Function(function) => {
|
ast::TypeUsage::Function(function) => {
|
||||||
return ast::TypeUsage::Function(ast::FunctionTypeUsage {
|
let mut arguments = vec!();
|
||||||
arguments: function.arguments.iter().map(|a| process_type(ctx, &a.clone())).collect(),
|
for a in function.arguments.iter() {
|
||||||
return_type: Box::new(process_type(ctx, &function.return_type.clone())),
|
arguments.push(process_type(ctx, &a.clone())?);
|
||||||
});
|
}
|
||||||
|
return Ok(ast::TypeUsage::Function(ast::FunctionTypeUsage {
|
||||||
|
arguments: arguments,
|
||||||
|
return_type: Box::new(process_type(ctx, &function.return_type.clone())?),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
ast::TypeUsage::Unknown(unknown) => {
|
ast::TypeUsage::Unknown(unknown) => {
|
||||||
return ast::TypeUsage::Unknown(unknown.clone());
|
return Ok(ast::TypeUsage::Unknown(unknown.clone()));
|
||||||
|
},
|
||||||
|
ast::TypeUsage::Namespace(namespace) => {
|
||||||
|
match namespace {
|
||||||
|
ast::NamespaceTypeUsage::Type(named_type)=> {
|
||||||
|
let result = resolve_type(ctx, named_type);
|
||||||
|
match result {
|
||||||
|
ast::TypeUsage::Named(named) => {
|
||||||
|
return Ok(ast::TypeUsage::Namespace(ast::NamespaceTypeUsage::Type(named)));
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Err(errors::TypingError::InvalidUseofAlias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +68,7 @@ fn process_type(ctx: &Context, type_: &ast::TypeUsage) -> ast::TypeUsage {
|
|||||||
pub struct TypeAliasResolver {}
|
pub struct TypeAliasResolver {}
|
||||||
|
|
||||||
impl TypeAliasResolver {
|
impl TypeAliasResolver {
|
||||||
pub fn with_module(self: &Self, module: &ast::Module) -> ast::Module {
|
pub fn with_module(self: &Self, module: &ast::Module) -> Result<ast::Module> {
|
||||||
let mut ctx = Context { type_aliases: vec![] };
|
let mut ctx = Context { type_aliases: vec![] };
|
||||||
for item in module.items.iter() {
|
for item in module.items.iter() {
|
||||||
match item {
|
match item {
|
||||||
@@ -57,77 +79,78 @@ impl TypeAliasResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ast::Module {
|
let mut items = vec!();
|
||||||
items: module
|
for item in module.items.iter() {
|
||||||
.items
|
items.push(match item {
|
||||||
.iter()
|
ast::ModuleItem::Function(function) => ast::ModuleItem::Function(self.with_function(&ctx, function)?),
|
||||||
.map(|item| match item {
|
|
||||||
ast::ModuleItem::Function(function) => ast::ModuleItem::Function(self.with_function(&ctx, function)),
|
|
||||||
ast::ModuleItem::TypeDeclaration(type_declaration) => {
|
ast::ModuleItem::TypeDeclaration(type_declaration) => {
|
||||||
ast::ModuleItem::TypeDeclaration(self.with_type_declaration(&ctx, type_declaration))
|
ast::ModuleItem::TypeDeclaration(self.with_type_declaration(&ctx, type_declaration)?)
|
||||||
}
|
}
|
||||||
ast::ModuleItem::Impl(impl_) => ast::ModuleItem::Impl(self.with_impl(&ctx, impl_)),
|
ast::ModuleItem::Impl(impl_) => ast::ModuleItem::Impl(self.with_impl(&ctx, impl_)?),
|
||||||
})
|
});
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> ast::Function {
|
return Ok(ast::Module {
|
||||||
return ast::Function {
|
items: items,
|
||||||
declaration: self.with_function_declaration(ctx, &function.declaration),
|
});
|
||||||
block: self.with_block(ctx, &function.block),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> ast::FunctionDeclaration {
|
fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> Result<ast::Function> {
|
||||||
return ast::FunctionDeclaration {
|
return Ok(ast::Function {
|
||||||
|
declaration: self.with_function_declaration(ctx, &function.declaration)?,
|
||||||
|
block: self.with_block(ctx, &function.block)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> Result<ast::FunctionDeclaration> {
|
||||||
|
let mut arguments = vec!();
|
||||||
|
for arg in declaration.arguments.iter() {
|
||||||
|
arguments.push(ast::VariableDeclaration {
|
||||||
|
name: arg.name.clone(),
|
||||||
|
type_: process_type(ctx, &arg.type_)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Ok(ast::FunctionDeclaration {
|
||||||
name: declaration.name.clone(),
|
name: declaration.name.clone(),
|
||||||
generic: declaration.generic.clone(),
|
generic: declaration.generic.clone(),
|
||||||
arguments: declaration
|
arguments: arguments,
|
||||||
.arguments
|
return_type: process_type(ctx, &declaration.return_type)?,
|
||||||
.iter()
|
});
|
||||||
.map(|arg| ast::VariableDeclaration {
|
|
||||||
name: arg.name.clone(),
|
|
||||||
type_: process_type(ctx, &arg.type_),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
return_type: process_type(ctx, &declaration.return_type),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_type_declaration(self: &Self, ctx: &Context, type_declaration: &ast::TypeDeclaration) -> ast::TypeDeclaration {
|
fn with_type_declaration(self: &Self, ctx: &Context, type_declaration: &ast::TypeDeclaration) -> Result<ast::TypeDeclaration> {
|
||||||
match type_declaration {
|
match type_declaration {
|
||||||
ast::TypeDeclaration::Struct(struct_) => {
|
ast::TypeDeclaration::Struct(struct_) => {
|
||||||
return ast::TypeDeclaration::Struct(self.with_struct_declaration(ctx, struct_));
|
return Ok(ast::TypeDeclaration::Struct(self.with_struct_declaration(ctx, struct_)?));
|
||||||
}
|
}
|
||||||
ast::TypeDeclaration::Primitive(primitive) => {
|
ast::TypeDeclaration::Primitive(primitive) => {
|
||||||
return ast::TypeDeclaration::Primitive(primitive.clone());
|
return Ok(ast::TypeDeclaration::Primitive(primitive.clone()));
|
||||||
}
|
}
|
||||||
ast::TypeDeclaration::Alias(alias) => {
|
ast::TypeDeclaration::Alias(alias) => {
|
||||||
return ast::TypeDeclaration::Alias(alias.clone());
|
return Ok(ast::TypeDeclaration::Alias(alias.clone()));
|
||||||
}
|
}
|
||||||
ast::TypeDeclaration::Trait(trait_) => {
|
ast::TypeDeclaration::Trait(trait_) => {
|
||||||
return ast::TypeDeclaration::Trait(self.with_trait(ctx, trait_));
|
return Ok(ast::TypeDeclaration::Trait(self.with_trait(ctx, trait_)?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> ast::StructTypeDeclaration {
|
fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> Result<ast::StructTypeDeclaration> {
|
||||||
return ast::StructTypeDeclaration {
|
let mut fields = vec!();
|
||||||
|
for field in struct_.fields.iter() {
|
||||||
|
fields.push(ast::StructField {
|
||||||
|
name: field.name.clone(),
|
||||||
|
type_: process_type(ctx, &field.type_)?,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Ok(ast::StructTypeDeclaration {
|
||||||
generic: struct_.generic.clone(),
|
generic: struct_.generic.clone(),
|
||||||
name: struct_.name.clone(),
|
name: struct_.name.clone(),
|
||||||
fields: struct_
|
fields: fields,
|
||||||
.fields
|
});
|
||||||
.iter()
|
|
||||||
.map(|field| ast::StructField {
|
|
||||||
name: field.name.clone(),
|
|
||||||
type_: process_type(ctx, &field.type_),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_trait(self: &Self, ctx: &Context, trait_: &ast::TraitTypeDeclaration) -> ast::TraitTypeDeclaration {
|
fn with_trait(self: &Self, ctx: &Context, trait_: &ast::TraitTypeDeclaration) -> Result<ast::TraitTypeDeclaration> {
|
||||||
let mut trait_ctx = ctx.clone();
|
let mut trait_ctx = ctx.clone();
|
||||||
trait_ctx.type_aliases.push(ast::AliasTypeDeclaration {
|
trait_ctx.type_aliases.push(ast::AliasTypeDeclaration {
|
||||||
name: ast::Identifier {
|
name: ast::Identifier {
|
||||||
@@ -141,23 +164,23 @@ impl TypeAliasResolver {
|
|||||||
name: trait_.name.clone(),
|
name: trait_.name.clone(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
return ast::TraitTypeDeclaration {
|
let mut functions = vec!();
|
||||||
|
for f in trait_.functions.iter() {
|
||||||
|
functions.push(match f {
|
||||||
|
ast::TraitItem::Function(function) => ast::TraitItem::Function(self.with_function(&trait_ctx, function)?),
|
||||||
|
ast::TraitItem::FunctionDeclaration(function_declaration) => {
|
||||||
|
ast::TraitItem::FunctionDeclaration(self.with_function_declaration(&trait_ctx, function_declaration)?)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Ok(ast::TraitTypeDeclaration {
|
||||||
generic: trait_.generic.clone(),
|
generic: trait_.generic.clone(),
|
||||||
name: trait_.name.clone(),
|
name: trait_.name.clone(),
|
||||||
functions: trait_
|
functions: functions,
|
||||||
.functions
|
});
|
||||||
.iter()
|
|
||||||
.map(|f| match f {
|
|
||||||
ast::TraitItem::Function(function) => ast::TraitItem::Function(self.with_function(&trait_ctx, function)),
|
|
||||||
ast::TraitItem::FunctionDeclaration(function_declaration) => {
|
|
||||||
ast::TraitItem::FunctionDeclaration(self.with_function_declaration(&trait_ctx, function_declaration))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_impl(self: &Self, ctx: &Context, impl_: &ast::Impl) -> ast::Impl {
|
fn with_impl(self: &Self, ctx: &Context, impl_: &ast::Impl) -> Result<ast::Impl> {
|
||||||
let mut impl_ctx = ctx.clone();
|
let mut impl_ctx = ctx.clone();
|
||||||
impl_ctx.type_aliases.push(ast::AliasTypeDeclaration {
|
impl_ctx.type_aliases.push(ast::AliasTypeDeclaration {
|
||||||
name: ast::Identifier {
|
name: ast::Identifier {
|
||||||
@@ -168,85 +191,93 @@ impl TypeAliasResolver {
|
|||||||
},
|
},
|
||||||
replaces: ast::TypeUsage::Named(impl_.struct_.clone()),
|
replaces: ast::TypeUsage::Named(impl_.struct_.clone()),
|
||||||
});
|
});
|
||||||
return ast::Impl {
|
let mut functions = vec!();
|
||||||
|
for f in impl_.functions.iter() {
|
||||||
|
functions.push(self.with_function(&impl_ctx, f)?);
|
||||||
|
}
|
||||||
|
return Ok(ast::Impl {
|
||||||
generic: impl_.generic.clone(),
|
generic: impl_.generic.clone(),
|
||||||
trait_: impl_.trait_.clone(),
|
trait_: impl_.trait_.clone(),
|
||||||
struct_: impl_.struct_.clone(),
|
struct_: impl_.struct_.clone(),
|
||||||
functions: impl_.functions.iter().map(|f| self.with_function(&impl_ctx, f)).collect(),
|
functions: functions,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_block(self: &Self, ctx: &Context, block: &ast::Block) -> ast::Block {
|
fn with_block(self: &Self, ctx: &Context, block: &ast::Block) -> Result<ast::Block> {
|
||||||
return ast::Block {
|
let mut statements = vec!();
|
||||||
statements: block.statements.iter().map(|s| self.with_statement(ctx, s)).collect(),
|
for s in block.statements.iter() {
|
||||||
type_: process_type(ctx, &block.type_),
|
statements.push(self.with_statement(ctx, s)?);
|
||||||
};
|
}
|
||||||
|
return Ok(ast::Block {
|
||||||
|
statements: statements,
|
||||||
|
type_: process_type(ctx, &block.type_)?,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_statement(self: &Self, ctx: &Context, statement: &ast::Statement) -> ast::Statement {
|
fn with_statement(self: &Self, ctx: &Context, statement: &ast::Statement) -> Result<ast::Statement> {
|
||||||
match statement {
|
match statement {
|
||||||
ast::Statement::Return(return_statement) => {
|
ast::Statement::Return(return_statement) => {
|
||||||
return ast::Statement::Return(self.with_return_statement(ctx, return_statement));
|
return Ok(ast::Statement::Return(self.with_return_statement(ctx, return_statement)?));
|
||||||
}
|
}
|
||||||
ast::Statement::Let(let_statement) => {
|
ast::Statement::Let(let_statement) => {
|
||||||
return ast::Statement::Let(self.with_let_statement(ctx, let_statement));
|
return Ok(ast::Statement::Let(self.with_let_statement(ctx, let_statement)?));
|
||||||
}
|
}
|
||||||
ast::Statement::Assignment(assignment_statement) => {
|
ast::Statement::Assignment(assignment_statement) => {
|
||||||
return ast::Statement::Assignment(self.with_assignment_statement(ctx, assignment_statement));
|
return Ok(ast::Statement::Assignment(self.with_assignment_statement(ctx, assignment_statement)?));
|
||||||
}
|
}
|
||||||
ast::Statement::Expression(expression) => {
|
ast::Statement::Expression(expression) => {
|
||||||
return ast::Statement::Expression(self.with_expression(ctx, expression));
|
return Ok(ast::Statement::Expression(self.with_expression(ctx, expression)?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_return_statement(self: &Self, ctx: &Context, statement: &ast::ReturnStatement) -> ast::ReturnStatement {
|
fn with_return_statement(self: &Self, ctx: &Context, statement: &ast::ReturnStatement) -> Result<ast::ReturnStatement> {
|
||||||
return ast::ReturnStatement {
|
return Ok(ast::ReturnStatement {
|
||||||
source: self.with_expression(ctx, &statement.source),
|
source: self.with_expression(ctx, &statement.source)?,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_let_statement(self: &Self, ctx: &Context, statement: &ast::LetStatement) -> ast::LetStatement {
|
fn with_let_statement(self: &Self, ctx: &Context, statement: &ast::LetStatement) -> Result<ast::LetStatement> {
|
||||||
return ast::LetStatement {
|
return Ok(ast::LetStatement {
|
||||||
variable_name: statement.variable_name.clone(),
|
variable_name: statement.variable_name.clone(),
|
||||||
expression: self.with_expression(ctx, &statement.expression),
|
expression: self.with_expression(ctx, &statement.expression)?,
|
||||||
type_: process_type(ctx, &statement.type_),
|
type_: process_type(ctx, &statement.type_)?,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_assignment_statement(self: &Self, ctx: &Context, statement: &ast::AssignmentStatement) -> ast::AssignmentStatement {
|
fn with_assignment_statement(self: &Self, ctx: &Context, statement: &ast::AssignmentStatement) -> Result<ast::AssignmentStatement> {
|
||||||
return ast::AssignmentStatement {
|
return Ok(ast::AssignmentStatement {
|
||||||
source: match &statement.source {
|
source: match &statement.source {
|
||||||
ast::AssignmentTarget::Variable(variable) => ast::AssignmentTarget::Variable(ast::VariableUsage {
|
ast::AssignmentTarget::Variable(variable) => ast::AssignmentTarget::Variable(ast::VariableUsage {
|
||||||
type_parameters: variable.type_parameters.clone(),
|
type_parameters: variable.type_parameters.clone(),
|
||||||
name: variable.name.clone(),
|
name: variable.name.clone(),
|
||||||
type_: process_type(ctx, &variable.type_),
|
type_: process_type(ctx, &variable.type_)?,
|
||||||
}),
|
}),
|
||||||
ast::AssignmentTarget::StructAttr(struct_attr) => ast::AssignmentTarget::StructAttr(ast::StructGetter {
|
ast::AssignmentTarget::StructAttr(struct_attr) => ast::AssignmentTarget::StructAttr(ast::StructGetter {
|
||||||
type_parameters: struct_attr.type_parameters.clone(),
|
type_parameters: struct_attr.type_parameters.clone(),
|
||||||
source: self.with_expression(ctx, &struct_attr.source),
|
source: self.with_expression(ctx, &struct_attr.source)?,
|
||||||
attribute: struct_attr.attribute.clone(),
|
attribute: struct_attr.attribute.clone(),
|
||||||
type_: process_type(ctx, &struct_attr.type_),
|
type_: process_type(ctx, &struct_attr.type_)?,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
expression: self.with_expression(ctx, &statement.expression),
|
expression: self.with_expression(ctx, &statement.expression)?,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_expression(self: &Self, ctx: &Context, expression: &ast::Expression) -> ast::Expression {
|
fn with_expression(self: &Self, ctx: &Context, expression: &ast::Expression) -> Result<ast::Expression> {
|
||||||
return ast::Expression {
|
return Ok(ast::Expression {
|
||||||
subexpression: Box::new(match &*expression.subexpression {
|
subexpression: Box::new(match &*expression.subexpression {
|
||||||
ast::Subexpression::LiteralInt(literal_int) => ast::Subexpression::LiteralInt(ast::LiteralInt {
|
ast::Subexpression::LiteralInt(literal_int) => ast::Subexpression::LiteralInt(ast::LiteralInt {
|
||||||
value: literal_int.value.clone(),
|
value: literal_int.value.clone(),
|
||||||
type_: process_type(ctx, &literal_int.type_),
|
type_: process_type(ctx, &literal_int.type_)?,
|
||||||
}),
|
}),
|
||||||
ast::Subexpression::LiteralFloat(literal_float) => ast::Subexpression::LiteralFloat(ast::LiteralFloat {
|
ast::Subexpression::LiteralFloat(literal_float) => ast::Subexpression::LiteralFloat(ast::LiteralFloat {
|
||||||
value: literal_float.value.clone(),
|
value: literal_float.value.clone(),
|
||||||
type_: process_type(ctx, &literal_float.type_),
|
type_: process_type(ctx, &literal_float.type_)?,
|
||||||
}),
|
}),
|
||||||
ast::Subexpression::LiteralBool(literal_bool) => ast::Subexpression::LiteralBool(ast::LiteralBool {
|
ast::Subexpression::LiteralBool(literal_bool) => ast::Subexpression::LiteralBool(ast::LiteralBool {
|
||||||
value: literal_bool.value.clone(),
|
value: literal_bool.value.clone(),
|
||||||
type_: process_type(ctx, &literal_bool.type_),
|
type_: process_type(ctx, &literal_bool.type_)?,
|
||||||
}),
|
}),
|
||||||
ast::Subexpression::LiteralStruct(literal_struct) => {
|
ast::Subexpression::LiteralStruct(literal_struct) => {
|
||||||
let result = resolve_type(
|
let result = resolve_type(
|
||||||
@@ -260,50 +291,56 @@ impl TypeAliasResolver {
|
|||||||
ast::TypeUsage::Named(named) => named.name.clone(),
|
ast::TypeUsage::Named(named) => named.name.clone(),
|
||||||
_ => panic!("LiteralStruct resolved to non-named-type"),
|
_ => panic!("LiteralStruct resolved to non-named-type"),
|
||||||
};
|
};
|
||||||
|
let mut fields = vec!();
|
||||||
|
for field in literal_struct.fields.iter() {
|
||||||
|
fields.push((field.0.clone(), self.with_expression(ctx, &field.1)?));
|
||||||
|
}
|
||||||
ast::Subexpression::LiteralStruct(ast::LiteralStruct {
|
ast::Subexpression::LiteralStruct(ast::LiteralStruct {
|
||||||
type_parameters: literal_struct.type_parameters.clone(),
|
type_parameters: literal_struct.type_parameters.clone(),
|
||||||
name: new_name.clone(),
|
name: new_name.clone(),
|
||||||
fields: literal_struct
|
fields: fields,
|
||||||
.fields
|
type_: process_type(ctx, &literal_struct.type_)?,
|
||||||
.iter()
|
|
||||||
.map(|field| (field.0.clone(), self.with_expression(ctx, &field.1)))
|
|
||||||
.collect(),
|
|
||||||
type_: process_type(ctx, &literal_struct.type_),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ast::Subexpression::FunctionCall(function_call) => ast::Subexpression::FunctionCall(ast::FunctionCall {
|
ast::Subexpression::FunctionCall(function_call) => {
|
||||||
source: self.with_expression(ctx, &function_call.source),
|
let mut arguments = vec!();
|
||||||
arguments: function_call.arguments.iter().map(|arg| self.with_expression(ctx, arg)).collect(),
|
for arg in function_call.arguments.iter() {
|
||||||
type_: process_type(ctx, &function_call.type_),
|
arguments.push(self.with_expression(ctx, arg)?);
|
||||||
}),
|
}
|
||||||
|
ast::Subexpression::FunctionCall(ast::FunctionCall {
|
||||||
|
source: self.with_expression(ctx, &function_call.source)?,
|
||||||
|
arguments: arguments,
|
||||||
|
type_: process_type(ctx, &function_call.type_)?,
|
||||||
|
})
|
||||||
|
},
|
||||||
ast::Subexpression::VariableUsage(variable_usage) => ast::Subexpression::VariableUsage(ast::VariableUsage {
|
ast::Subexpression::VariableUsage(variable_usage) => ast::Subexpression::VariableUsage(ast::VariableUsage {
|
||||||
type_parameters: variable_usage.type_parameters.clone(),
|
|
||||||
name: variable_usage.name.clone(),
|
name: variable_usage.name.clone(),
|
||||||
type_: process_type(ctx, &variable_usage.type_),
|
type_parameters: variable_usage.type_parameters.clone(),
|
||||||
|
type_: process_type(ctx, &variable_usage.type_)?,
|
||||||
}),
|
}),
|
||||||
ast::Subexpression::If(if_expression) => ast::Subexpression::If(ast::IfExpression {
|
ast::Subexpression::If(if_expression) => ast::Subexpression::If(ast::IfExpression {
|
||||||
condition: self.with_expression(ctx, &if_expression.condition),
|
condition: self.with_expression(ctx, &if_expression.condition)?,
|
||||||
block: self.with_block(ctx, &if_expression.block),
|
block: self.with_block(ctx, &if_expression.block)?,
|
||||||
else_: match &if_expression.else_ {
|
else_: match &if_expression.else_ {
|
||||||
Some(else_) => Some(self.with_block(ctx, else_)),
|
Some(else_) => Some(self.with_block(ctx, else_)?),
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
type_: process_type(ctx, &if_expression.type_),
|
type_: process_type(ctx, &if_expression.type_)?,
|
||||||
}),
|
}),
|
||||||
ast::Subexpression::StructGetter(struct_getter) => ast::Subexpression::StructGetter(ast::StructGetter {
|
ast::Subexpression::StructGetter(struct_getter) => ast::Subexpression::StructGetter(ast::StructGetter {
|
||||||
type_parameters: struct_getter.type_parameters.clone(),
|
type_parameters: struct_getter.type_parameters.clone(),
|
||||||
source: self.with_expression(ctx, &struct_getter.source),
|
source: self.with_expression(ctx, &struct_getter.source)?,
|
||||||
attribute: struct_getter.attribute.clone(),
|
attribute: struct_getter.attribute.clone(),
|
||||||
type_: process_type(ctx, &struct_getter.type_),
|
type_: process_type(ctx, &struct_getter.type_)?,
|
||||||
}),
|
}),
|
||||||
ast::Subexpression::Block(block) => ast::Subexpression::Block(self.with_block(ctx, &block)),
|
ast::Subexpression::Block(block) => ast::Subexpression::Block(self.with_block(ctx, &block)?),
|
||||||
ast::Subexpression::Op(op) => ast::Subexpression::Op(ast::Operation {
|
ast::Subexpression::Op(op) => ast::Subexpression::Op(ast::Operation {
|
||||||
left: self.with_expression(ctx, &op.left),
|
left: self.with_expression(ctx, &op.left)?,
|
||||||
op: op.op.clone(),
|
op: op.op.clone(),
|
||||||
right: self.with_expression(ctx, &op.right),
|
right: self.with_expression(ctx, &op.right)?,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
type_: process_type(ctx, &expression.type_),
|
type_: process_type(ctx, &expression.type_)?,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,121 @@
|
|||||||
use crate::ast;
|
use crate::ast;
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub type SubstitutionMap = HashMap<String, ast::TypeUsage>;
|
pub type SubstitutionMap = HashMap<String, ast::TypeUsage>;
|
||||||
|
|
||||||
pub type Result<T, E = errors::TypingError> = std::result::Result<T, E>;
|
pub type Result<T, E = errors::TypingError> = std::result::Result<T, E>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct TypeConstructor {
|
||||||
|
generic: ast::Generic,
|
||||||
|
type_usage: ast::TypeUsage,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_meets_trait_bounds(ctx: &Context, type_: &ast::TypeUsage, bounds: &Vec<ast::Identifier>) -> bool {
|
||||||
|
for bound in bounds.iter() {
|
||||||
|
let named = match type_ {
|
||||||
|
ast::TypeUsage::Named(named) => named,
|
||||||
|
ast::TypeUsage::Function(_) => {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
ast::TypeUsage::Unknown(_) => {
|
||||||
|
return true; // unknown this pass, skip, test once known
|
||||||
|
},
|
||||||
|
ast::TypeUsage::Namespace(_) => {
|
||||||
|
panic!("impossible");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match &ctx.environment[&named.name.name.value] {
|
||||||
|
NamedEntity::NamedType(named_type) => {
|
||||||
|
println!("env value: {:?}", &ctx.environment[&named.name.name.value]);
|
||||||
|
let mut found = false;
|
||||||
|
for impl_ in named_type.impls.iter() {
|
||||||
|
println!("for: {:?}", &named.name.name.value);
|
||||||
|
println!("bounds: {:?}", &bound.name.value);
|
||||||
|
println!("trait: {:?}", &impl_.trait_);
|
||||||
|
if impl_.trait_ == Some(bound.name.value.to_string()) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found == false {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
panic!("type is a variable, this should not happen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_generic_with_concrete(replace: &ast::Identifier, with_type: &ast::TypeUsage, in_type: &ast::TypeUsage) -> ast::TypeUsage {
|
||||||
|
match in_type {
|
||||||
|
ast::TypeUsage::Named(named) => {
|
||||||
|
if named.name.name.value == replace.name.value {
|
||||||
|
return with_type.clone();
|
||||||
|
}
|
||||||
|
return in_type.clone();
|
||||||
|
},
|
||||||
|
ast::TypeUsage::Function(func) => {
|
||||||
|
return ast::TypeUsage::Function(ast::FunctionTypeUsage{
|
||||||
|
arguments: func.arguments.iter().map(|arg| {
|
||||||
|
replace_generic_with_concrete(replace, with_type, arg)
|
||||||
|
}).collect(),
|
||||||
|
return_type: Box::new(replace_generic_with_concrete(replace, with_type, &func.return_type)),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_ => panic!("unknown in a generic, this should not happen")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeConstructor {
|
||||||
|
fn from_declaration(declaration: &ast::FunctionDeclaration) -> TypeConstructor {
|
||||||
|
return TypeConstructor{
|
||||||
|
generic: declaration.generic.clone(),
|
||||||
|
type_usage: declaration.to_type(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn construct(&self, ctx: &Context, usage: &ast::GenericUsage) -> Result<ast::TypeUsage> {
|
||||||
|
match usage {
|
||||||
|
ast::GenericUsage::Known(known_usage) => {
|
||||||
|
let mut result = self.type_usage.clone();
|
||||||
|
if known_usage.parameters.len() != self.generic.parameters.len() {
|
||||||
|
return Err(errors::TypingError::WrongNumberOfTypeParameters{});
|
||||||
|
}
|
||||||
|
// 1. for arg in args, assert arg matches self.generic traits via impl name
|
||||||
|
// 2. replace type usage names with arg types
|
||||||
|
for i in 0..known_usage.parameters.len() {
|
||||||
|
println!("test: {:?}\n{:?}", &known_usage.parameters[i], &self.generic.parameters[i].bounds);
|
||||||
|
if !type_meets_trait_bounds(ctx, &known_usage.parameters[i], &self.generic.parameters[i].bounds) {
|
||||||
|
panic!("InvalidTypeForGeneric");
|
||||||
|
return Err(errors::TypingError::InvalidTypeForGeneric);
|
||||||
|
}
|
||||||
|
result = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &self.type_usage);
|
||||||
|
}
|
||||||
|
return Ok(result);
|
||||||
|
},
|
||||||
|
ast::GenericUsage::Unknown => {
|
||||||
|
// generate new Unknown Types for matching
|
||||||
|
let mut result = self.type_usage.clone();
|
||||||
|
for param in self.generic.parameters.iter() {
|
||||||
|
let id = ctx.id_generator.next();
|
||||||
|
let unknown = ast::TypeUsage::Unknown(ast::UnknownTypeUsage{name: id});
|
||||||
|
result = replace_generic_with_concrete(¶m.name, &unknown, &self.type_usage);
|
||||||
|
}
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct EnvImpl {
|
pub struct EnvImpl {
|
||||||
trait_: Option<String>,
|
trait_: Option<String>,
|
||||||
functions: HashMap<String, ast::TypeUsage>,
|
functions: HashMap<String, TypeConstructor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@@ -21,6 +127,7 @@ pub enum TypeType {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct EnvType {
|
pub struct EnvType {
|
||||||
|
generic: ast::Generic,
|
||||||
is_a: TypeType,
|
is_a: TypeType,
|
||||||
fields: HashMap<String, ast::TypeUsage>,
|
fields: HashMap<String, ast::TypeUsage>,
|
||||||
impls: Vec<EnvImpl>,
|
impls: Vec<EnvImpl>,
|
||||||
@@ -29,6 +136,7 @@ pub struct EnvType {
|
|||||||
impl EnvType {
|
impl EnvType {
|
||||||
fn from_struct(struct_: &ast::StructTypeDeclaration) -> EnvType {
|
fn from_struct(struct_: &ast::StructTypeDeclaration) -> EnvType {
|
||||||
return EnvType {
|
return EnvType {
|
||||||
|
generic: struct_.generic.clone(),
|
||||||
is_a: TypeType::Struct,
|
is_a: TypeType::Struct,
|
||||||
fields: struct_
|
fields: struct_
|
||||||
.fields
|
.fields
|
||||||
@@ -44,42 +152,65 @@ impl EnvType {
|
|||||||
for func in trait_.functions.iter() {
|
for func in trait_.functions.iter() {
|
||||||
match func {
|
match func {
|
||||||
ast::TraitItem::FunctionDeclaration(fd) => {
|
ast::TraitItem::FunctionDeclaration(fd) => {
|
||||||
functions.insert(fd.name.name.value.to_string(), fd.to_type());
|
functions.insert(fd.name.name.value.to_string(), TypeConstructor::from_declaration(&fd));
|
||||||
}
|
}
|
||||||
ast::TraitItem::Function(f) => {
|
ast::TraitItem::Function(f) => {
|
||||||
functions.insert(f.declaration.name.name.value.to_string(), f.declaration.to_type());
|
functions.insert(f.declaration.name.name.value.to_string(), TypeConstructor::from_declaration(&f.declaration));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let impl_ = EnvImpl {
|
let impl_ = EnvImpl {
|
||||||
trait_: None,
|
trait_: Some(trait_.name.name.value.to_string()),
|
||||||
functions: functions,
|
functions: functions,
|
||||||
};
|
};
|
||||||
return EnvType {
|
return EnvType {
|
||||||
|
generic: trait_.generic.clone(),
|
||||||
is_a: TypeType::Trait,
|
is_a: TypeType::Trait,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![impl_],
|
impls: vec![impl_],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_construct(&self, ctx: &Context, usage: &ast::GenericUsage) -> Result<EnvType> {
|
||||||
|
let mut fields = HashMap::new();
|
||||||
|
for (k, v) in self.fields.iter() {
|
||||||
|
let type_usage = TypeConstructor{generic: self.generic.clone(), type_usage: v.clone()}.construct(ctx, usage)?;
|
||||||
|
fields.insert(k.clone(), type_usage);
|
||||||
|
}
|
||||||
|
let mut impls = vec!();
|
||||||
|
for impl_ in self.impls.iter() {
|
||||||
|
let mut functions = HashMap::new();
|
||||||
|
for (name, func) in impl_.functions.iter() {
|
||||||
|
let type_usage = TypeConstructor{generic: self.generic.clone(), type_usage: func.type_usage.clone()}.construct(ctx, usage)?;
|
||||||
|
functions.insert(name.clone(), TypeConstructor{generic: func.generic.clone(), type_usage: type_usage});
|
||||||
|
}
|
||||||
|
impls.push(EnvImpl{
|
||||||
|
trait_: impl_.trait_.clone(),
|
||||||
|
functions: functions,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Ok(EnvType{
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
|
is_a: self.is_a.clone(),
|
||||||
|
fields: fields,
|
||||||
|
impls: impls,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum NamedEntity {
|
pub enum NamedEntity {
|
||||||
NamedType(EnvType),
|
NamedType(EnvType),
|
||||||
|
Function(TypeConstructor),
|
||||||
Variable(ast::TypeUsage),
|
Variable(ast::TypeUsage),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
struct Context {
|
|
||||||
pub current_function_return: Option<ast::TypeUsage>,
|
|
||||||
pub environment: HashMap<String, NamedEntity>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_builtins() -> HashMap<String, NamedEntity> {
|
fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||||
let mut result = HashMap::new();
|
let mut result = HashMap::new();
|
||||||
result.insert(
|
result.insert(
|
||||||
"i8".to_string(),
|
"i8".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -88,6 +219,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"i16".to_string(),
|
"i16".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -96,6 +228,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"i32".to_string(),
|
"i32".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -104,6 +237,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"i64".to_string(),
|
"i64".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -112,6 +246,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"isize".to_string(),
|
"isize".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -121,6 +256,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"u8".to_string(),
|
"u8".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -129,6 +265,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"u16".to_string(),
|
"u16".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -137,6 +274,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"u32".to_string(),
|
"u32".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -145,6 +283,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"u64".to_string(),
|
"u64".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -153,6 +292,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"usize".to_string(),
|
"usize".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -162,6 +302,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"f32".to_string(),
|
"f32".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -170,6 +311,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"f64".to_string(),
|
"f64".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -179,6 +321,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"bool".to_string(),
|
"bool".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -187,6 +330,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"!".to_string(),
|
"!".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -195,6 +339,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
result.insert(
|
result.insert(
|
||||||
"unit".to_string(),
|
"unit".to_string(),
|
||||||
NamedEntity::NamedType(EnvType {
|
NamedEntity::NamedType(EnvType {
|
||||||
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: TypeType::Scalar,
|
is_a: TypeType::Scalar,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
@@ -205,20 +350,24 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
|
|
||||||
enum StructAttr {
|
enum StructAttr {
|
||||||
Field(ast::TypeUsage),
|
Field(ast::TypeUsage),
|
||||||
Method(ast::TypeUsage),
|
Method(TypeConstructor),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_self(type_name: &str, type_: &ast::TypeUsage) -> ast::TypeUsage {
|
fn apply_self(type_name: &str, constructor: &TypeConstructor) -> TypeConstructor {
|
||||||
match type_ {
|
match &constructor.type_usage {
|
||||||
ast::TypeUsage::Function(func) => {
|
ast::TypeUsage::Function(func) => {
|
||||||
if func.arguments.len() > 0 {
|
if func.arguments.len() > 0 {
|
||||||
match &func.arguments[0] {
|
match &func.arguments[0] {
|
||||||
ast::TypeUsage::Named(named) => {
|
ast::TypeUsage::Named(named) => {
|
||||||
if type_name == named.name.name.value {
|
if type_name == named.name.name.value {
|
||||||
return ast::TypeUsage::Function(ast::FunctionTypeUsage {
|
let result = ast::TypeUsage::Function(ast::FunctionTypeUsage {
|
||||||
arguments: func.arguments[1..func.arguments.len()].iter().map(|arg| arg.clone()).collect(),
|
arguments: func.arguments[1..func.arguments.len()].iter().map(|arg| arg.clone()).collect(),
|
||||||
return_type: func.return_type.clone(),
|
return_type: func.return_type.clone(),
|
||||||
});
|
});
|
||||||
|
return TypeConstructor{
|
||||||
|
generic: constructor.generic.clone(),
|
||||||
|
type_usage: result,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -227,7 +376,7 @@ fn apply_self(type_name: &str, type_: &ast::TypeUsage) -> ast::TypeUsage {
|
|||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
return type_.clone();
|
return constructor.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier) -> Result<StructAttr> {
|
fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier) -> Result<StructAttr> {
|
||||||
@@ -256,7 +405,12 @@ fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier)
|
|||||||
}
|
}
|
||||||
NamedEntity::Variable(type_) => match type_ {
|
NamedEntity::Variable(type_) => match type_ {
|
||||||
ast::TypeUsage::Named(named) => {
|
ast::TypeUsage::Named(named) => {
|
||||||
let attr = get_attr(ctx, &ctx.environment[&named.name.name.value], attribute)?;
|
let env_type = match &ctx.environment[&named.name.name.value] {
|
||||||
|
NamedEntity::NamedType(env_type) => env_type,
|
||||||
|
_ => panic!("variable has non-type as type"),
|
||||||
|
};
|
||||||
|
let type_ = env_type.type_construct(ctx, &named.type_parameters)?;
|
||||||
|
let attr = get_attr(ctx, &NamedEntity::NamedType(type_), attribute)?;
|
||||||
let method = match attr {
|
let method = match attr {
|
||||||
StructAttr::Field(field) => return Ok(StructAttr::Field(field)),
|
StructAttr::Field(field) => return Ok(StructAttr::Field(field)),
|
||||||
StructAttr::Method(method) => method,
|
StructAttr::Method(method) => method,
|
||||||
@@ -269,8 +423,20 @@ fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
NamedEntity::Function(_) => {
|
||||||
|
return Err(errors::TypingError::AttributeOfNonstruct {
|
||||||
|
identifier: attribute.clone(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
struct Context {
|
||||||
|
pub current_function_return: Option<ast::TypeUsage>,
|
||||||
|
pub environment: HashMap<String, NamedEntity>,
|
||||||
|
pub id_generator: Rc<ast::IdGenerator>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
fn add_variable(&self, name: String, type_usage: &ast::TypeUsage) -> Context {
|
fn add_variable(&self, name: String, type_usage: &ast::TypeUsage) -> Context {
|
||||||
@@ -289,11 +455,16 @@ impl Context {
|
|||||||
let mut ctx = self.clone();
|
let mut ctx = self.clone();
|
||||||
for parameter in generic.parameters.iter() {
|
for parameter in generic.parameters.iter() {
|
||||||
let mut env_type = EnvType{
|
let mut env_type = EnvType{
|
||||||
|
generic: ast::Generic{
|
||||||
|
parameters: vec!(),
|
||||||
|
},
|
||||||
is_a: TypeType::Trait,
|
is_a: TypeType::Trait,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
impls: vec!(),
|
impls: vec!(),
|
||||||
};
|
};
|
||||||
for bound in parameter.bounds.iter() {
|
for bound in parameter.bounds.iter() {
|
||||||
|
println!("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
|
||||||
|
println!("found bound: {:?}", bound);
|
||||||
if !self.environment.contains_key(&bound.name.value) {
|
if !self.environment.contains_key(&bound.name.value) {
|
||||||
return Err(errors::TypingError::TypeDoesNotExist {
|
return Err(errors::TypingError::TypeDoesNotExist {
|
||||||
identifier: bound.clone(),
|
identifier: bound.clone(),
|
||||||
@@ -314,7 +485,7 @@ impl Context {
|
|||||||
fn add_impl(&self, impl_: &ast::Impl, traits: &HashMap<String, ast::TraitTypeDeclaration>) -> Result<Context> {
|
fn add_impl(&self, impl_: &ast::Impl, traits: &HashMap<String, ast::TraitTypeDeclaration>) -> Result<Context> {
|
||||||
let mut functions = HashMap::new();
|
let mut functions = HashMap::new();
|
||||||
for func in impl_.functions.iter() {
|
for func in impl_.functions.iter() {
|
||||||
functions.insert(func.declaration.name.name.value.to_string(), func.declaration.to_type());
|
functions.insert(func.declaration.name.name.value.to_string(), TypeConstructor::from_declaration(&func.declaration));
|
||||||
}
|
}
|
||||||
// fill out defaults
|
// fill out defaults
|
||||||
match &impl_.trait_ {
|
match &impl_.trait_ {
|
||||||
@@ -330,7 +501,7 @@ impl Context {
|
|||||||
if !functions.contains_key(&default_function.declaration.name.name.value) {
|
if !functions.contains_key(&default_function.declaration.name.name.value) {
|
||||||
functions.insert(
|
functions.insert(
|
||||||
default_function.declaration.name.name.value.to_string(),
|
default_function.declaration.name.name.value.to_string(),
|
||||||
default_function.declaration.to_type(),
|
TypeConstructor::from_declaration(&default_function.declaration),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,7 +527,12 @@ impl Context {
|
|||||||
.insert(impl_.struct_.name.name.value.to_string(), NamedEntity::NamedType(env_type.clone()));
|
.insert(impl_.struct_.name.name.value.to_string(), NamedEntity::NamedType(env_type.clone()));
|
||||||
}
|
}
|
||||||
NamedEntity::Variable(_) => {
|
NamedEntity::Variable(_) => {
|
||||||
return Err(errors::TypingError::TypeDoesNotExist {
|
return Err(errors::TypingError::IdentifierIsNotType {
|
||||||
|
identifier: impl_.struct_.name.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
NamedEntity::Function(_) => {
|
||||||
|
return Err(errors::TypingError::IdentifierIsNotType {
|
||||||
identifier: impl_.struct_.name.clone(),
|
identifier: impl_.struct_.name.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -369,6 +545,7 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
|
|||||||
let result = match type_ {
|
let result = match type_ {
|
||||||
ast::TypeUsage::Named(named) => {
|
ast::TypeUsage::Named(named) => {
|
||||||
if !ctx.environment.contains_key(&named.name.name.value) {
|
if !ctx.environment.contains_key(&named.name.name.value) {
|
||||||
|
panic!("foo");
|
||||||
return Err(errors::TypingError::TypeDoesNotExist {
|
return Err(errors::TypingError::TypeDoesNotExist {
|
||||||
identifier: named.name.clone(),
|
identifier: named.name.clone(),
|
||||||
});
|
});
|
||||||
@@ -385,6 +562,7 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::TypeUsage::Unknown(_) => {} // do nothing
|
ast::TypeUsage::Unknown(_) => {} // do nothing
|
||||||
|
ast::TypeUsage::Namespace(_) => {}
|
||||||
ast::TypeUsage::Function(function) => {
|
ast::TypeUsage::Function(function) => {
|
||||||
let mut errs = vec![];
|
let mut errs = vec![];
|
||||||
for arg in function.arguments.iter() {
|
for arg in function.arguments.iter() {
|
||||||
@@ -415,6 +593,9 @@ fn apply_substitution(ctx: &Context, substitution: &SubstitutionMap, type_: &ast
|
|||||||
ast::TypeUsage::Unknown(unknown.clone())
|
ast::TypeUsage::Unknown(unknown.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::TypeUsage::Namespace(namespace) => {
|
||||||
|
ast::TypeUsage::Namespace(namespace.clone())
|
||||||
|
}
|
||||||
ast::TypeUsage::Function(function) => {
|
ast::TypeUsage::Function(function) => {
|
||||||
let mut arguments = vec![];
|
let mut arguments = vec![];
|
||||||
for arg in function.arguments.iter() {
|
for arg in function.arguments.iter() {
|
||||||
@@ -507,6 +688,7 @@ fn contains(t: &ast::TypeUsage, name: &str) -> bool {
|
|||||||
match t {
|
match t {
|
||||||
ast::TypeUsage::Named(_) => return false,
|
ast::TypeUsage::Named(_) => return false,
|
||||||
ast::TypeUsage::Unknown(unknown) => unknown.name == name,
|
ast::TypeUsage::Unknown(unknown) => unknown.name == name,
|
||||||
|
ast::TypeUsage::Namespace(_) => return false,
|
||||||
ast::TypeUsage::Function(f) => {
|
ast::TypeUsage::Function(f) => {
|
||||||
if contains(&*f.return_type, name) {
|
if contains(&*f.return_type, name) {
|
||||||
return true;
|
return true;
|
||||||
@@ -528,6 +710,7 @@ impl TypeChecker {
|
|||||||
let mut ctx = Context {
|
let mut ctx = Context {
|
||||||
environment: create_builtins(),
|
environment: create_builtins(),
|
||||||
current_function_return: None,
|
current_function_return: None,
|
||||||
|
id_generator: Rc::new(ast::IdGenerator::new("T")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut traits = HashMap::new();
|
let mut traits = HashMap::new();
|
||||||
@@ -554,7 +737,10 @@ impl TypeChecker {
|
|||||||
};
|
};
|
||||||
ctx.environment.insert(
|
ctx.environment.insert(
|
||||||
function.declaration.name.name.value.to_string(),
|
function.declaration.name.name.value.to_string(),
|
||||||
NamedEntity::Variable(ast::TypeUsage::Function(function_type)),
|
NamedEntity::Function(TypeConstructor{
|
||||||
|
generic: function.declaration.generic.clone(),
|
||||||
|
type_usage: ast::TypeUsage::Function(function_type),
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -743,6 +929,7 @@ impl TypeChecker {
|
|||||||
&impl_ctx,
|
&impl_ctx,
|
||||||
&ast::TypeUsage::new_named(&impl_.struct_.name.clone(), &ast::GenericUsage::Unknown),
|
&ast::TypeUsage::new_named(&impl_.struct_.name.clone(), &ast::GenericUsage::Unknown),
|
||||||
)?;
|
)?;
|
||||||
|
println!("env {:?}", impl_ctx);
|
||||||
let mut functions = vec![];
|
let mut functions = vec![];
|
||||||
for function in impl_.functions.iter() {
|
for function in impl_.functions.iter() {
|
||||||
let (result, function_subs) = self.with_function(&impl_ctx, &substitutions, function)?;
|
let (result, function_subs) = self.with_function(&impl_ctx, &substitutions, function)?;
|
||||||
@@ -900,8 +1087,8 @@ impl TypeChecker {
|
|||||||
ast::AssignmentTarget::Variable(variable) => {
|
ast::AssignmentTarget::Variable(variable) => {
|
||||||
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable.type_, &expr.type_)?)?;
|
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable.type_, &expr.type_)?)?;
|
||||||
ast::AssignmentTarget::Variable(ast::VariableUsage {
|
ast::AssignmentTarget::Variable(ast::VariableUsage {
|
||||||
type_parameters: variable.type_parameters.clone(),
|
|
||||||
name: variable.name.clone(),
|
name: variable.name.clone(),
|
||||||
|
type_parameters: variable.type_parameters.clone(),
|
||||||
type_: apply_substitution(ctx, &substitution, &variable.type_)?,
|
type_: apply_substitution(ctx, &substitution, &variable.type_)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1070,7 +1257,7 @@ impl TypeChecker {
|
|||||||
let mut substitution = substitution.clone();
|
let mut substitution = substitution.clone();
|
||||||
let struct_type = match &ctx.environment[&literal_struct.name.name.value] {
|
let struct_type = match &ctx.environment[&literal_struct.name.name.value] {
|
||||||
NamedEntity::NamedType(env_type) => match &env_type.is_a {
|
NamedEntity::NamedType(env_type) => match &env_type.is_a {
|
||||||
TypeType::Struct => env_type.clone(),
|
TypeType::Struct => env_type.type_construct(ctx, &literal_struct.type_parameters)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(errors::TypingError::NotAStructLiteral {
|
return Err(errors::TypingError::NotAStructLiteral {
|
||||||
identifier: literal_struct.name.clone(),
|
identifier: literal_struct.name.clone(),
|
||||||
@@ -1177,19 +1364,21 @@ impl TypeChecker {
|
|||||||
) -> Result<(ast::VariableUsage, SubstitutionMap)> {
|
) -> Result<(ast::VariableUsage, SubstitutionMap)> {
|
||||||
let mut substitution = substitution.clone();
|
let mut substitution = substitution.clone();
|
||||||
match &ctx.environment[&variable_usage.name.name.value] {
|
match &ctx.environment[&variable_usage.name.name.value] {
|
||||||
NamedEntity::NamedType(_) => {
|
NamedEntity::NamedType(named_type) => {
|
||||||
return Err(errors::TypingError::TypeIsNotAnExpression {
|
let type_ = ast::TypeUsage::Namespace(ast::NamespaceTypeUsage::Type(ast::NamedTypeUsage{name: variable_usage.name.clone(), type_parameters: variable_usage.type_parameters.clone()}));
|
||||||
type_name: variable_usage.name.clone(),
|
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &type_)?)?;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
NamedEntity::Variable(variable) => {
|
NamedEntity::Variable(variable) => {
|
||||||
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &variable)?)?;
|
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &variable)?)?;
|
||||||
}
|
}
|
||||||
|
NamedEntity::Function(function) => {
|
||||||
|
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &function.construct(ctx, &variable_usage.type_parameters)?)?)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok((
|
Ok((
|
||||||
ast::VariableUsage {
|
ast::VariableUsage {
|
||||||
type_parameters: variable_usage.type_parameters.clone(),
|
|
||||||
name: variable_usage.name.clone(),
|
name: variable_usage.name.clone(),
|
||||||
|
type_parameters: variable_usage.type_parameters.clone(), // Redundant to type
|
||||||
type_: apply_substitution(ctx, &substitution, &variable_usage.type_)?,
|
type_: apply_substitution(ctx, &substitution, &variable_usage.type_)?,
|
||||||
},
|
},
|
||||||
substitution,
|
substitution,
|
||||||
@@ -1290,11 +1479,12 @@ impl TypeChecker {
|
|||||||
) -> Result<(ast::StructGetter, SubstitutionMap)> {
|
) -> Result<(ast::StructGetter, SubstitutionMap)> {
|
||||||
let mut substitution = substitution.clone();
|
let mut substitution = substitution.clone();
|
||||||
let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source)?;
|
let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source)?;
|
||||||
|
println!("source: {:?}", &source);
|
||||||
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
||||||
|
|
||||||
let field_type = match get_attr(ctx, &NamedEntity::Variable(source.type_.clone()), &struct_getter.attribute)? {
|
let field_type = match get_attr(ctx, &NamedEntity::Variable(source.type_.clone()), &struct_getter.attribute)? {
|
||||||
StructAttr::Field(type_) => type_,
|
StructAttr::Field(type_) => type_,
|
||||||
StructAttr::Method(type_) => type_,
|
StructAttr::Method(constructor) => constructor.construct(ctx, &struct_getter.type_parameters)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &struct_getter.type_, &field_type)?)?;
|
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &struct_getter.type_, &field_type)?)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user