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"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"inkwell",
|
||||
"lalrpop",
|
||||
"lalrpop-util",
|
||||
"regex",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@@ -196,39 +189,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "itertools"
|
||||
version = "0.10.1"
|
||||
@@ -282,28 +242,6 @@ version = "0.2.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
@@ -331,31 +269,6 @@ version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "petgraph"
|
||||
version = "0.5.1"
|
||||
@@ -448,39 +361,12 @@ version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "siphasher"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.1"
|
||||
|
||||
@@ -13,6 +13,6 @@ features = ["lexer"]
|
||||
[dependencies]
|
||||
lalrpop-util = "0.19.6"
|
||||
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"
|
||||
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;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct IdGenerator {
|
||||
id_key: String,
|
||||
counter: RefCell<i64>,
|
||||
}
|
||||
|
||||
impl IdGenerator {
|
||||
pub fn new() -> Self {
|
||||
IdGenerator { counter: RefCell::new(0) }
|
||||
pub fn new(key: &str) -> Self {
|
||||
IdGenerator { id_key: key.to_string(), counter: RefCell::new(0) }
|
||||
}
|
||||
|
||||
pub fn next(&self) -> String {
|
||||
*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,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum NamespaceTypeUsage {
|
||||
Type(NamedTypeUsage)
|
||||
// Module
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum TypeUsage {
|
||||
Function(FunctionTypeUsage),
|
||||
Named(NamedTypeUsage),
|
||||
Unknown(UnknownTypeUsage),
|
||||
Namespace(NamespaceTypeUsage)
|
||||
}
|
||||
|
||||
impl TypeUsage {
|
||||
@@ -200,8 +209,8 @@ pub struct Operation {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct VariableUsage {
|
||||
pub type_parameters: GenericUsage,
|
||||
pub name: Identifier,
|
||||
pub type_parameters: GenericUsage,
|
||||
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")]
|
||||
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")]
|
||||
MultipleErrors { errors: Vec<TypingError> },
|
||||
}
|
||||
|
||||
@@ -117,8 +117,8 @@ pub StructGetter: ast::StructGetter = {
|
||||
|
||||
pub VariableUsage: ast::VariableUsage = {
|
||||
<identifier:SpannedIdentifier> <gu:GenericUsage?> => match gu {
|
||||
Some(tp) => ast::VariableUsage{type_parameters: tp, name: identifier, type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||
None => ast::VariableUsage{type_parameters: ast::GenericUsage::Unknown, 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{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 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
|
||||
// println!("ast: {:#?}", &module_ast);
|
||||
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);
|
||||
let trait_checker = trait_checking::TraitChecker {};
|
||||
match trait_checker.with_module(&resolved_ast) {
|
||||
@@ -76,7 +83,7 @@ fn main() {
|
||||
|
||||
#[test]
|
||||
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::IdentifierParser::new().parse(&id_gen, "foo").is_ok());
|
||||
assert!(grammar::LiteralIntParser::new().parse(&id_gen, "2a").is_err());
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::ast;
|
||||
use crate::errors;
|
||||
|
||||
pub type Result<T, E = errors::TypingError> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
struct Context {
|
||||
@@ -26,19 +29,38 @@ fn resolve_type(ctx: &Context, type_: &ast::NamedTypeUsage) -> ast::TypeUsage {
|
||||
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_ {
|
||||
ast::TypeUsage::Named(named) => {
|
||||
return resolve_type(ctx, named);
|
||||
return Ok(resolve_type(ctx, named));
|
||||
}
|
||||
ast::TypeUsage::Function(function) => {
|
||||
return ast::TypeUsage::Function(ast::FunctionTypeUsage {
|
||||
arguments: function.arguments.iter().map(|a| process_type(ctx, &a.clone())).collect(),
|
||||
return_type: Box::new(process_type(ctx, &function.return_type.clone())),
|
||||
});
|
||||
let mut arguments = vec!();
|
||||
for a in function.arguments.iter() {
|
||||
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) => {
|
||||
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 {}
|
||||
|
||||
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![] };
|
||||
for item in module.items.iter() {
|
||||
match item {
|
||||
@@ -57,77 +79,78 @@ impl TypeAliasResolver {
|
||||
}
|
||||
}
|
||||
|
||||
return ast::Module {
|
||||
items: module
|
||||
.items
|
||||
.iter()
|
||||
.map(|item| match item {
|
||||
ast::ModuleItem::Function(function) => ast::ModuleItem::Function(self.with_function(&ctx, function)),
|
||||
let mut items = vec!();
|
||||
for item in module.items.iter() {
|
||||
items.push(match item {
|
||||
ast::ModuleItem::Function(function) => ast::ModuleItem::Function(self.with_function(&ctx, function)?),
|
||||
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_)),
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
ast::ModuleItem::Impl(impl_) => ast::ModuleItem::Impl(self.with_impl(&ctx, impl_)?),
|
||||
});
|
||||
}
|
||||
|
||||
fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> ast::Function {
|
||||
return ast::Function {
|
||||
declaration: self.with_function_declaration(ctx, &function.declaration),
|
||||
block: self.with_block(ctx, &function.block),
|
||||
};
|
||||
return Ok(ast::Module {
|
||||
items: items,
|
||||
});
|
||||
}
|
||||
|
||||
fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> ast::FunctionDeclaration {
|
||||
return ast::FunctionDeclaration {
|
||||
fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> Result<ast::Function> {
|
||||
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(),
|
||||
generic: declaration.generic.clone(),
|
||||
arguments: declaration
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|arg| ast::VariableDeclaration {
|
||||
name: arg.name.clone(),
|
||||
type_: process_type(ctx, &arg.type_),
|
||||
})
|
||||
.collect(),
|
||||
return_type: process_type(ctx, &declaration.return_type),
|
||||
};
|
||||
arguments: arguments,
|
||||
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 {
|
||||
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) => {
|
||||
return ast::TypeDeclaration::Primitive(primitive.clone());
|
||||
return Ok(ast::TypeDeclaration::Primitive(primitive.clone()));
|
||||
}
|
||||
ast::TypeDeclaration::Alias(alias) => {
|
||||
return ast::TypeDeclaration::Alias(alias.clone());
|
||||
return Ok(ast::TypeDeclaration::Alias(alias.clone()));
|
||||
}
|
||||
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 {
|
||||
return ast::StructTypeDeclaration {
|
||||
fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> Result<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(),
|
||||
name: struct_.name.clone(),
|
||||
fields: struct_
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field| ast::StructField {
|
||||
name: field.name.clone(),
|
||||
type_: process_type(ctx, &field.type_),
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
fields: fields,
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
trait_ctx.type_aliases.push(ast::AliasTypeDeclaration {
|
||||
name: ast::Identifier {
|
||||
@@ -141,23 +164,23 @@ impl TypeAliasResolver {
|
||||
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(),
|
||||
name: trait_.name.clone(),
|
||||
functions: trait_
|
||||
.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(),
|
||||
};
|
||||
functions: functions,
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
impl_ctx.type_aliases.push(ast::AliasTypeDeclaration {
|
||||
name: ast::Identifier {
|
||||
@@ -168,85 +191,93 @@ impl TypeAliasResolver {
|
||||
},
|
||||
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(),
|
||||
trait_: impl_.trait_.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 {
|
||||
return ast::Block {
|
||||
statements: block.statements.iter().map(|s| self.with_statement(ctx, s)).collect(),
|
||||
type_: process_type(ctx, &block.type_),
|
||||
};
|
||||
fn with_block(self: &Self, ctx: &Context, block: &ast::Block) -> Result<ast::Block> {
|
||||
let mut statements = vec!();
|
||||
for s in block.statements.iter() {
|
||||
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 {
|
||||
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) => {
|
||||
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) => {
|
||||
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) => {
|
||||
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 {
|
||||
return ast::ReturnStatement {
|
||||
source: self.with_expression(ctx, &statement.source),
|
||||
};
|
||||
fn with_return_statement(self: &Self, ctx: &Context, statement: &ast::ReturnStatement) -> Result<ast::ReturnStatement> {
|
||||
return Ok(ast::ReturnStatement {
|
||||
source: self.with_expression(ctx, &statement.source)?,
|
||||
});
|
||||
}
|
||||
|
||||
fn with_let_statement(self: &Self, ctx: &Context, statement: &ast::LetStatement) -> ast::LetStatement {
|
||||
return ast::LetStatement {
|
||||
fn with_let_statement(self: &Self, ctx: &Context, statement: &ast::LetStatement) -> Result<ast::LetStatement> {
|
||||
return Ok(ast::LetStatement {
|
||||
variable_name: statement.variable_name.clone(),
|
||||
expression: self.with_expression(ctx, &statement.expression),
|
||||
type_: process_type(ctx, &statement.type_),
|
||||
};
|
||||
expression: self.with_expression(ctx, &statement.expression)?,
|
||||
type_: process_type(ctx, &statement.type_)?,
|
||||
});
|
||||
}
|
||||
|
||||
fn with_assignment_statement(self: &Self, ctx: &Context, statement: &ast::AssignmentStatement) -> ast::AssignmentStatement {
|
||||
return ast::AssignmentStatement {
|
||||
fn with_assignment_statement(self: &Self, ctx: &Context, statement: &ast::AssignmentStatement) -> Result<ast::AssignmentStatement> {
|
||||
return Ok(ast::AssignmentStatement {
|
||||
source: match &statement.source {
|
||||
ast::AssignmentTarget::Variable(variable) => ast::AssignmentTarget::Variable(ast::VariableUsage {
|
||||
type_parameters: variable.type_parameters.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 {
|
||||
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(),
|
||||
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 {
|
||||
return ast::Expression {
|
||||
fn with_expression(self: &Self, ctx: &Context, expression: &ast::Expression) -> Result<ast::Expression> {
|
||||
return Ok(ast::Expression {
|
||||
subexpression: Box::new(match &*expression.subexpression {
|
||||
ast::Subexpression::LiteralInt(literal_int) => ast::Subexpression::LiteralInt(ast::LiteralInt {
|
||||
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 {
|
||||
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 {
|
||||
value: literal_bool.value.clone(),
|
||||
type_: process_type(ctx, &literal_bool.type_),
|
||||
type_: process_type(ctx, &literal_bool.type_)?,
|
||||
}),
|
||||
ast::Subexpression::LiteralStruct(literal_struct) => {
|
||||
let result = resolve_type(
|
||||
@@ -260,50 +291,56 @@ impl TypeAliasResolver {
|
||||
ast::TypeUsage::Named(named) => named.name.clone(),
|
||||
_ => 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 {
|
||||
type_parameters: literal_struct.type_parameters.clone(),
|
||||
name: new_name.clone(),
|
||||
fields: literal_struct
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field| (field.0.clone(), self.with_expression(ctx, &field.1)))
|
||||
.collect(),
|
||||
type_: process_type(ctx, &literal_struct.type_),
|
||||
fields: fields,
|
||||
type_: process_type(ctx, &literal_struct.type_)?,
|
||||
})
|
||||
}
|
||||
ast::Subexpression::FunctionCall(function_call) => ast::Subexpression::FunctionCall(ast::FunctionCall {
|
||||
source: self.with_expression(ctx, &function_call.source),
|
||||
arguments: function_call.arguments.iter().map(|arg| self.with_expression(ctx, arg)).collect(),
|
||||
type_: process_type(ctx, &function_call.type_),
|
||||
}),
|
||||
ast::Subexpression::FunctionCall(function_call) => {
|
||||
let mut arguments = vec!();
|
||||
for arg in function_call.arguments.iter() {
|
||||
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 {
|
||||
type_parameters: variable_usage.type_parameters.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 {
|
||||
condition: self.with_expression(ctx, &if_expression.condition),
|
||||
block: self.with_block(ctx, &if_expression.block),
|
||||
condition: self.with_expression(ctx, &if_expression.condition)?,
|
||||
block: self.with_block(ctx, &if_expression.block)?,
|
||||
else_: match &if_expression.else_ {
|
||||
Some(else_) => Some(self.with_block(ctx, else_)),
|
||||
Some(else_) => Some(self.with_block(ctx, else_)?),
|
||||
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 {
|
||||
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(),
|
||||
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 {
|
||||
left: self.with_expression(ctx, &op.left),
|
||||
left: self.with_expression(ctx, &op.left)?,
|
||||
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::errors;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub type SubstitutionMap = HashMap<String, ast::TypeUsage>;
|
||||
|
||||
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)]
|
||||
pub struct EnvImpl {
|
||||
trait_: Option<String>,
|
||||
functions: HashMap<String, ast::TypeUsage>,
|
||||
functions: HashMap<String, TypeConstructor>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@@ -21,6 +127,7 @@ pub enum TypeType {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EnvType {
|
||||
generic: ast::Generic,
|
||||
is_a: TypeType,
|
||||
fields: HashMap<String, ast::TypeUsage>,
|
||||
impls: Vec<EnvImpl>,
|
||||
@@ -29,6 +136,7 @@ pub struct EnvType {
|
||||
impl EnvType {
|
||||
fn from_struct(struct_: &ast::StructTypeDeclaration) -> EnvType {
|
||||
return EnvType {
|
||||
generic: struct_.generic.clone(),
|
||||
is_a: TypeType::Struct,
|
||||
fields: struct_
|
||||
.fields
|
||||
@@ -44,42 +152,65 @@ impl EnvType {
|
||||
for func in trait_.functions.iter() {
|
||||
match func {
|
||||
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) => {
|
||||
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 {
|
||||
trait_: None,
|
||||
trait_: Some(trait_.name.name.value.to_string()),
|
||||
functions: functions,
|
||||
};
|
||||
return EnvType {
|
||||
generic: trait_.generic.clone(),
|
||||
is_a: TypeType::Trait,
|
||||
fields: HashMap::new(),
|
||||
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)]
|
||||
pub enum NamedEntity {
|
||||
NamedType(EnvType),
|
||||
Function(TypeConstructor),
|
||||
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> {
|
||||
let mut result = HashMap::new();
|
||||
result.insert(
|
||||
"i8".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -88,6 +219,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"i16".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -96,6 +228,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"i32".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -104,6 +237,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"i64".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -112,6 +246,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"isize".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -121,6 +256,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"u8".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -129,6 +265,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"u16".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -137,6 +274,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"u32".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -145,6 +283,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"u64".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -153,6 +292,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"usize".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -162,6 +302,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"f32".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -170,6 +311,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"f64".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -179,6 +321,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"bool".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -187,6 +330,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"!".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -195,6 +339,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"unit".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -205,20 +350,24 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
|
||||
enum StructAttr {
|
||||
Field(ast::TypeUsage),
|
||||
Method(ast::TypeUsage),
|
||||
Method(TypeConstructor),
|
||||
}
|
||||
|
||||
fn apply_self(type_name: &str, type_: &ast::TypeUsage) -> ast::TypeUsage {
|
||||
match type_ {
|
||||
fn apply_self(type_name: &str, constructor: &TypeConstructor) -> TypeConstructor {
|
||||
match &constructor.type_usage {
|
||||
ast::TypeUsage::Function(func) => {
|
||||
if func.arguments.len() > 0 {
|
||||
match &func.arguments[0] {
|
||||
ast::TypeUsage::Named(named) => {
|
||||
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(),
|
||||
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> {
|
||||
@@ -256,7 +405,12 @@ fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier)
|
||||
}
|
||||
NamedEntity::Variable(type_) => match type_ {
|
||||
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 {
|
||||
StructAttr::Field(field) => return Ok(StructAttr::Field(field)),
|
||||
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 {
|
||||
fn add_variable(&self, name: String, type_usage: &ast::TypeUsage) -> Context {
|
||||
@@ -289,11 +455,16 @@ impl Context {
|
||||
let mut ctx = self.clone();
|
||||
for parameter in generic.parameters.iter() {
|
||||
let mut env_type = EnvType{
|
||||
generic: ast::Generic{
|
||||
parameters: vec!(),
|
||||
},
|
||||
is_a: TypeType::Trait,
|
||||
fields: HashMap::new(),
|
||||
impls: vec!(),
|
||||
};
|
||||
for bound in parameter.bounds.iter() {
|
||||
println!("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
|
||||
println!("found bound: {:?}", bound);
|
||||
if !self.environment.contains_key(&bound.name.value) {
|
||||
return Err(errors::TypingError::TypeDoesNotExist {
|
||||
identifier: bound.clone(),
|
||||
@@ -314,7 +485,7 @@ impl Context {
|
||||
fn add_impl(&self, impl_: &ast::Impl, traits: &HashMap<String, ast::TraitTypeDeclaration>) -> Result<Context> {
|
||||
let mut functions = HashMap::new();
|
||||
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
|
||||
match &impl_.trait_ {
|
||||
@@ -330,7 +501,7 @@ impl Context {
|
||||
if !functions.contains_key(&default_function.declaration.name.name.value) {
|
||||
functions.insert(
|
||||
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()));
|
||||
}
|
||||
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(),
|
||||
});
|
||||
}
|
||||
@@ -369,6 +545,7 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
|
||||
let result = match type_ {
|
||||
ast::TypeUsage::Named(named) => {
|
||||
if !ctx.environment.contains_key(&named.name.name.value) {
|
||||
panic!("foo");
|
||||
return Err(errors::TypingError::TypeDoesNotExist {
|
||||
identifier: named.name.clone(),
|
||||
});
|
||||
@@ -385,6 +562,7 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
|
||||
}
|
||||
}
|
||||
ast::TypeUsage::Unknown(_) => {} // do nothing
|
||||
ast::TypeUsage::Namespace(_) => {}
|
||||
ast::TypeUsage::Function(function) => {
|
||||
let mut errs = vec![];
|
||||
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::Namespace(namespace) => {
|
||||
ast::TypeUsage::Namespace(namespace.clone())
|
||||
}
|
||||
ast::TypeUsage::Function(function) => {
|
||||
let mut arguments = vec![];
|
||||
for arg in function.arguments.iter() {
|
||||
@@ -507,6 +688,7 @@ fn contains(t: &ast::TypeUsage, name: &str) -> bool {
|
||||
match t {
|
||||
ast::TypeUsage::Named(_) => return false,
|
||||
ast::TypeUsage::Unknown(unknown) => unknown.name == name,
|
||||
ast::TypeUsage::Namespace(_) => return false,
|
||||
ast::TypeUsage::Function(f) => {
|
||||
if contains(&*f.return_type, name) {
|
||||
return true;
|
||||
@@ -528,6 +710,7 @@ impl TypeChecker {
|
||||
let mut ctx = Context {
|
||||
environment: create_builtins(),
|
||||
current_function_return: None,
|
||||
id_generator: Rc::new(ast::IdGenerator::new("T")),
|
||||
};
|
||||
|
||||
let mut traits = HashMap::new();
|
||||
@@ -554,7 +737,10 @@ impl TypeChecker {
|
||||
};
|
||||
ctx.environment.insert(
|
||||
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,
|
||||
&ast::TypeUsage::new_named(&impl_.struct_.name.clone(), &ast::GenericUsage::Unknown),
|
||||
)?;
|
||||
println!("env {:?}", impl_ctx);
|
||||
let mut functions = vec![];
|
||||
for function in impl_.functions.iter() {
|
||||
let (result, function_subs) = self.with_function(&impl_ctx, &substitutions, function)?;
|
||||
@@ -900,8 +1087,8 @@ impl TypeChecker {
|
||||
ast::AssignmentTarget::Variable(variable) => {
|
||||
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable.type_, &expr.type_)?)?;
|
||||
ast::AssignmentTarget::Variable(ast::VariableUsage {
|
||||
type_parameters: variable.type_parameters.clone(),
|
||||
name: variable.name.clone(),
|
||||
type_parameters: variable.type_parameters.clone(),
|
||||
type_: apply_substitution(ctx, &substitution, &variable.type_)?,
|
||||
})
|
||||
}
|
||||
@@ -1070,7 +1257,7 @@ impl TypeChecker {
|
||||
let mut substitution = substitution.clone();
|
||||
let struct_type = match &ctx.environment[&literal_struct.name.name.value] {
|
||||
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 {
|
||||
identifier: literal_struct.name.clone(),
|
||||
@@ -1177,19 +1364,21 @@ impl TypeChecker {
|
||||
) -> Result<(ast::VariableUsage, SubstitutionMap)> {
|
||||
let mut substitution = substitution.clone();
|
||||
match &ctx.environment[&variable_usage.name.name.value] {
|
||||
NamedEntity::NamedType(_) => {
|
||||
return Err(errors::TypingError::TypeIsNotAnExpression {
|
||||
type_name: variable_usage.name.clone(),
|
||||
});
|
||||
NamedEntity::NamedType(named_type) => {
|
||||
let type_ = ast::TypeUsage::Namespace(ast::NamespaceTypeUsage::Type(ast::NamedTypeUsage{name: variable_usage.name.clone(), type_parameters: variable_usage.type_parameters.clone()}));
|
||||
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &type_)?)?;
|
||||
}
|
||||
NamedEntity::Variable(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((
|
||||
ast::VariableUsage {
|
||||
type_parameters: variable_usage.type_parameters.clone(),
|
||||
name: variable_usage.name.clone(),
|
||||
type_parameters: variable_usage.type_parameters.clone(), // Redundant to type
|
||||
type_: apply_substitution(ctx, &substitution, &variable_usage.type_)?,
|
||||
},
|
||||
substitution,
|
||||
@@ -1290,11 +1479,12 @@ impl TypeChecker {
|
||||
) -> Result<(ast::StructGetter, SubstitutionMap)> {
|
||||
let mut substitution = substitution.clone();
|
||||
let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source)?;
|
||||
println!("source: {:?}", &source);
|
||||
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
||||
|
||||
let field_type = match get_attr(ctx, &NamedEntity::Variable(source.type_.clone()), &struct_getter.attribute)? {
|
||||
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)?)?;
|
||||
|
||||
Reference in New Issue
Block a user