finished revamping type system as setup for generics
This commit is contained in:
19
src/ast.rs
19
src/ast.rs
@@ -17,7 +17,7 @@ impl IdGenerator {
|
|||||||
|
|
||||||
pub fn new_unit() -> TypeUsage {
|
pub fn new_unit() -> TypeUsage {
|
||||||
TypeUsage::Named(NamedTypeUsage {
|
TypeUsage::Named(NamedTypeUsage {
|
||||||
type_parameters: GenericUsage::Known(GenericInstantiation{parameters: vec!()}),
|
type_parameters: GenericUsage::Known(GenericInstantiation { parameters: vec![] }),
|
||||||
name: Identifier {
|
name: Identifier {
|
||||||
name: Spanned {
|
name: Spanned {
|
||||||
span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these
|
span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these
|
||||||
@@ -29,7 +29,7 @@ pub fn new_unit() -> TypeUsage {
|
|||||||
|
|
||||||
pub fn new_never() -> TypeUsage {
|
pub fn new_never() -> TypeUsage {
|
||||||
TypeUsage::Named(NamedTypeUsage {
|
TypeUsage::Named(NamedTypeUsage {
|
||||||
type_parameters: GenericUsage::Known(GenericInstantiation{parameters: vec!()}),
|
type_parameters: GenericUsage::Known(GenericInstantiation { parameters: vec![] }),
|
||||||
name: Identifier {
|
name: Identifier {
|
||||||
name: Spanned {
|
name: Spanned {
|
||||||
span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these
|
span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these
|
||||||
@@ -81,12 +81,15 @@ impl TypeUsage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_named(identifier: &Identifier, generic_usage: &GenericUsage) -> TypeUsage {
|
pub fn new_named(identifier: &Identifier, generic_usage: &GenericUsage) -> TypeUsage {
|
||||||
return TypeUsage::Named(NamedTypeUsage { type_parameters: generic_usage.clone(), name: identifier.clone() });
|
return TypeUsage::Named(NamedTypeUsage {
|
||||||
|
type_parameters: generic_usage.clone(),
|
||||||
|
name: identifier.clone(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_builtin(name: String) -> TypeUsage {
|
pub fn new_builtin(name: String) -> TypeUsage {
|
||||||
TypeUsage::Named(NamedTypeUsage {
|
TypeUsage::Named(NamedTypeUsage {
|
||||||
type_parameters: GenericUsage::Known(GenericInstantiation{parameters: vec!()}),
|
type_parameters: GenericUsage::Known(GenericInstantiation { parameters: vec![] }),
|
||||||
name: Identifier {
|
name: Identifier {
|
||||||
name: Spanned {
|
name: Spanned {
|
||||||
span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these
|
span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these
|
||||||
@@ -128,16 +131,12 @@ pub enum GenericUsage {
|
|||||||
|
|
||||||
impl GenericUsage {
|
impl GenericUsage {
|
||||||
pub fn new(type_parameters: &[TypeUsage]) -> Self {
|
pub fn new(type_parameters: &[TypeUsage]) -> Self {
|
||||||
GenericUsage::Known(GenericInstantiation{
|
GenericUsage::Known(GenericInstantiation {
|
||||||
parameters: type_parameters.iter().map(|tp| {
|
parameters: type_parameters.iter().map(|tp| tp.clone()).collect(),
|
||||||
tp.clone()
|
|
||||||
}).collect(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
Mul,
|
Mul,
|
||||||
|
|||||||
@@ -27,10 +27,7 @@ pub enum TypingError {
|
|||||||
#[error("name is not a struct, cannot instaniate")]
|
#[error("name is not a struct, cannot instaniate")]
|
||||||
NotAStructLiteral { identifier: ast::Identifier },
|
NotAStructLiteral { identifier: ast::Identifier },
|
||||||
#[error("struct literal fields mismatch")]
|
#[error("struct literal fields mismatch")]
|
||||||
StructLiteralFieldsMismatch {
|
StructLiteralFieldsMismatch { struct_name: ast::Identifier },
|
||||||
struct_name: ast::Identifier,
|
|
||||||
struct_definition_name: ast::Identifier,
|
|
||||||
},
|
|
||||||
#[error("missing trait function")]
|
#[error("missing trait function")]
|
||||||
MissingTraitFunction {
|
MissingTraitFunction {
|
||||||
struct_name: ast::Identifier,
|
struct_name: ast::Identifier,
|
||||||
@@ -48,6 +45,8 @@ pub enum TypingError {
|
|||||||
IfConditionMustBeBool {
|
IfConditionMustBeBool {
|
||||||
// TODO: add position
|
// TODO: add position
|
||||||
},
|
},
|
||||||
|
#[error("cannot use type as an expression")]
|
||||||
|
TypeIsNotAnExpression { type_name: ast::Identifier },
|
||||||
#[error("multiple errors")]
|
#[error("multiple errors")]
|
||||||
MultipleErrors { errors: Vec<TypingError> },
|
MultipleErrors { errors: Vec<TypingError> },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,12 +95,10 @@ impl Context {
|
|||||||
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(),
|
||||||
NamedEntity::Variable(Value::Function(
|
NamedEntity::Variable(Value::Function(Function {
|
||||||
Function{
|
partial: vec![],
|
||||||
partial: vec!(),
|
|
||||||
ref_: FunctionRef::User(function.clone()),
|
ref_: FunctionRef::User(function.clone()),
|
||||||
}
|
})),
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ast::ModuleItem::Impl(impl_) => {
|
ast::ModuleItem::Impl(impl_) => {
|
||||||
@@ -225,11 +223,9 @@ impl TreeWalkInterpreter {
|
|||||||
let mut ctx = Context::from_module(module);
|
let mut ctx = Context::from_module(module);
|
||||||
|
|
||||||
let main = match &ctx.environment["main"] {
|
let main = match &ctx.environment["main"] {
|
||||||
NamedEntity::Variable(Value::Function(func)) => {
|
NamedEntity::Variable(Value::Function(func)) => match &func.ref_ {
|
||||||
match &func.ref_ {
|
|
||||||
FunctionRef::User(ref_) => ref_.clone(),
|
FunctionRef::User(ref_) => ref_.clone(),
|
||||||
_ => panic!("main should be a user defined function"),
|
_ => panic!("main should be a user defined function"),
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => panic!("main should be a user defined function"),
|
_ => panic!("main should be a user defined function"),
|
||||||
};
|
};
|
||||||
@@ -378,26 +374,35 @@ impl TreeWalkInterpreter {
|
|||||||
argument_values.push(argument_value);
|
argument_values.push(argument_value);
|
||||||
}
|
}
|
||||||
match &source {
|
match &source {
|
||||||
Value::Function(function) => {
|
Value::Function(function) => match &function.ref_ {
|
||||||
match &function.ref_ {
|
|
||||||
FunctionRef::User(user_function) => {
|
FunctionRef::User(user_function) => {
|
||||||
let mut fn_ctx = ctx.new_env();
|
let mut fn_ctx = ctx.new_env();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
for partial_arg in &function.partial {
|
for partial_arg in &function.partial {
|
||||||
fn_ctx.set_variable(user_function.declaration.arguments[i].name.name.value.to_string(), &partial_arg.clone());
|
fn_ctx.set_variable(
|
||||||
|
user_function.declaration.arguments[i].name.name.value.to_string(),
|
||||||
|
&partial_arg.clone(),
|
||||||
|
);
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
}
|
}
|
||||||
for argument_value in &argument_values {
|
for argument_value in &argument_values {
|
||||||
fn_ctx.set_variable(user_function.declaration.arguments[i].name.name.value.to_string(), &argument_value.clone());
|
fn_ctx.set_variable(
|
||||||
|
user_function.declaration.arguments[i].name.name.value.to_string(),
|
||||||
|
&argument_value.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return ExpressionResult::Value(self.with_function(&mut fn_ctx, user_function));
|
return ExpressionResult::Value(self.with_function(&mut fn_ctx, user_function));
|
||||||
}
|
}
|
||||||
FunctionRef::Builtin(builtin_function) => {
|
FunctionRef::Builtin(builtin_function) => {
|
||||||
let all_values = function.partial.iter().map(|val| {val.clone()}).chain(argument_values.into_iter()).collect();
|
let all_values = function
|
||||||
|
.partial
|
||||||
|
.iter()
|
||||||
|
.map(|val| val.clone())
|
||||||
|
.chain(argument_values.into_iter())
|
||||||
|
.collect();
|
||||||
return ExpressionResult::Value(builtin_function(all_values));
|
return ExpressionResult::Value(builtin_function(all_values));
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
_ => panic!("type error: function call source must be a function"),
|
_ => panic!("type error: function call source must be a function"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,17 +459,17 @@ impl TreeWalkInterpreter {
|
|||||||
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 == s.source.name.name.value {
|
||||||
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()),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ExpressionResult::Value(Value::Function(Function{
|
return ExpressionResult::Value(Value::Function(Function {
|
||||||
partial: vec!(),
|
partial: vec![],
|
||||||
ref_: FunctionRef::User(method.clone()),
|
ref_: FunctionRef::User(method.clone()),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
mod ast;
|
mod ast;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod interpreter;
|
mod interpreter;
|
||||||
|
mod trait_checking;
|
||||||
mod type_alias_resolution;
|
mod type_alias_resolution;
|
||||||
mod type_checking;
|
mod type_checking;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@@ -42,6 +43,14 @@ fn main() {
|
|||||||
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 = alias_resolver.with_module(&module_ast);
|
||||||
// println!("resolved ast: {:#?}", &resolved_ast);
|
// println!("resolved ast: {:#?}", &resolved_ast);
|
||||||
|
let trait_checker = trait_checking::TraitChecker {};
|
||||||
|
match trait_checker.with_module(&resolved_ast) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => {
|
||||||
|
println!("type checking error: {:#?}", &err);
|
||||||
|
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(&resolved_ast);
|
||||||
match &type_checking_result {
|
match &type_checking_result {
|
||||||
|
|||||||
171
src/trait_checking.rs
Normal file
171
src/trait_checking.rs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
use crate::ast;
|
||||||
|
use crate::errors;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub type Result<T, E = errors::TypingError> = std::result::Result<T, E>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
struct Context {
|
||||||
|
pub environment_traits: HashMap<String, ast::TraitTypeDeclaration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_builtins() -> HashMap<String, ast::TraitTypeDeclaration> {
|
||||||
|
let mut result = HashMap::<String, ast::TraitTypeDeclaration>::new();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare_struct_trait(
|
||||||
|
struct_: &ast::TypeUsage,
|
||||||
|
trait_: &ast::TypeUsage,
|
||||||
|
struct_name: &ast::Identifier,
|
||||||
|
trait_name: &ast::Identifier,
|
||||||
|
) -> Result<()> {
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
return Err(errors::TypingError::TypeMismatch {
|
||||||
|
type_one: struct_.clone(),
|
||||||
|
type_two: trait_.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ast::TypeUsage::Function(_) => {
|
||||||
|
return Err(errors::TypingError::TypeMismatch {
|
||||||
|
type_one: struct_.clone(),
|
||||||
|
type_two: trait_.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => panic!("Unknown in function definition"),
|
||||||
|
},
|
||||||
|
ast::TypeUsage::Function(function) => match trait_ {
|
||||||
|
ast::TypeUsage::Named(_) => {
|
||||||
|
return Err(errors::TypingError::TypeMismatch {
|
||||||
|
type_one: struct_.clone(),
|
||||||
|
type_two: trait_.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ast::TypeUsage::Function(trait_function) => {
|
||||||
|
if function.arguments.len() != trait_function.arguments.len() {
|
||||||
|
return Err(errors::TypingError::TypeMismatch {
|
||||||
|
type_one: struct_.clone(),
|
||||||
|
type_two: trait_.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (i, _) in function.arguments.iter().enumerate() {
|
||||||
|
compare_struct_trait(&function.arguments[i], &trait_function.arguments[i], struct_name, trait_name)?;
|
||||||
|
}
|
||||||
|
compare_struct_trait(&function.return_type, &trait_function.return_type, struct_name, trait_name)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
_ => panic!("Unknown in function definition"),
|
||||||
|
},
|
||||||
|
_ => panic!("Unknown in function definition"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TraitChecker {}
|
||||||
|
|
||||||
|
impl TraitChecker {
|
||||||
|
pub fn with_module(self: &Self, module: &ast::Module) -> Result<()> {
|
||||||
|
let mut ctx = Context {
|
||||||
|
environment_traits: create_builtins(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for item in module.items.iter() {
|
||||||
|
match item {
|
||||||
|
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Trait(trait_)) => {
|
||||||
|
ctx.environment_traits.insert(trait_.name.name.value.to_string(), trait_.clone());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for item in module.items.iter() {
|
||||||
|
match item {
|
||||||
|
ast::ModuleItem::Impl(impl_) => {
|
||||||
|
self.with_impl(&ctx, impl_)?;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_impl(self: &Self, ctx: &Context, impl_: &ast::Impl) -> Result<()> {
|
||||||
|
// See if trait actually matches
|
||||||
|
match &impl_.trait_ {
|
||||||
|
Some(trait_) => {
|
||||||
|
// assert trait functions satisfied
|
||||||
|
if !ctx.environment_traits.contains_key(&trait_.name.value) {
|
||||||
|
return Err(errors::TypingError::TypeDoesNotExist {
|
||||||
|
identifier: trait_.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let trait_declaration = &ctx.environment_traits[&trait_.name.value];
|
||||||
|
for trait_item in trait_declaration.functions.iter() {
|
||||||
|
match trait_item {
|
||||||
|
ast::TraitItem::FunctionDeclaration(declaration) => {
|
||||||
|
let mut found = false;
|
||||||
|
for impl_function in impl_.functions.iter() {
|
||||||
|
if impl_function.declaration.name.name.value == declaration.name.name.value {
|
||||||
|
found = true;
|
||||||
|
compare_struct_trait(
|
||||||
|
&impl_function.declaration.to_type(),
|
||||||
|
&declaration.to_type(),
|
||||||
|
&impl_.struct_name,
|
||||||
|
&trait_,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found == false {
|
||||||
|
return Err(errors::TypingError::MissingTraitFunction {
|
||||||
|
struct_name: impl_.struct_name.clone(),
|
||||||
|
function_name: declaration.name.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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_,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// assert all functions are in trait
|
||||||
|
for impl_function in impl_.functions.iter() {
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
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(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
// TODO: check for duplicate functions
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -138,7 +138,7 @@ impl TypeAliasResolver {
|
|||||||
},
|
},
|
||||||
replaces: ast::TypeUsage::Named(ast::NamedTypeUsage {
|
replaces: ast::TypeUsage::Named(ast::NamedTypeUsage {
|
||||||
type_parameters: ast::GenericUsage::Unknown,
|
type_parameters: ast::GenericUsage::Unknown,
|
||||||
name: trait_.name.clone()
|
name: trait_.name.clone(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
return ast::TraitTypeDeclaration {
|
return ast::TraitTypeDeclaration {
|
||||||
@@ -148,9 +148,7 @@ impl TypeAliasResolver {
|
|||||||
.functions
|
.functions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| match f {
|
.map(|f| match f {
|
||||||
ast::TraitItem::Function(function) => {
|
ast::TraitItem::Function(function) => ast::TraitItem::Function(self.with_function(&trait_ctx, function)),
|
||||||
ast::TraitItem::Function(self.with_function(&trait_ctx, function))
|
|
||||||
},
|
|
||||||
ast::TraitItem::FunctionDeclaration(function_declaration) => {
|
ast::TraitItem::FunctionDeclaration(function_declaration) => {
|
||||||
ast::TraitItem::FunctionDeclaration(self.with_function_declaration(&trait_ctx, function_declaration))
|
ast::TraitItem::FunctionDeclaration(self.with_function_declaration(&trait_ctx, function_declaration))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,72 @@ 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, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct EnvImpl {
|
||||||
|
trait_: Option<String>,
|
||||||
|
functions: HashMap<String, ast::TypeUsage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum TypeType {
|
||||||
|
Scalar,
|
||||||
|
Trait,
|
||||||
|
Struct,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct EnvType {
|
||||||
|
is_a: TypeType,
|
||||||
|
fields: HashMap<String, ast::TypeUsage>,
|
||||||
|
impls: Vec<EnvImpl>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnvType {
|
||||||
|
fn from_struct(struct_: &ast::StructTypeDeclaration) -> EnvType {
|
||||||
|
return EnvType {
|
||||||
|
is_a: TypeType::Struct,
|
||||||
|
fields: struct_
|
||||||
|
.fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| (field.name.name.value.to_string(), field.type_.clone()))
|
||||||
|
.collect(),
|
||||||
|
impls: vec![],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_trait(trait_: &ast::TraitTypeDeclaration) -> EnvType {
|
||||||
|
let mut functions = HashMap::new();
|
||||||
|
for func in trait_.functions.iter() {
|
||||||
|
match func {
|
||||||
|
ast::TraitItem::FunctionDeclaration(fd) => {
|
||||||
|
functions.insert(fd.name.name.value.to_string(), fd.to_type());
|
||||||
|
}
|
||||||
|
ast::TraitItem::Function(f) => {
|
||||||
|
functions.insert(f.declaration.name.name.value.to_string(), f.declaration.to_type());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let impl_ = EnvImpl {
|
||||||
|
trait_: None,
|
||||||
|
functions: functions,
|
||||||
|
};
|
||||||
|
return EnvType {
|
||||||
|
is_a: TypeType::Trait,
|
||||||
|
fields: HashMap::new(),
|
||||||
|
impls: vec![impl_],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum NamedEntity {
|
pub enum NamedEntity {
|
||||||
TypeDeclaration(ast::TypeDeclaration),
|
NamedType(EnvType),
|
||||||
Variable(ast::TypeUsage),
|
Variable(ast::TypeUsage),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
struct Context {
|
struct Context {
|
||||||
pub current_function_return: Option<ast::TypeUsage>,
|
pub current_function_return: Option<ast::TypeUsage>,
|
||||||
pub impls: Vec<ast::Impl>,
|
|
||||||
pub environment: HashMap<String, NamedEntity>,
|
pub environment: HashMap<String, NamedEntity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,99 +79,127 @@ 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::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "i8".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
result.insert(
|
result.insert(
|
||||||
"i16".to_string(),
|
"i16".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "i16".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
result.insert(
|
result.insert(
|
||||||
"i32".to_string(),
|
"i32".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "i32".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
result.insert(
|
result.insert(
|
||||||
"i64".to_string(),
|
"i64".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "i64".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
result.insert(
|
result.insert(
|
||||||
"isize".to_string(),
|
"isize".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "isize".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
result.insert(
|
result.insert(
|
||||||
"u8".to_string(),
|
"u8".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "u8".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
result.insert(
|
result.insert(
|
||||||
"u16".to_string(),
|
"u16".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "u16".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
result.insert(
|
result.insert(
|
||||||
"u32".to_string(),
|
"u32".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "u32".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
result.insert(
|
result.insert(
|
||||||
"u64".to_string(),
|
"u64".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "u64".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
result.insert(
|
result.insert(
|
||||||
"usize".to_string(),
|
"usize".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "usize".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
result.insert(
|
result.insert(
|
||||||
"f32".to_string(),
|
"f32".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "f32".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
result.insert(
|
result.insert(
|
||||||
"f64".to_string(),
|
"f64".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "f64".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
result.insert(
|
result.insert(
|
||||||
"bool".to_string(),
|
"bool".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "bool".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
result.insert(
|
result.insert(
|
||||||
"!".to_string(),
|
"!".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "!".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
result.insert(
|
result.insert(
|
||||||
"unit".to_string(),
|
"unit".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration {
|
NamedEntity::NamedType(EnvType {
|
||||||
name: "unit".to_string(),
|
is_a: TypeType::Scalar,
|
||||||
})),
|
fields: HashMap::new(),
|
||||||
|
impls: vec![],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,73 +208,38 @@ enum StructAttr {
|
|||||||
Method(ast::TypeUsage),
|
Method(ast::TypeUsage),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_struct_attr(ctx: &Context, struct_declaration: &ast::StructTypeDeclaration, attribute: &ast::Identifier) -> Result<StructAttr> {
|
fn apply_self(type_name: &str, type_: &ast::TypeUsage) -> ast::TypeUsage {
|
||||||
for field in struct_declaration.fields.iter() {
|
match type_ {
|
||||||
if field.name.name.value == attribute.name.value {
|
ast::TypeUsage::Function(func) => {
|
||||||
return Ok(StructAttr::Field(field.type_.clone()));
|
if func.arguments.len() > 0 {
|
||||||
}
|
match &func.arguments[0] {
|
||||||
}
|
|
||||||
|
|
||||||
let mut result = Vec::new();
|
|
||||||
for impl_ in ctx.impls.iter() {
|
|
||||||
if &struct_declaration.name.name.value != &impl_.struct_name.name.value {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for method in impl_.functions.iter() {
|
|
||||||
if method.declaration.name.name.value == attribute.name.value {
|
|
||||||
let mut function_type = method.declaration.to_type();
|
|
||||||
|
|
||||||
// if the name of the type of the first argument == the class, remove the first arg
|
|
||||||
if method.declaration.arguments.len() > 0 {
|
|
||||||
match &method.declaration.arguments[0].type_ {
|
|
||||||
ast::TypeUsage::Named(named) => {
|
ast::TypeUsage::Named(named) => {
|
||||||
if named.name.name.value == struct_declaration.name.name.value {
|
if type_name == named.name.name.value {
|
||||||
function_type = method.declaration.to_method_type();
|
return ast::TypeUsage::Function(ast::FunctionTypeUsage {
|
||||||
|
arguments: func.arguments[1..func.arguments.len()].iter().map(|arg| arg.clone()).collect(),
|
||||||
|
return_type: func.return_type.clone(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
|
||||||
}
|
|
||||||
result.push(function_type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: default trait impls
|
_ => {}
|
||||||
if result.len() == 0 {
|
|
||||||
return Err(errors::TypingError::UnknownFieldName {
|
|
||||||
identifier: attribute.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if result.len() > 1 {
|
return type_.clone();
|
||||||
return Err(errors::TypingError::MultipleFieldName {
|
|
||||||
identifier: attribute.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Ok(StructAttr::Method(result[0].clone()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_trait_attr(ctx: &Context, trait_declaration: &ast::TraitTypeDeclaration, attribute: &ast::Identifier) -> Result<StructAttr> {
|
fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier) -> Result<StructAttr> {
|
||||||
|
match get_from {
|
||||||
|
NamedEntity::NamedType(env_type) => {
|
||||||
|
if env_type.fields.contains_key(&attribute.name.value) {
|
||||||
|
return Ok(StructAttr::Field(env_type.fields[&attribute.name.value].clone()));
|
||||||
|
}
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for trait_item in trait_declaration.functions.iter() {
|
for impl_ in env_type.impls.iter() {
|
||||||
let declaration = match trait_item {
|
if impl_.functions.contains_key(&attribute.name.value) {
|
||||||
ast::TraitItem::Function(function) => &function.declaration,
|
result.push(impl_.functions[&attribute.name.value].clone())
|
||||||
ast::TraitItem::FunctionDeclaration(declaration) => declaration,
|
|
||||||
};
|
|
||||||
if declaration.name.name.value == attribute.name.value {
|
|
||||||
let mut function_type = declaration.to_type();
|
|
||||||
println!("foo: {:?}", declaration);
|
|
||||||
// if the name of the type of the first argument == the class, remove the first arg
|
|
||||||
if declaration.arguments.len() > 0 {
|
|
||||||
match &declaration.arguments[0].type_ {
|
|
||||||
ast::TypeUsage::Named(named) => {
|
|
||||||
if named.name.name.value == trait_declaration.name.name.value {
|
|
||||||
function_type = declaration.to_method_type();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
result.push(function_type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if result.len() == 0 {
|
if result.len() == 0 {
|
||||||
@@ -204,87 +253,22 @@ fn get_trait_attr(ctx: &Context, trait_declaration: &ast::TraitTypeDeclaration,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Ok(StructAttr::Method(result[0].clone()));
|
return Ok(StructAttr::Method(result[0].clone()));
|
||||||
}
|
|
||||||
|
|
||||||
fn get_attr(ctx: &Context, source_type: &ast::TypeUsage, attribute: &ast::Identifier) -> Result<StructAttr> {
|
|
||||||
match source_type {
|
|
||||||
ast::TypeUsage::Named(named) => {
|
|
||||||
match &ctx.environment[&named.name.name.value] {
|
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(type_declaration)) => {
|
|
||||||
return get_struct_attr(ctx, type_declaration, attribute);
|
|
||||||
}
|
}
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Trait(type_declaration)) => {
|
NamedEntity::Variable(type_) => match type_ {
|
||||||
return get_trait_attr(ctx, type_declaration, attribute);
|
ast::TypeUsage::Named(named) => {
|
||||||
|
let attr = get_attr(ctx, &ctx.environment[&named.name.name.value], attribute)?;
|
||||||
|
let method = match attr {
|
||||||
|
StructAttr::Field(field) => return Ok(StructAttr::Field(field)),
|
||||||
|
StructAttr::Method(method) => method,
|
||||||
|
};
|
||||||
|
return Ok(StructAttr::Method(apply_self(&named.name.name.value, &method)));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(errors::TypingError::AttributeOfNonstruct {
|
return Err(errors::TypingError::AttributeOfNonstruct {
|
||||||
identifier: attribute.clone(),
|
identifier: attribute.clone(),
|
||||||
});
|
});
|
||||||
// TODO: support builtins - float, int, etc.
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::TypeUsage::Function(_) => {
|
|
||||||
return Err(errors::TypingError::NotAStructLiteral {
|
|
||||||
identifier: attribute.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
panic!("tried to get attr of unknown");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compare_struct_trait(
|
|
||||||
struct_: &ast::TypeUsage,
|
|
||||||
trait_: &ast::TypeUsage,
|
|
||||||
struct_name: &ast::Identifier,
|
|
||||||
trait_name: &ast::Identifier,
|
|
||||||
) -> Result<()> {
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
return Err(errors::TypingError::TypeMismatch {
|
|
||||||
type_one: struct_.clone(),
|
|
||||||
type_two: trait_.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ast::TypeUsage::Function(_) => {
|
|
||||||
return Err(errors::TypingError::TypeMismatch {
|
|
||||||
type_one: struct_.clone(),
|
|
||||||
type_two: trait_.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => panic!("Unknown in function definition"),
|
|
||||||
},
|
},
|
||||||
ast::TypeUsage::Function(function) => match trait_ {
|
|
||||||
ast::TypeUsage::Named(_) => {
|
|
||||||
return Err(errors::TypingError::TypeMismatch {
|
|
||||||
type_one: struct_.clone(),
|
|
||||||
type_two: trait_.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ast::TypeUsage::Function(trait_function) => {
|
|
||||||
if function.arguments.len() != trait_function.arguments.len() {
|
|
||||||
return Err(errors::TypingError::TypeMismatch {
|
|
||||||
type_one: struct_.clone(),
|
|
||||||
type_two: trait_.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (i, _) in function.arguments.iter().enumerate() {
|
|
||||||
compare_struct_trait(&function.arguments[i], &trait_function.arguments[i], struct_name, trait_name)?;
|
|
||||||
}
|
|
||||||
compare_struct_trait(&function.return_type, &trait_function.return_type, struct_name, trait_name)?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
_ => panic!("Unknown in function definition"),
|
|
||||||
},
|
|
||||||
_ => panic!("Unknown in function definition"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,6 +284,59 @@ impl Context {
|
|||||||
ctx.current_function_return = Some(function.clone());
|
ctx.current_function_return = Some(function.clone());
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_impl(&self, impl_: &ast::Impl, traits: &HashMap<String, ast::TraitTypeDeclaration>) -> Result<Context> {
|
||||||
|
let mut functions = HashMap::new();
|
||||||
|
for func in impl_.functions.iter() {
|
||||||
|
functions.insert(func.declaration.name.name.value.to_string(), func.declaration.to_type());
|
||||||
|
}
|
||||||
|
// fill out defaults
|
||||||
|
match &impl_.trait_ {
|
||||||
|
Some(trait_name) => {
|
||||||
|
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(),
|
||||||
|
default_function.declaration.to_type(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
let mut result = self.clone();
|
||||||
|
let mut env_named = result.environment[&impl_.struct_name.name.value].clone();
|
||||||
|
match &mut env_named {
|
||||||
|
NamedEntity::NamedType(env_type) => {
|
||||||
|
env_type.impls.push(EnvImpl {
|
||||||
|
trait_: match &impl_.trait_ {
|
||||||
|
Some(trait_) => Some(trait_.name.value.to_string()),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
functions: functions,
|
||||||
|
});
|
||||||
|
result
|
||||||
|
.environment
|
||||||
|
.insert(impl_.struct_name.name.value.to_string(), NamedEntity::NamedType(env_type.clone()));
|
||||||
|
}
|
||||||
|
NamedEntity::Variable(_) => {
|
||||||
|
return Err(errors::TypingError::TypeDoesNotExist {
|
||||||
|
identifier: impl_.struct_name.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
|
fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
|
||||||
@@ -311,7 +348,7 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
match ctx.environment[&named.name.name.value] {
|
match ctx.environment[&named.name.name.value] {
|
||||||
NamedEntity::TypeDeclaration(_) => {
|
NamedEntity::NamedType(_) => {
|
||||||
// is a type
|
// is a type
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -464,28 +501,24 @@ impl TypeChecker {
|
|||||||
pub fn with_module(self: &Self, module: &ast::Module) -> Result<(ast::Module, SubstitutionMap)> {
|
pub fn with_module(self: &Self, module: &ast::Module) -> Result<(ast::Module, SubstitutionMap)> {
|
||||||
let mut ctx = Context {
|
let mut ctx = Context {
|
||||||
environment: create_builtins(),
|
environment: create_builtins(),
|
||||||
impls: Vec::new(),
|
|
||||||
current_function_return: None,
|
current_function_return: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut traits = HashMap::new();
|
||||||
|
|
||||||
for item in module.items.iter() {
|
for item in module.items.iter() {
|
||||||
match item {
|
match item {
|
||||||
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Struct(struct_)) => {
|
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Struct(struct_)) => {
|
||||||
ctx.environment.insert(
|
ctx.environment.insert(
|
||||||
struct_.name.name.value.to_string(),
|
struct_.name.name.value.to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(struct_.clone())),
|
NamedEntity::NamedType(EnvType::from_struct(&struct_)),
|
||||||
);
|
|
||||||
}
|
|
||||||
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::TypeDeclaration(ast::TypeDeclaration::Trait(trait_)) => {
|
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Trait(trait_)) => {
|
||||||
|
traits.insert(trait_.name.name.value.to_string(), trait_.clone());
|
||||||
ctx.environment.insert(
|
ctx.environment.insert(
|
||||||
trait_.name.name.value.to_string(),
|
trait_.name.name.value.to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Trait(trait_.clone())),
|
NamedEntity::NamedType(EnvType::from_trait(&trait_)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ast::ModuleItem::Function(function) => {
|
ast::ModuleItem::Function(function) => {
|
||||||
@@ -498,8 +531,19 @@ impl TypeChecker {
|
|||||||
NamedEntity::Variable(ast::TypeUsage::Function(function_type)),
|
NamedEntity::Variable(ast::TypeUsage::Function(function_type)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for item in module.items.iter() {
|
||||||
|
match item {
|
||||||
ast::ModuleItem::Impl(impl_) => {
|
ast::ModuleItem::Impl(impl_) => {
|
||||||
ctx.impls.push(impl_.clone());
|
if !ctx.environment.contains_key(&impl_.struct_name.name.value) {
|
||||||
|
return Err(errors::TypingError::IdentifierIsNotType {
|
||||||
|
identifier: impl_.struct_name.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ctx = ctx.add_impl(&impl_, &traits)?;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -530,11 +574,7 @@ impl TypeChecker {
|
|||||||
return Ok((result, subst));
|
return Ok((result, subst));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_function_declaration(
|
fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> Result<ast::FunctionDeclaration> {
|
||||||
self: &Self,
|
|
||||||
ctx: &Context,
|
|
||||||
declaration: &ast::FunctionDeclaration,
|
|
||||||
) -> Result<ast::FunctionDeclaration> {
|
|
||||||
for arg in declaration.arguments.iter() {
|
for arg in declaration.arguments.iter() {
|
||||||
type_exists(ctx, &arg.type_)?;
|
type_exists(ctx, &arg.type_)?;
|
||||||
}
|
}
|
||||||
@@ -621,7 +661,7 @@ impl TypeChecker {
|
|||||||
trait_: &ast::TraitTypeDeclaration,
|
trait_: &ast::TraitTypeDeclaration,
|
||||||
) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> {
|
) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> {
|
||||||
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 {
|
||||||
match item {
|
match item {
|
||||||
ast::TraitItem::FunctionDeclaration(declaration) => {
|
ast::TraitItem::FunctionDeclaration(declaration) => {
|
||||||
@@ -668,79 +708,16 @@ impl TypeChecker {
|
|||||||
impl_: &ast::Impl,
|
impl_: &ast::Impl,
|
||||||
) -> Result<(ast::Impl, SubstitutionMap)> {
|
) -> Result<(ast::Impl, SubstitutionMap)> {
|
||||||
let mut substitutions = incoming_substitutions.clone();
|
let mut substitutions = incoming_substitutions.clone();
|
||||||
type_exists(ctx, &ast::TypeUsage::new_named(&impl_.struct_name.clone(), &ast::GenericUsage::Unknown))?;
|
type_exists(
|
||||||
|
ctx,
|
||||||
|
&ast::TypeUsage::new_named(&impl_.struct_name.clone(), &ast::GenericUsage::Unknown),
|
||||||
|
)?;
|
||||||
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(&ctx, &substitutions, function)?;
|
let (result, function_subs) = self.with_function(&ctx, &substitutions, function)?;
|
||||||
substitutions = compose_substitutions(ctx, &substitutions, &function_subs)?;
|
substitutions = compose_substitutions(ctx, &substitutions, &function_subs)?;
|
||||||
functions.push(result);
|
functions.push(result);
|
||||||
}
|
}
|
||||||
// See if trait actually matches
|
|
||||||
match &impl_.trait_ {
|
|
||||||
Some(trait_) => {
|
|
||||||
// assert trait functions satisfied
|
|
||||||
if !ctx.environment.contains_key(&trait_.name.value) {
|
|
||||||
return Err(errors::TypingError::TypeDoesNotExist {
|
|
||||||
identifier: trait_.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let trait_declaration = match &ctx.environment[&trait_.name.value] {
|
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Trait(declaration)) => declaration,
|
|
||||||
_ => {
|
|
||||||
return Err(errors::TypingError::ImplTraitMustBeTrait {
|
|
||||||
trait_name: trait_.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
for trait_item in trait_declaration.functions.iter() {
|
|
||||||
match trait_item {
|
|
||||||
ast::TraitItem::FunctionDeclaration(declaration) => {
|
|
||||||
let mut found = false;
|
|
||||||
for impl_function in impl_.functions.iter() {
|
|
||||||
if impl_function.declaration.name.name.value == declaration.name.name.value {
|
|
||||||
found = true;
|
|
||||||
compare_struct_trait(&impl_function.declaration.to_type(), &declaration.to_type(), &impl_.struct_name, &trait_)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if found == false {
|
|
||||||
return Err(errors::TypingError::MissingTraitFunction {
|
|
||||||
struct_name: impl_.struct_name.clone(),
|
|
||||||
function_name: declaration.name.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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_)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// assert all functions are in trait
|
|
||||||
for impl_function in impl_.functions.iter() {
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
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(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
return Ok((
|
return Ok((
|
||||||
ast::Impl {
|
ast::Impl {
|
||||||
generic: impl_.generic.clone(),
|
generic: impl_.generic.clone(),
|
||||||
@@ -903,7 +880,7 @@ impl TypeChecker {
|
|||||||
let (source, subst) = self.with_expression(ctx, &substitution, &struct_attr.source)?;
|
let (source, subst) = self.with_expression(ctx, &substitution, &struct_attr.source)?;
|
||||||
let mut subst = subst.clone();
|
let mut subst = subst.clone();
|
||||||
|
|
||||||
let field_type = match get_attr(ctx, &source.type_, &struct_attr.attribute)? {
|
let field_type = match get_attr(ctx, &NamedEntity::Variable(source.type_.clone()), &struct_attr.attribute)? {
|
||||||
StructAttr::Field(type_) => type_,
|
StructAttr::Field(type_) => type_,
|
||||||
StructAttr::Method(_) => {
|
StructAttr::Method(_) => {
|
||||||
return Err(errors::TypingError::CannotAssignToMethod {
|
return Err(errors::TypingError::CannotAssignToMethod {
|
||||||
@@ -1062,40 +1039,47 @@ impl TypeChecker {
|
|||||||
literal_struct: &ast::LiteralStruct,
|
literal_struct: &ast::LiteralStruct,
|
||||||
) -> Result<(ast::LiteralStruct, SubstitutionMap)> {
|
) -> Result<(ast::LiteralStruct, SubstitutionMap)> {
|
||||||
let mut substitution = substitution.clone();
|
let mut substitution = substitution.clone();
|
||||||
let type_declaration = match &ctx.environment[&literal_struct.name.name.value] {
|
let struct_type = match &ctx.environment[&literal_struct.name.name.value] {
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(type_declaration)) => type_declaration,
|
NamedEntity::NamedType(env_type) => match &env_type.is_a {
|
||||||
|
TypeType::Struct => env_type.clone(),
|
||||||
|
_ => {
|
||||||
|
return Err(errors::TypingError::NotAStructLiteral {
|
||||||
|
identifier: literal_struct.name.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return Err(errors::TypingError::NotAStructLiteral {
|
return Err(errors::TypingError::NotAStructLiteral {
|
||||||
identifier: literal_struct.name.clone(),
|
identifier: literal_struct.name.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if type_declaration.fields.len() != literal_struct.fields.len() {
|
if struct_type.fields.len() != literal_struct.fields.len() {
|
||||||
return Err(errors::TypingError::StructLiteralFieldsMismatch {
|
return Err(errors::TypingError::StructLiteralFieldsMismatch {
|
||||||
struct_name: literal_struct.name.clone(),
|
struct_name: literal_struct.name.clone(),
|
||||||
struct_definition_name: type_declaration.name.clone(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let mut fields = vec![];
|
let mut fields = vec![];
|
||||||
for type_field in type_declaration.fields.iter() {
|
for (type_field_name, type_field_type) in struct_type.fields.iter() {
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
let mut field_expression: Option<ast::Expression> = None;
|
let mut field_expression: Option<ast::Expression> = None;
|
||||||
|
let mut field_name: Option<ast::Identifier> = None;
|
||||||
for field in literal_struct.fields.iter() {
|
for field in literal_struct.fields.iter() {
|
||||||
if type_field.name.name.value == field.0.name.value {
|
if type_field_name == &field.0.name.value {
|
||||||
found = true;
|
found = true;
|
||||||
let (result, subst) = self.with_expression(ctx, &substitution, &field.1)?;
|
let (result, subst) = self.with_expression(ctx, &substitution, &field.1)?;
|
||||||
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
||||||
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &type_field.type_, &result.type_)?)?;
|
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, type_field_type, &result.type_)?)?;
|
||||||
field_expression = Some(result);
|
field_expression = Some(result);
|
||||||
|
field_name = Some(field.0.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
return Err(errors::TypingError::StructLiteralFieldsMismatch {
|
return Err(errors::TypingError::StructLiteralFieldsMismatch {
|
||||||
struct_name: literal_struct.name.clone(),
|
struct_name: literal_struct.name.clone(),
|
||||||
struct_definition_name: type_field.name.clone(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
fields.push((type_field.name.clone(), field_expression.unwrap()));
|
fields.push((field_name.unwrap(), field_expression.unwrap()));
|
||||||
}
|
}
|
||||||
Ok((
|
Ok((
|
||||||
ast::LiteralStruct {
|
ast::LiteralStruct {
|
||||||
@@ -1164,8 +1148,10 @@ 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::TypeDeclaration(_) => {
|
NamedEntity::NamedType(_) => {
|
||||||
panic!("Using types not yet supported");
|
return Err(errors::TypingError::TypeIsNotAnExpression {
|
||||||
|
type_name: variable_usage.name.clone(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
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)?)?;
|
||||||
@@ -1277,7 +1263,7 @@ impl TypeChecker {
|
|||||||
let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source)?;
|
let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source)?;
|
||||||
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
||||||
|
|
||||||
let field_type = match get_attr(ctx, &source.type_, &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(type_) => type_,
|
||||||
};
|
};
|
||||||
@@ -1295,14 +1281,24 @@ impl TypeChecker {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_block_expression(self: &Self, ctx: &Context, substitution: &SubstitutionMap, block: &ast::Block) -> Result<(ast::Block, SubstitutionMap)> {
|
fn with_block_expression(
|
||||||
|
self: &Self,
|
||||||
|
ctx: &Context,
|
||||||
|
substitution: &SubstitutionMap,
|
||||||
|
block: &ast::Block,
|
||||||
|
) -> Result<(ast::Block, SubstitutionMap)> {
|
||||||
let mut substitution = substitution.clone();
|
let mut substitution = substitution.clone();
|
||||||
let (result, subst) = self.with_block(ctx, &substitution, &block)?;
|
let (result, subst) = self.with_block(ctx, &substitution, &block)?;
|
||||||
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
||||||
Ok((result, substitution))
|
Ok((result, substitution))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_op(self: &Self, ctx: &Context, substitution: &SubstitutionMap, op: &ast::Operation) -> Result<(ast::Operation, SubstitutionMap)> {
|
fn with_op(
|
||||||
|
self: &Self,
|
||||||
|
ctx: &Context,
|
||||||
|
substitution: &SubstitutionMap,
|
||||||
|
op: &ast::Operation,
|
||||||
|
) -> Result<(ast::Operation, SubstitutionMap)> {
|
||||||
let mut substitution = substitution.clone();
|
let mut substitution = substitution.clone();
|
||||||
let (expr_left, subst_left) = self.with_expression(ctx, &substitution, &op.left)?;
|
let (expr_left, subst_left) = self.with_expression(ctx, &substitution, &op.left)?;
|
||||||
let (expr_right, subst_right) = self.with_expression(ctx, &substitution, &op.right)?;
|
let (expr_right, subst_right) = self.with_expression(ctx, &substitution, &op.right)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user