stared redo
This commit is contained in:
@@ -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
|
||||
WORKDIR /code
|
||||
|
||||
@@ -43,13 +43,13 @@ This language is under active development, progress will be marked here as the l
|
||||
- [x] Basic
|
||||
- [ ] Inferred
|
||||
- [ ] Higher kinded types
|
||||
- [ ] Variadic generic types
|
||||
- [ ] Control Flow
|
||||
- [x] If
|
||||
- [ ] While
|
||||
- [ ] For
|
||||
- [ ] IO
|
||||
- [ ] Enums
|
||||
- [ ] Errors
|
||||
- [ ] Lambdas
|
||||
- [ ] Imports
|
||||
- [ ] Visibility
|
||||
|
||||
@@ -81,16 +81,17 @@ fn main(): i64 {
|
||||
type TestTrait trait {
|
||||
fn class_method(id: i64): Self;
|
||||
fn instance_method(self: Self): i64;
|
||||
fn default_impl(self: Self): i64 {
|
||||
return self.instance_method();
|
||||
}
|
||||
fn default_impl(self: Self): i64;
|
||||
}
|
||||
|
||||
impl TestTrait for User {
|
||||
fn class_method(id: i64): Self {
|
||||
return User{id: id,};
|
||||
return Self{id: id,};
|
||||
}
|
||||
fn instance_method(self: Self): i64 {
|
||||
return self.get_id();
|
||||
}
|
||||
fn default_impl(self: Self): i64 {
|
||||
return self.instance_method();
|
||||
}
|
||||
}
|
||||
|
||||
44
src/ast.rs
44
src/ast.rs
@@ -1,4 +1,4 @@
|
||||
use std::cell::RefCell;
|
||||
use std::{cell::RefCell, clone};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct IdGenerator {
|
||||
@@ -8,7 +8,10 @@ pub struct IdGenerator {
|
||||
|
||||
impl IdGenerator {
|
||||
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 {
|
||||
@@ -72,8 +75,7 @@ pub struct UnknownTypeUsage {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum NamespaceTypeUsage {
|
||||
Type(NamedTypeUsage)
|
||||
// Module
|
||||
Type(NamedTypeUsage), // Module
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
@@ -81,7 +83,7 @@ pub enum TypeUsage {
|
||||
Function(FunctionTypeUsage),
|
||||
Named(NamedTypeUsage),
|
||||
Unknown(UnknownTypeUsage),
|
||||
Namespace(NamespaceTypeUsage)
|
||||
Namespace(NamespaceTypeUsage),
|
||||
}
|
||||
|
||||
impl TypeUsage {
|
||||
@@ -114,6 +116,30 @@ impl TypeUsage {
|
||||
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)]
|
||||
@@ -347,7 +373,6 @@ pub struct StructTypeDeclaration {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum TraitItem {
|
||||
FunctionDeclaration(FunctionDeclaration),
|
||||
Function(Function),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
@@ -357,17 +382,10 @@ pub struct TraitTypeDeclaration {
|
||||
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)]
|
||||
pub enum TypeDeclaration {
|
||||
Struct(StructTypeDeclaration),
|
||||
Primitive(PrimitiveTypeDeclaration),
|
||||
Alias(AliasTypeDeclaration),
|
||||
Trait(TraitTypeDeclaration),
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
<fd:FunctionDeclaration> ";" => ast::TraitItem::FunctionDeclaration(fd),
|
||||
<f:Function> => ast::TraitItem::Function(f),
|
||||
};
|
||||
|
||||
pub TraitTypeDeclaration: ast::TraitTypeDeclaration = {
|
||||
@@ -297,7 +292,6 @@ pub TraitTypeDeclaration: ast::TraitTypeDeclaration = {
|
||||
|
||||
pub TypeDeclaration: ast::TypeDeclaration = {
|
||||
<s:StructTypeDeclaration> => ast::TypeDeclaration::Struct(s),
|
||||
<a:AliasTypeDeclaration> => ast::TypeDeclaration::Alias(a),
|
||||
<t:TraitTypeDeclaration> => ast::TypeDeclaration::Trait(t),
|
||||
};
|
||||
|
||||
|
||||
@@ -87,12 +87,6 @@ impl Context {
|
||||
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) => {
|
||||
ctx.environment.insert(
|
||||
function.declaration.name.name.value.to_string(),
|
||||
@@ -418,6 +412,9 @@ impl TreeWalkInterpreter {
|
||||
}
|
||||
}
|
||||
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] {
|
||||
NamedEntity::Variable(v) => v.clone(),
|
||||
_ => panic!("variable lookup of type"),
|
||||
@@ -469,7 +466,7 @@ impl TreeWalkInterpreter {
|
||||
if method.declaration.arguments.len() > 0 {
|
||||
match &method.declaration.arguments[0].type_ {
|
||||
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 {
|
||||
partial: vec![source.clone()],
|
||||
ref_: FunctionRef::User(method.clone()),
|
||||
|
||||
17
src/main.rs
17
src/main.rs
@@ -3,7 +3,6 @@ mod ast;
|
||||
mod errors;
|
||||
mod interpreter;
|
||||
mod trait_checking;
|
||||
mod type_alias_resolution;
|
||||
mod type_checking;
|
||||
#[macro_use]
|
||||
extern crate lalrpop_util;
|
||||
@@ -19,7 +18,7 @@ fn main() {
|
||||
let matches = App::new("Boring Language Compiler")
|
||||
.version("0.0.1")
|
||||
.author("Andrew Segavac")
|
||||
.about("Compiles boring language files to LLVM IR.")
|
||||
.about("Compiles boringlang files")
|
||||
.arg(
|
||||
Arg::with_name("OUTPUT")
|
||||
.short("o")
|
||||
@@ -40,26 +39,18 @@ fn main() {
|
||||
let unknown_id_gen = ast::IdGenerator::new("S");
|
||||
let module_ast = grammar::ModuleParser::new().parse(&unknown_id_gen, &contents).unwrap(); //TODO: convert to error
|
||||
// println!("ast: {:#?}", &module_ast);
|
||||
let alias_resolver = type_alias_resolution::TypeAliasResolver {};
|
||||
let resolved_ast = match alias_resolver.with_module(&module_ast) {
|
||||
Ok(r) => r,
|
||||
Err(err) => {
|
||||
println!("type checking error: {:#?}", &err);
|
||||
panic!("bad alias");
|
||||
}
|
||||
};
|
||||
|
||||
// println!("resolved ast: {:#?}", &resolved_ast);
|
||||
let trait_checker = trait_checking::TraitChecker {};
|
||||
match trait_checker.with_module(&resolved_ast) {
|
||||
match trait_checker.with_module(&module_ast) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
println!("type checking error: {:#?}", &err);
|
||||
println!("trait checking error: {:#?}", &err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
Ok((checked_ast, subst)) => {
|
||||
println!("checked ast: {:#?}", &checked_ast);
|
||||
|
||||
@@ -23,9 +23,7 @@ fn compare_struct_trait(
|
||||
match struct_ {
|
||||
ast::TypeUsage::Named(named) => match trait_ {
|
||||
ast::TypeUsage::Named(trait_named) => {
|
||||
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)
|
||||
{
|
||||
if named.name.name.value == trait_named.name.name.value {
|
||||
return Ok(());
|
||||
}
|
||||
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
|
||||
@@ -148,14 +133,14 @@ impl TraitChecker {
|
||||
let mut found = false;
|
||||
for trait_item in trait_declaration.functions.iter() {
|
||||
let declaration = match trait_item {
|
||||
ast::TraitItem::Function(function) => &function.declaration,
|
||||
ast::TraitItem::FunctionDeclaration(declaration) => &declaration,
|
||||
};
|
||||
ast::TraitItem::FunctionDeclaration(declaration) => {
|
||||
if impl_function.declaration.name.name.value == declaration.name.name.value {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
if found == false {
|
||||
return Err(errors::TypingError::FunctionNotInTrait {
|
||||
function_name: impl_function.declaration.name.clone(),
|
||||
|
||||
@@ -19,10 +19,10 @@ fn type_meets_trait_bounds(ctx: &Context, type_: &ast::TypeUsage, bounds: &Vec<a
|
||||
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");
|
||||
}
|
||||
@@ -39,7 +39,7 @@ fn type_meets_trait_bounds(ctx: &Context, type_: &ast::TypeUsage, bounds: &Vec<a
|
||||
if found == false {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
panic!("type is a variable, this should not happen");
|
||||
}
|
||||
@@ -57,31 +57,31 @@ fn replace_generic_with_concrete(replace: &ast::Identifier, with_type: &ast::Typ
|
||||
}
|
||||
result.type_parameters = match &named.type_parameters {
|
||||
ast::GenericUsage::Known(known) => {
|
||||
let mut param_result = vec!();
|
||||
let mut param_result = vec![];
|
||||
for param in known.parameters.iter() {
|
||||
param_result.push(replace_generic_with_concrete(replace, with_type, param));
|
||||
}
|
||||
ast::GenericUsage::new(¶m_result)
|
||||
},
|
||||
ast::GenericUsage::Unknown => {
|
||||
ast::GenericUsage::Unknown
|
||||
},
|
||||
}
|
||||
ast::GenericUsage::Unknown => ast::GenericUsage::Unknown,
|
||||
};
|
||||
return ast::TypeUsage::Named(result);
|
||||
},
|
||||
}
|
||||
ast::TypeUsage::Function(func) => {
|
||||
let result = ast::TypeUsage::Function(ast::FunctionTypeUsage {
|
||||
arguments: func.arguments.iter().map(|arg| {
|
||||
replace_generic_with_concrete(replace, with_type, arg)
|
||||
}).collect(),
|
||||
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)),
|
||||
});
|
||||
return result;
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
// in_type is unknown, skip
|
||||
return in_type.clone();
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ impl 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 {
|
||||
@@ -108,7 +108,7 @@ impl TypeConstructor {
|
||||
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();
|
||||
@@ -165,9 +165,6 @@ impl EnvType {
|
||||
ast::TraitItem::FunctionDeclaration(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 {
|
||||
@@ -190,14 +187,14 @@ impl EnvType {
|
||||
let known_usage = match usage {
|
||||
ast::GenericUsage::Known(known) => known.clone(),
|
||||
ast::GenericUsage::Unknown => {
|
||||
let mut new_unknowns = vec!();
|
||||
let mut new_unknowns = vec![];
|
||||
for _ in 0..self.generic.parameters.len() {
|
||||
new_unknowns.push(ast::TypeUsage::new_unknown(&ctx.id_generator));
|
||||
}
|
||||
ast::GenericInstantiation {
|
||||
parameters: new_unknowns.iter().map(|tp| tp.clone()).collect(),
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
if known_usage.parameters.len() != self.generic.parameters.len() {
|
||||
return Err(errors::TypingError::WrongNumberOfTypeParameters {});
|
||||
@@ -215,13 +212,20 @@ impl EnvType {
|
||||
let type_usage = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &v);
|
||||
fields.insert(k.clone(), type_usage);
|
||||
}
|
||||
let mut impls = vec!();
|
||||
let mut impls = vec![];
|
||||
for impl_ in result.impls.iter() {
|
||||
let mut functions = HashMap::new();
|
||||
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 {
|
||||
trait_: impl_.trait_.clone(),
|
||||
@@ -229,7 +233,7 @@ impl EnvType {
|
||||
});
|
||||
}
|
||||
result = EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: self.is_a.clone(),
|
||||
fields: fields,
|
||||
impls: impls,
|
||||
@@ -251,7 +255,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"i8".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -260,7 +264,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"i16".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -269,7 +273,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"i32".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -278,7 +282,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"i64".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -287,7 +291,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"isize".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -297,7 +301,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"u8".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -306,7 +310,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"u16".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -315,7 +319,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"u32".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -324,7 +328,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"u64".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -333,7 +337,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"usize".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -343,7 +347,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"f32".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -352,7 +356,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"f64".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -362,7 +366,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"bool".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -371,7 +375,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"!".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -380,7 +384,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"unit".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -389,7 +393,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
||||
result.insert(
|
||||
"String".to_string(),
|
||||
NamedEntity::NamedType(EnvType {
|
||||
generic: ast::Generic{parameters: vec!()},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Scalar,
|
||||
fields: HashMap::new(),
|
||||
impls: vec![],
|
||||
@@ -409,7 +413,7 @@ fn apply_self(type_name: &str, constructor: &TypeConstructor) -> TypeConstructor
|
||||
if func.arguments.len() > 0 {
|
||||
match &func.arguments[0] {
|
||||
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 {
|
||||
arguments: func.arguments[1..func.arguments.len()].iter().map(|arg| arg.clone()).collect(),
|
||||
return_type: func.return_type.clone(),
|
||||
@@ -417,7 +421,7 @@ fn apply_self(type_name: &str, constructor: &TypeConstructor) -> TypeConstructor
|
||||
return TypeConstructor {
|
||||
generic: constructor.generic.clone(),
|
||||
type_usage: result,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -487,6 +491,7 @@ struct Context {
|
||||
pub current_function_return: Option<ast::TypeUsage>,
|
||||
pub environment: HashMap<String, NamedEntity>,
|
||||
pub id_generator: Rc<ast::IdGenerator>,
|
||||
pub current_self: Option<String>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
@@ -506,27 +511,24 @@ impl Context {
|
||||
let mut ctx = self.clone();
|
||||
for parameter in generic.parameters.iter() {
|
||||
let mut env_type = EnvType {
|
||||
generic: ast::Generic{
|
||||
parameters: vec!(),
|
||||
},
|
||||
generic: ast::Generic { parameters: vec![] },
|
||||
is_a: TypeType::Trait,
|
||||
fields: HashMap::new(),
|
||||
impls: vec!(),
|
||||
impls: vec![],
|
||||
};
|
||||
for bound in parameter.bounds.iter() {
|
||||
if !self.environment.contains_key(&bound.name.value) {
|
||||
return Err(errors::TypingError::TypeDoesNotExist {
|
||||
identifier: bound.clone(),
|
||||
});
|
||||
return Err(errors::TypingError::TypeDoesNotExist { identifier: bound.clone() });
|
||||
}
|
||||
match &self.environment[&bound.name.value] {
|
||||
NamedEntity::NamedType(named_type) => {
|
||||
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);
|
||||
}
|
||||
@@ -534,31 +536,26 @@ impl Context {
|
||||
fn add_impl(&self, impl_: &ast::Impl, traits: &HashMap<String, ast::TraitTypeDeclaration>) -> Result<Context> {
|
||||
let mut functions = HashMap::new();
|
||||
for func in impl_.functions.iter() {
|
||||
functions.insert(func.declaration.name.name.value.to_string(), TypeConstructor::from_declaration(&func.declaration));
|
||||
if (func.declaration.arguments.len() == 0) {
|
||||
continue;
|
||||
}
|
||||
// fill out defaults
|
||||
match &impl_.trait_ {
|
||||
Some(trait_) => {
|
||||
if !traits.contains_key(&trait_.name.name.value) {
|
||||
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),
|
||||
);
|
||||
match &func.declaration.arguments[0].type_ {
|
||||
ast::TypeUsage::Named(named) => {
|
||||
if (named.name.name.value != "Self") {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
let type_constructor = TypeConstructor::from_declaration(&func.declaration);
|
||||
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 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::Namespace(namespace) => {
|
||||
ast::TypeUsage::Namespace(namespace.clone())
|
||||
}
|
||||
ast::TypeUsage::Namespace(namespace) => ast::TypeUsage::Namespace(namespace.clone()),
|
||||
ast::TypeUsage::Function(function) => {
|
||||
let mut arguments = vec![];
|
||||
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> {
|
||||
match (t1, t2) {
|
||||
(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();
|
||||
match (&named1.type_parameters, &named2.type_parameters) {
|
||||
(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")
|
||||
},
|
||||
}
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
@@ -784,6 +782,7 @@ impl TypeChecker {
|
||||
environment: create_builtins(),
|
||||
current_function_return: None,
|
||||
id_generator: Rc::new(ast::IdGenerator::new("T")),
|
||||
current_self: None,
|
||||
};
|
||||
|
||||
let mut traits = HashMap::new();
|
||||
@@ -931,9 +930,6 @@ impl TypeChecker {
|
||||
ast::TypeDeclaration::Primitive(primitive) => {
|
||||
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_) => {
|
||||
let (result, subst) = self.with_trait_declaration(ctx, incoming_substitutions, trait_)?;
|
||||
return Ok((ast::TypeDeclaration::Trait(result), subst));
|
||||
@@ -947,7 +943,11 @@ impl TypeChecker {
|
||||
incoming_substitutions: &SubstitutionMap,
|
||||
trait_: &ast::TraitTypeDeclaration,
|
||||
) -> 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 result_functions = vec![];
|
||||
for item in &trait_.functions {
|
||||
@@ -956,11 +956,6 @@ impl TypeChecker {
|
||||
let result_declaration = self.with_function_declaration(&gen_ctx, 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((
|
||||
@@ -996,7 +991,11 @@ impl TypeChecker {
|
||||
incoming_substitutions: &SubstitutionMap,
|
||||
impl_: &ast::Impl,
|
||||
) -> 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();
|
||||
type_exists(
|
||||
@@ -1459,14 +1458,25 @@ impl TypeChecker {
|
||||
let mut substitution = substitution.clone();
|
||||
match &ctx.environment[&variable_usage.name.name.value] {
|
||||
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_)?)?;
|
||||
}
|
||||
NamedEntity::Variable(variable) => {
|
||||
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &variable)?)?;
|
||||
}
|
||||
NamedEntity::Function(function) => {
|
||||
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &function.construct(ctx, &variable_usage.type_parameters)?)?)?;
|
||||
substitution = compose_substitutions(
|
||||
ctx,
|
||||
&substitution,
|
||||
&unify(
|
||||
ctx,
|
||||
&variable_usage.type_,
|
||||
&function.construct(ctx, &variable_usage.type_parameters)?,
|
||||
)?,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok((
|
||||
|
||||
Reference in New Issue
Block a user