working on adding generics

This commit is contained in:
Andrew Segavac
2022-03-12 04:35:48 -07:00
parent 51c698ba5d
commit 4c1c13149d
10 changed files with 443 additions and 278 deletions

114
Cargo.lock generated
View File

@@ -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"

View File

@@ -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
View 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);
}

View File

@@ -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
View File

@@ -0,0 +1 @@
use std::collections::HashMap;

View File

@@ -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> },
} }

View File

@@ -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)},
} }
}; };

View File

@@ -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());

View File

@@ -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::TypeDeclaration(type_declaration) => {
ast::ModuleItem::Function(function) => ast::ModuleItem::Function(self.with_function(&ctx, function)), ast::ModuleItem::TypeDeclaration(self.with_type_declaration(&ctx, type_declaration)?)
ast::ModuleItem::TypeDeclaration(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(), return Ok(ast::Module {
}; items: items,
});
} }
fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> ast::Function { fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> Result<ast::Function> {
return ast::Function { return Ok(ast::Function {
declaration: self.with_function_declaration(ctx, &function.declaration), declaration: self.with_function_declaration(ctx, &function.declaration)?,
block: self.with_block(ctx, &function.block), block: self.with_block(ctx, &function.block)?,
}; });
} }
fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> ast::FunctionDeclaration { fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> Result<ast::FunctionDeclaration> {
return 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_)?,
}; });
} }
} }

View File

@@ -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(&param.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,9 +423,21 @@ 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 {
let mut ctx = self.clone(); let mut ctx = self.clone();
@@ -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)?)?;