stared redo

This commit is contained in:
2025-08-11 22:17:34 -06:00
parent 1c08ce3a0c
commit 491cf29e68
9 changed files with 167 additions and 171 deletions

View File

@@ -1,5 +1,5 @@
FROM rust:1.54 FROM rust:1.89
RUN apt update && apt-get install -y llvm clang # RUN apt update && apt-get install -y llvm clang
RUN rustup component add rustfmt RUN rustup component add rustfmt
WORKDIR /code WORKDIR /code

View File

@@ -43,13 +43,13 @@ This language is under active development, progress will be marked here as the l
- [x] Basic - [x] Basic
- [ ] Inferred - [ ] Inferred
- [ ] Higher kinded types - [ ] Higher kinded types
- [ ] Variadic generic types
- [ ] Control Flow - [ ] Control Flow
- [x] If - [x] If
- [ ] While - [ ] While
- [ ] For - [ ] For
- [ ] IO - [ ] IO
- [ ] Enums - [ ] Enums
- [ ] Errors
- [ ] Lambdas - [ ] Lambdas
- [ ] Imports - [ ] Imports
- [ ] Visibility - [ ] Visibility

View File

@@ -81,16 +81,17 @@ fn main(): i64 {
type TestTrait trait { type TestTrait trait {
fn class_method(id: i64): Self; fn class_method(id: i64): Self;
fn instance_method(self: Self): i64; fn instance_method(self: Self): i64;
fn default_impl(self: Self): i64 { fn default_impl(self: Self): i64;
return self.instance_method();
}
} }
impl TestTrait for User { impl TestTrait for User {
fn class_method(id: i64): Self { fn class_method(id: i64): Self {
return User{id: id,}; return Self{id: id,};
} }
fn instance_method(self: Self): i64 { fn instance_method(self: Self): i64 {
return self.get_id(); return self.get_id();
} }
fn default_impl(self: Self): i64 {
return self.instance_method();
}
} }

View File

@@ -1,4 +1,4 @@
use std::cell::RefCell; use std::{cell::RefCell, clone};
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct IdGenerator { pub struct IdGenerator {
@@ -8,7 +8,10 @@ pub struct IdGenerator {
impl IdGenerator { impl IdGenerator {
pub fn new(key: &str) -> Self { pub fn new(key: &str) -> Self {
IdGenerator { id_key: key.to_string(), counter: RefCell::new(0) } IdGenerator {
id_key: key.to_string(),
counter: RefCell::new(0),
}
} }
pub fn next(&self) -> String { pub fn next(&self) -> String {
@@ -72,8 +75,7 @@ pub struct UnknownTypeUsage {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum NamespaceTypeUsage { pub enum NamespaceTypeUsage {
Type(NamedTypeUsage) Type(NamedTypeUsage), // Module
// Module
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -81,7 +83,7 @@ pub enum TypeUsage {
Function(FunctionTypeUsage), Function(FunctionTypeUsage),
Named(NamedTypeUsage), Named(NamedTypeUsage),
Unknown(UnknownTypeUsage), Unknown(UnknownTypeUsage),
Namespace(NamespaceTypeUsage) Namespace(NamespaceTypeUsage),
} }
impl TypeUsage { impl TypeUsage {
@@ -114,6 +116,30 @@ impl TypeUsage {
return_type: Box::new(TypeUsage::new_unknown(&id_gen)), return_type: Box::new(TypeUsage::new_unknown(&id_gen)),
}); });
} }
pub fn replace_type(&self, old: &str, new: &Identifier) -> TypeUsage {
return match &self {
TypeUsage::Function(function) => {
return TypeUsage::Function(FunctionTypeUsage {
arguments: function.arguments.iter().map(|arg| arg.replace_type(old, new)).collect(),
return_type: Box::new(function.return_type.replace_type(old, new)),
});
}
TypeUsage::Named(named) => {
let name = if (named.name.name.value == old) {
new.clone()
} else {
named.name.clone()
};
return TypeUsage::Named(NamedTypeUsage {
type_parameters: named.type_parameters.clone(),
name: name,
});
}
TypeUsage::Namespace(namespace) => return TypeUsage::Namespace(namespace.clone()),
TypeUsage::Unknown(unkown) => return TypeUsage::Unknown(unkown.clone()),
};
}
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -347,7 +373,6 @@ pub struct StructTypeDeclaration {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TraitItem { pub enum TraitItem {
FunctionDeclaration(FunctionDeclaration), FunctionDeclaration(FunctionDeclaration),
Function(Function),
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -357,17 +382,10 @@ pub struct TraitTypeDeclaration {
pub functions: Vec<TraitItem>, pub functions: Vec<TraitItem>,
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AliasTypeDeclaration {
pub name: Identifier,
pub replaces: TypeUsage,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TypeDeclaration { pub enum TypeDeclaration {
Struct(StructTypeDeclaration), Struct(StructTypeDeclaration),
Primitive(PrimitiveTypeDeclaration), Primitive(PrimitiveTypeDeclaration),
Alias(AliasTypeDeclaration),
Trait(TraitTypeDeclaration), Trait(TraitTypeDeclaration),
} }

View File

@@ -281,13 +281,8 @@ pub StructTypeDeclaration: ast::StructTypeDeclaration = {
} }
}; };
pub AliasTypeDeclaration: ast::AliasTypeDeclaration = {
"type" <i:SpannedIdentifier> "=" <t:TypeUsage> ";" => ast::AliasTypeDeclaration{name: i, replaces: t}
};
pub TraitItem: ast::TraitItem = { pub TraitItem: ast::TraitItem = {
<fd:FunctionDeclaration> ";" => ast::TraitItem::FunctionDeclaration(fd), <fd:FunctionDeclaration> ";" => ast::TraitItem::FunctionDeclaration(fd),
<f:Function> => ast::TraitItem::Function(f),
}; };
pub TraitTypeDeclaration: ast::TraitTypeDeclaration = { pub TraitTypeDeclaration: ast::TraitTypeDeclaration = {
@@ -297,7 +292,6 @@ pub TraitTypeDeclaration: ast::TraitTypeDeclaration = {
pub TypeDeclaration: ast::TypeDeclaration = { pub TypeDeclaration: ast::TypeDeclaration = {
<s:StructTypeDeclaration> => ast::TypeDeclaration::Struct(s), <s:StructTypeDeclaration> => ast::TypeDeclaration::Struct(s),
<a:AliasTypeDeclaration> => ast::TypeDeclaration::Alias(a),
<t:TraitTypeDeclaration> => ast::TypeDeclaration::Trait(t), <t:TraitTypeDeclaration> => ast::TypeDeclaration::Trait(t),
}; };

View File

@@ -87,12 +87,6 @@ impl Context {
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(struct_.clone())), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(struct_.clone())),
); );
} }
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Alias(alias)) => {
ctx.environment.insert(
alias.name.name.value.to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Alias(alias.clone())),
);
}
ast::ModuleItem::Function(function) => { ast::ModuleItem::Function(function) => {
ctx.environment.insert( ctx.environment.insert(
function.declaration.name.name.value.to_string(), function.declaration.name.name.value.to_string(),
@@ -418,6 +412,9 @@ impl TreeWalkInterpreter {
} }
} }
ast::Subexpression::VariableUsage(variable_usage) => { ast::Subexpression::VariableUsage(variable_usage) => {
if !ctx.environment.contains_key(&variable_usage.name.name.value) {
panic!(variable_usage.name.name.value.clone());
}
let variable_value = match &ctx.environment[&variable_usage.name.name.value] { let variable_value = match &ctx.environment[&variable_usage.name.name.value] {
NamedEntity::Variable(v) => v.clone(), NamedEntity::Variable(v) => v.clone(),
_ => panic!("variable lookup of type"), _ => panic!("variable lookup of type"),
@@ -469,7 +466,7 @@ impl TreeWalkInterpreter {
if method.declaration.arguments.len() > 0 { if method.declaration.arguments.len() > 0 {
match &method.declaration.arguments[0].type_ { match &method.declaration.arguments[0].type_ {
ast::TypeUsage::Named(arg_named) => { ast::TypeUsage::Named(arg_named) => {
if arg_named.name.name.value == s.source.name.name.value { if arg_named.name.name.value == "Self" {
return ExpressionResult::Value(Value::Function(Function { return ExpressionResult::Value(Value::Function(Function {
partial: vec![source.clone()], partial: vec![source.clone()],
ref_: FunctionRef::User(method.clone()), ref_: FunctionRef::User(method.clone()),

View File

@@ -3,7 +3,6 @@ mod ast;
mod errors; mod errors;
mod interpreter; mod interpreter;
mod trait_checking; mod trait_checking;
mod type_alias_resolution;
mod type_checking; mod type_checking;
#[macro_use] #[macro_use]
extern crate lalrpop_util; extern crate lalrpop_util;
@@ -19,7 +18,7 @@ fn main() {
let matches = App::new("Boring Language Compiler") let matches = App::new("Boring Language Compiler")
.version("0.0.1") .version("0.0.1")
.author("Andrew Segavac") .author("Andrew Segavac")
.about("Compiles boring language files to LLVM IR.") .about("Compiles boringlang files")
.arg( .arg(
Arg::with_name("OUTPUT") Arg::with_name("OUTPUT")
.short("o") .short("o")
@@ -40,26 +39,18 @@ fn main() {
let unknown_id_gen = ast::IdGenerator::new("S"); 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 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(&module_ast) {
Ok(_) => {} Ok(_) => {}
Err(err) => { Err(err) => {
println!("type checking error: {:#?}", &err); println!("trait checking error: {:#?}", &err);
return; return;
} }
} }
let type_checker = type_checking::TypeChecker {}; let type_checker = type_checking::TypeChecker {};
let type_checking_result = type_checker.with_module(&resolved_ast); let type_checking_result = type_checker.with_module(&module_ast);
match &type_checking_result { match &type_checking_result {
Ok((checked_ast, subst)) => { Ok((checked_ast, subst)) => {
println!("checked ast: {:#?}", &checked_ast); println!("checked ast: {:#?}", &checked_ast);

View File

@@ -23,9 +23,7 @@ fn compare_struct_trait(
match struct_ { match struct_ {
ast::TypeUsage::Named(named) => match trait_ { ast::TypeUsage::Named(named) => match trait_ {
ast::TypeUsage::Named(trait_named) => { ast::TypeUsage::Named(trait_named) => {
if named.name.name.value == trait_named.name.name.value if named.name.name.value == trait_named.name.name.value {
|| (named.name.name.value == struct_name.name.value && trait_named.name.name.value == trait_name.name.value)
{
return Ok(()); return Ok(());
} }
return Err(errors::TypingError::TypeMismatch { return Err(errors::TypingError::TypeMismatch {
@@ -128,19 +126,6 @@ impl TraitChecker {
}); });
} }
} }
ast::TraitItem::Function(function) => {
// skip found check because it has a default
for impl_function in impl_.functions.iter() {
if impl_function.declaration.name.name.value == function.declaration.name.name.value {
compare_struct_trait(
&impl_function.declaration.to_type(),
&function.declaration.to_type(),
&impl_.struct_.name,
&trait_.name,
)?;
}
}
}
} }
} }
// assert all functions are in trait // assert all functions are in trait
@@ -148,14 +133,14 @@ impl TraitChecker {
let mut found = false; let mut found = false;
for trait_item in trait_declaration.functions.iter() { for trait_item in trait_declaration.functions.iter() {
let declaration = match trait_item { let declaration = match trait_item {
ast::TraitItem::Function(function) => &function.declaration, ast::TraitItem::FunctionDeclaration(declaration) => {
ast::TraitItem::FunctionDeclaration(declaration) => &declaration,
};
if impl_function.declaration.name.name.value == declaration.name.name.value { if impl_function.declaration.name.name.value == declaration.name.name.value {
found = true; found = true;
break; break;
} }
} }
};
}
if found == false { if found == false {
return Err(errors::TypingError::FunctionNotInTrait { return Err(errors::TypingError::FunctionNotInTrait {
function_name: impl_function.declaration.name.clone(), function_name: impl_function.declaration.name.clone(),

View File

@@ -19,10 +19,10 @@ fn type_meets_trait_bounds(ctx: &Context, type_: &ast::TypeUsage, bounds: &Vec<a
ast::TypeUsage::Named(named) => named, ast::TypeUsage::Named(named) => named,
ast::TypeUsage::Function(_) => { ast::TypeUsage::Function(_) => {
return false; return false;
}, }
ast::TypeUsage::Unknown(_) => { ast::TypeUsage::Unknown(_) => {
return true; // unknown this pass, skip, test once known return true; // unknown this pass, skip, test once known
}, }
ast::TypeUsage::Namespace(_) => { ast::TypeUsage::Namespace(_) => {
panic!("impossible"); panic!("impossible");
} }
@@ -39,7 +39,7 @@ fn type_meets_trait_bounds(ctx: &Context, type_: &ast::TypeUsage, bounds: &Vec<a
if found == false { if found == false {
return false; return false;
} }
}, }
_ => { _ => {
panic!("type is a variable, this should not happen"); panic!("type is a variable, this should not happen");
} }
@@ -57,47 +57,47 @@ fn replace_generic_with_concrete(replace: &ast::Identifier, with_type: &ast::Typ
} }
result.type_parameters = match &named.type_parameters { result.type_parameters = match &named.type_parameters {
ast::GenericUsage::Known(known) => { ast::GenericUsage::Known(known) => {
let mut param_result = vec!(); let mut param_result = vec![];
for param in known.parameters.iter() { for param in known.parameters.iter() {
param_result.push(replace_generic_with_concrete(replace, with_type, param)); param_result.push(replace_generic_with_concrete(replace, with_type, param));
} }
ast::GenericUsage::new(&param_result) ast::GenericUsage::new(&param_result)
}, }
ast::GenericUsage::Unknown => { ast::GenericUsage::Unknown => ast::GenericUsage::Unknown,
ast::GenericUsage::Unknown
},
}; };
return ast::TypeUsage::Named(result); return ast::TypeUsage::Named(result);
}, }
ast::TypeUsage::Function(func) => { ast::TypeUsage::Function(func) => {
let result = ast::TypeUsage::Function(ast::FunctionTypeUsage{ let result = ast::TypeUsage::Function(ast::FunctionTypeUsage {
arguments: func.arguments.iter().map(|arg| { arguments: func
replace_generic_with_concrete(replace, with_type, arg) .arguments
}).collect(), .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)), return_type: Box::new(replace_generic_with_concrete(replace, with_type, &func.return_type)),
}); });
return result; return result;
}, }
_ => { _ => {
// in_type is unknown, skip // in_type is unknown, skip
return in_type.clone(); return in_type.clone();
}, }
}; };
} }
impl TypeConstructor { impl TypeConstructor {
fn from_declaration(declaration: &ast::FunctionDeclaration) -> TypeConstructor { fn from_declaration(declaration: &ast::FunctionDeclaration) -> TypeConstructor {
return TypeConstructor{ return TypeConstructor {
generic: declaration.generic.clone(), generic: declaration.generic.clone(),
type_usage: declaration.to_type(), type_usage: declaration.to_type(),
} };
} }
fn construct(&self, ctx: &Context, usage: &ast::GenericUsage) -> Result<ast::TypeUsage> { fn construct(&self, ctx: &Context, usage: &ast::GenericUsage) -> Result<ast::TypeUsage> {
match usage { match usage {
ast::GenericUsage::Known(known_usage) => { ast::GenericUsage::Known(known_usage) => {
let mut result = self.type_usage.clone(); let mut result = self.type_usage.clone();
if known_usage.parameters.len() != self.generic.parameters.len() { if known_usage.parameters.len() != self.generic.parameters.len() {
return Err(errors::TypingError::WrongNumberOfTypeParameters{}); return Err(errors::TypingError::WrongNumberOfTypeParameters {});
} }
// 1. for arg in args, assert arg matches self.generic traits via impl name // 1. for arg in args, assert arg matches self.generic traits via impl name
// 2. replace type usage names with arg types // 2. replace type usage names with arg types
@@ -108,13 +108,13 @@ impl TypeConstructor {
result = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &self.type_usage); result = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &self.type_usage);
} }
return Ok(result); return Ok(result);
}, }
ast::GenericUsage::Unknown => { ast::GenericUsage::Unknown => {
// generate new Unknown Types for matching // generate new Unknown Types for matching
let mut result = self.type_usage.clone(); let mut result = self.type_usage.clone();
for param in self.generic.parameters.iter() { for param in self.generic.parameters.iter() {
let id = ctx.id_generator.next(); let id = ctx.id_generator.next();
let unknown = ast::TypeUsage::Unknown(ast::UnknownTypeUsage{name: id}); let unknown = ast::TypeUsage::Unknown(ast::UnknownTypeUsage { name: id });
result = replace_generic_with_concrete(&param.name, &unknown, &self.type_usage); result = replace_generic_with_concrete(&param.name, &unknown, &self.type_usage);
} }
return Ok(result); return Ok(result);
@@ -165,9 +165,6 @@ impl EnvType {
ast::TraitItem::FunctionDeclaration(fd) => { ast::TraitItem::FunctionDeclaration(fd) => {
functions.insert(fd.name.name.value.to_string(), TypeConstructor::from_declaration(&fd)); 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(), TypeConstructor::from_declaration(&f.declaration));
}
} }
} }
let impl_ = EnvImpl { let impl_ = EnvImpl {
@@ -190,17 +187,17 @@ impl EnvType {
let known_usage = match usage { let known_usage = match usage {
ast::GenericUsage::Known(known) => known.clone(), ast::GenericUsage::Known(known) => known.clone(),
ast::GenericUsage::Unknown => { ast::GenericUsage::Unknown => {
let mut new_unknowns = vec!(); let mut new_unknowns = vec![];
for _ in 0..self.generic.parameters.len() { for _ in 0..self.generic.parameters.len() {
new_unknowns.push(ast::TypeUsage::new_unknown(&ctx.id_generator)); new_unknowns.push(ast::TypeUsage::new_unknown(&ctx.id_generator));
} }
ast::GenericInstantiation { ast::GenericInstantiation {
parameters: new_unknowns.iter().map(|tp| tp.clone()).collect(), parameters: new_unknowns.iter().map(|tp| tp.clone()).collect(),
} }
}, }
}; };
if known_usage.parameters.len() != self.generic.parameters.len() { if known_usage.parameters.len() != self.generic.parameters.len() {
return Err(errors::TypingError::WrongNumberOfTypeParameters{}); return Err(errors::TypingError::WrongNumberOfTypeParameters {});
} }
for i in 0..known_usage.parameters.len() { for i in 0..known_usage.parameters.len() {
if !type_meets_trait_bounds(ctx, &known_usage.parameters[i], &self.generic.parameters[i].bounds) { if !type_meets_trait_bounds(ctx, &known_usage.parameters[i], &self.generic.parameters[i].bounds) {
@@ -215,21 +212,28 @@ impl EnvType {
let type_usage = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &v); let type_usage = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &v);
fields.insert(k.clone(), type_usage); fields.insert(k.clone(), type_usage);
} }
let mut impls = vec!(); let mut impls = vec![];
for impl_ in result.impls.iter() { for impl_ in result.impls.iter() {
let mut functions = HashMap::new(); let mut functions = HashMap::new();
for (name, func) in impl_.functions.iter() { for (name, func) in impl_.functions.iter() {
let type_usage = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &func.type_usage); let type_usage =
replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &func.type_usage);
functions.insert(name.clone(), TypeConstructor{generic: func.generic.clone(), type_usage: type_usage}); functions.insert(
name.clone(),
TypeConstructor {
generic: func.generic.clone(),
type_usage: type_usage,
},
);
} }
impls.push(EnvImpl{ impls.push(EnvImpl {
trait_: impl_.trait_.clone(), trait_: impl_.trait_.clone(),
functions: functions, functions: functions,
}); });
} }
result = EnvType{ result = EnvType {
generic: ast::Generic{parameters: vec!()}, generic: ast::Generic { parameters: vec![] },
is_a: self.is_a.clone(), is_a: self.is_a.clone(),
fields: fields, fields: fields,
impls: impls, impls: impls,
@@ -251,7 +255,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert( result.insert(
"i8".to_string(), "i8".to_string(),
NamedEntity::NamedType(EnvType { NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -260,7 +264,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -269,7 +273,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -278,7 +282,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -287,7 +291,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -297,7 +301,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -306,7 +310,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -315,7 +319,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -324,7 +328,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -333,7 +337,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -343,7 +347,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -352,7 +356,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -362,7 +366,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -371,7 +375,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -380,7 +384,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!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -389,7 +393,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert( result.insert(
"String".to_string(), "String".to_string(),
NamedEntity::NamedType(EnvType { NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()}, generic: ast::Generic { parameters: vec![] },
is_a: TypeType::Scalar, is_a: TypeType::Scalar,
fields: HashMap::new(), fields: HashMap::new(),
impls: vec![], impls: vec![],
@@ -409,15 +413,15 @@ fn apply_self(type_name: &str, constructor: &TypeConstructor) -> TypeConstructor
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 || type_name == "Self" {
let result = 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{ return TypeConstructor {
generic: constructor.generic.clone(), generic: constructor.generic.clone(),
type_usage: result, type_usage: result,
} };
} }
} }
_ => {} _ => {}
@@ -487,6 +491,7 @@ struct Context {
pub current_function_return: Option<ast::TypeUsage>, pub current_function_return: Option<ast::TypeUsage>,
pub environment: HashMap<String, NamedEntity>, pub environment: HashMap<String, NamedEntity>,
pub id_generator: Rc<ast::IdGenerator>, pub id_generator: Rc<ast::IdGenerator>,
pub current_self: Option<String>,
} }
impl Context { impl Context {
@@ -505,28 +510,25 @@ impl Context {
fn add_generic(&self, generic: &ast::Generic) -> Result<Context> { fn add_generic(&self, generic: &ast::Generic) -> Result<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{ generic: ast::Generic { parameters: vec![] },
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() {
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(),
});
} }
match &self.environment[&bound.name.value] { match &self.environment[&bound.name.value] {
NamedEntity::NamedType(named_type) => { NamedEntity::NamedType(named_type) => {
env_type.impls.push(named_type.impls[0].clone()); env_type.impls.push(named_type.impls[0].clone());
}, }
_ => {} _ => {}
} }
}; }
ctx.environment.insert(parameter.name.name.value.clone(), NamedEntity::NamedType(env_type)); ctx.environment
.insert(parameter.name.name.value.clone(), NamedEntity::NamedType(env_type));
} }
return Ok(ctx); return Ok(ctx);
} }
@@ -534,31 +536,26 @@ 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(), TypeConstructor::from_declaration(&func.declaration)); if (func.declaration.arguments.len() == 0) {
continue;
} }
// fill out defaults match &func.declaration.arguments[0].type_ {
match &impl_.trait_ { ast::TypeUsage::Named(named) => {
Some(trait_) => { if (named.name.name.value != "Self") {
if !traits.contains_key(&trait_.name.name.value) { continue;
return Err(errors::TypingError::TypeDoesNotExist {
identifier: trait_.name.clone(),
});
}
for func in traits[&trait_.name.name.value].functions.iter() {
match func {
ast::TraitItem::Function(default_function) => {
if !functions.contains_key(&default_function.declaration.name.name.value) {
functions.insert(
default_function.declaration.name.name.value.to_string(),
TypeConstructor::from_declaration(&default_function.declaration),
);
} }
} }
_ => {} _ => {
continue;
} }
} }
} let type_constructor = TypeConstructor::from_declaration(&func.declaration);
None => {} let resolved_tc = TypeConstructor {
generic: type_constructor.generic.clone(),
type_usage: type_constructor.type_usage.replace_type(&"Self", &impl_.struct_.name),
};
// is self function, add to context for this type
functions.insert(func.declaration.name.name.value.to_string(), resolved_tc);
} }
let mut result = self.clone(); let mut result = self.clone();
let mut env_named = result.environment[&impl_.struct_.name.name.value].clone(); let mut env_named = result.environment[&impl_.struct_.name.name.value].clone();
@@ -641,9 +638,7 @@ 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) => ast::TypeUsage::Namespace(namespace.clone()),
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() {
@@ -670,7 +665,10 @@ fn compose_substitutions(ctx: &Context, s1: &SubstitutionMap, s2: &SubstitutionM
fn unify(ctx: &Context, t1: &ast::TypeUsage, t2: &ast::TypeUsage) -> Result<SubstitutionMap> { fn unify(ctx: &Context, t1: &ast::TypeUsage, t2: &ast::TypeUsage) -> Result<SubstitutionMap> {
match (t1, t2) { match (t1, t2) {
(ast::TypeUsage::Named(named1), ast::TypeUsage::Named(named2)) => { (ast::TypeUsage::Named(named1), ast::TypeUsage::Named(named2)) => {
if named1.name.name.value == named2.name.name.value { if named1.name.name.value == named2.name.name.value
|| (named1.name.name.value == "Self" && Some(named2.name.name.value.clone()) == ctx.current_self)
|| (named2.name.name.value == "Self" && Some(named1.name.name.value.clone()) == ctx.current_self)
{
let mut result = SubstitutionMap::new(); let mut result = SubstitutionMap::new();
match (&named1.type_parameters, &named2.type_parameters) { match (&named1.type_parameters, &named2.type_parameters) {
(ast::GenericUsage::Known(known1), ast::GenericUsage::Known(known2)) => { (ast::GenericUsage::Known(known1), ast::GenericUsage::Known(known2)) => {
@@ -691,10 +689,10 @@ fn unify(ctx: &Context, t1: &ast::TypeUsage, t2: &ast::TypeUsage) -> Result<Subs
)?, )?,
)?; )?;
} }
}, }
_ => { _ => {
panic!("should never be unknown") panic!("should never be unknown")
}, }
} }
return Ok(result); return Ok(result);
} }
@@ -784,6 +782,7 @@ impl TypeChecker {
environment: create_builtins(), environment: create_builtins(),
current_function_return: None, current_function_return: None,
id_generator: Rc::new(ast::IdGenerator::new("T")), id_generator: Rc::new(ast::IdGenerator::new("T")),
current_self: None,
}; };
let mut traits = HashMap::new(); let mut traits = HashMap::new();
@@ -810,7 +809,7 @@ impl TypeChecker {
}; };
ctx.environment.insert( ctx.environment.insert(
function.declaration.name.name.value.to_string(), function.declaration.name.name.value.to_string(),
NamedEntity::Function(TypeConstructor{ NamedEntity::Function(TypeConstructor {
generic: function.declaration.generic.clone(), generic: function.declaration.generic.clone(),
type_usage: ast::TypeUsage::Function(function_type), type_usage: ast::TypeUsage::Function(function_type),
}), }),
@@ -931,9 +930,6 @@ impl TypeChecker {
ast::TypeDeclaration::Primitive(primitive) => { ast::TypeDeclaration::Primitive(primitive) => {
return Ok((ast::TypeDeclaration::Primitive(primitive.clone()), SubstitutionMap::new())); return Ok((ast::TypeDeclaration::Primitive(primitive.clone()), SubstitutionMap::new()));
} }
ast::TypeDeclaration::Alias(alias) => {
return Ok((ast::TypeDeclaration::Alias(alias.clone()), SubstitutionMap::new()));
}
ast::TypeDeclaration::Trait(trait_) => { ast::TypeDeclaration::Trait(trait_) => {
let (result, subst) = self.with_trait_declaration(ctx, incoming_substitutions, trait_)?; let (result, subst) = self.with_trait_declaration(ctx, incoming_substitutions, trait_)?;
return Ok((ast::TypeDeclaration::Trait(result), subst)); return Ok((ast::TypeDeclaration::Trait(result), subst));
@@ -947,7 +943,11 @@ impl TypeChecker {
incoming_substitutions: &SubstitutionMap, incoming_substitutions: &SubstitutionMap,
trait_: &ast::TraitTypeDeclaration, trait_: &ast::TraitTypeDeclaration,
) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> { ) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> {
let gen_ctx = ctx.add_generic(&trait_.generic)?; let mut gen_ctx = ctx.add_generic(&trait_.generic)?;
gen_ctx
.environment
.insert("Self".to_string(), gen_ctx.environment[&trait_.name.name.value].clone());
gen_ctx.current_self = Some(trait_.name.name.value.clone());
let mut substitutions = incoming_substitutions.clone(); let mut substitutions = incoming_substitutions.clone();
let mut result_functions = vec![]; let mut result_functions = vec![];
for item in &trait_.functions { for item in &trait_.functions {
@@ -956,11 +956,6 @@ impl TypeChecker {
let result_declaration = self.with_function_declaration(&gen_ctx, declaration)?; let result_declaration = self.with_function_declaration(&gen_ctx, declaration)?;
result_functions.push(ast::TraitItem::FunctionDeclaration(result_declaration)); result_functions.push(ast::TraitItem::FunctionDeclaration(result_declaration));
} }
ast::TraitItem::Function(function) => {
let (function_result, susbt) = self.with_function(&gen_ctx, incoming_substitutions, function)?;
substitutions = compose_substitutions(ctx, &substitutions, &susbt)?;
result_functions.push(ast::TraitItem::Function(function_result));
}
} }
} }
Ok(( Ok((
@@ -996,7 +991,11 @@ impl TypeChecker {
incoming_substitutions: &SubstitutionMap, incoming_substitutions: &SubstitutionMap,
impl_: &ast::Impl, impl_: &ast::Impl,
) -> Result<(ast::Impl, SubstitutionMap)> { ) -> Result<(ast::Impl, SubstitutionMap)> {
let impl_ctx = ctx.add_generic(&impl_.generic)?; let mut impl_ctx = ctx.add_generic(&impl_.generic)?;
impl_ctx
.environment
.insert("Self".to_string(), impl_ctx.environment[&impl_.struct_.name.name.value].clone());
impl_ctx.current_self = Some(impl_.struct_.name.name.value.clone());
let mut substitutions = incoming_substitutions.clone(); let mut substitutions = incoming_substitutions.clone();
type_exists( type_exists(
@@ -1459,14 +1458,25 @@ impl TypeChecker {
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(named_type) => { 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()})); 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_)?)?; 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) => { NamedEntity::Function(function) => {
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &function.construct(ctx, &variable_usage.type_parameters)?)?)?; substitution = compose_substitutions(
ctx,
&substitution,
&unify(
ctx,
&variable_usage.type_,
&function.construct(ctx, &variable_usage.type_parameters)?,
)?,
)?;
} }
} }
Ok(( Ok((