Skip to content

Commit

Permalink
Add variants to function definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
dusty-phillips committed Sep 17, 2024
1 parent df5cf65 commit 9176bc0
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 275 deletions.
73 changes: 47 additions & 26 deletions src/glimpse/internal/typecheck.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import glimpse/internal/typecheck/functions.{
type CallableState, type CallableStateFold, type CallableStateResult,
}
import glimpse/internal/typecheck/types.{type TypeResult}
import glimpse/internal/typecheck/variants.{type VariantField}
import pprint

/// Used when checking the function signature.
Expand Down Expand Up @@ -89,47 +88,69 @@ pub fn fold_function_parameter_into_env(
}
}

pub fn fold_variant_constructors(
/// Ensure variant constructors are added as function types to the environment's
/// definition.
///
/// HackNote: The TypeState passed in is using the type as the custom_type on the
/// constructed callable. It is not an output.
pub fn fold_variant_constructors_into_env(
state: TypeStateResult,
variant: glance.Variant,
) -> TypeStateFold {
case state {
Error(error) -> list.Stop(Error(error))
Ok(environment.EnvState(environment, types.CustomType(custom_type))) ->
Ok(environment.EnvState(environment, custom_type)) ->
{
use variant_fields <- result.try(
use callable_state <- result.try(
variant.fields
|> list.map(variant_field(environment, _))
|> result.all,
|> list.fold_until(
Ok(functions.empty_state(environment)),
fold_variant_field_into_callable,
),
)

Ok(environment.EnvState(
environment.add_variant_constructor(
environment,
let environment =
environment
|> environment.add_def(
variant.name,
variants.Variant(variant.name, custom_type, variant_fields),
),
types.CustomType(custom_type),
))
functions.to_callable_type(callable_state, custom_type),
)

Ok(environment.EnvState(environment, custom_type))
}
|> list.Continue
Ok(_) -> panic as "Variant custom type should only be custom type"
}
}

pub fn variant_field(
environment: Environment,
pub fn fold_variant_field_into_callable(
state: CallableStateResult,
field: glance.Field(glance.Type),
) -> error.TypeCheckResult(VariantField) {
case field {
glance.Field(option.Some(field_name), glance_type) -> {
use field_type <- result.try(type_(environment, glance_type))
Ok(variants.NamedField(field_name, field_type))
}
glance.Field(option.None, glance_type) -> {
use field_type <- result.try(type_(environment, glance_type))
Ok(variants.PositionField(field_type))
}
) -> CallableStateFold {
case state {
Error(error) -> list.Stop(Error(error))
Ok(functions.CallableState(environment, reversed_by_position, labels)) ->
{
case field {
glance.Field(label: option.Some(label), item: glance_type) -> {
use glimpse_type <- result.try(type_(environment, glance_type))
Ok(functions.CallableState(
environment,
[glimpse_type, ..reversed_by_position],
dict.insert(labels, label, reversed_by_position |> list.length),
))
}

glance.Field(label: option.None, item: glance_type) -> {
use glimpse_type <- result.try(type_(environment, glance_type))
Ok(functions.CallableState(
environment,
[glimpse_type, ..reversed_by_position],
labels,
))
}
}
}
|> list.Continue
}
}

Expand Down
19 changes: 1 addition & 18 deletions src/glimpse/internal/typecheck/environment.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import gleam/dict
import gleam/result
import glimpse/error
import glimpse/internal/typecheck/types.{type Type, type TypeResult}
import glimpse/internal/typecheck/variants.{type Variant}

pub type Environment {
Environment(
definitions: dict.Dict(String, Type),
custom_types: dict.Dict(String, Type),
constructors: dict.Dict(String, Variant),
)
}

Expand All @@ -35,11 +33,7 @@ pub type EnvironmentFold =
error.TypeCheckFold(Environment)

pub fn new() -> Environment {
Environment(
definitions: dict.new(),
custom_types: dict.new(),
constructors: dict.new(),
)
Environment(definitions: dict.new(), custom_types: dict.new())
}

pub fn add_def(
Expand All @@ -64,17 +58,6 @@ pub fn add_custom_type(environment: Environment, name: String) -> Environment {
)
}

pub fn add_variant_constructor(
environment: Environment,
name: String,
constructor: Variant,
) -> Environment {
Environment(
..environment,
constructors: dict.insert(environment.constructors, name, constructor),
)
}

pub fn lookup_variable_type(
environment: Environment,
name: String,
Expand Down
10 changes: 0 additions & 10 deletions src/glimpse/internal/typecheck/variants.gleam

This file was deleted.

2 changes: 1 addition & 1 deletion src/glimpse/typecheck.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub fn custom_type(
list.fold_until(
custom_type.variants,
Ok(environment.EnvState(environment, types.CustomType(custom_type.name))),
intern.fold_variant_constructors,
intern.fold_variant_constructors_into_env,
)
|> result.map(environment.extract_env)
}
Expand Down
9 changes: 3 additions & 6 deletions test/load_package_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import gleam/dict
import gleeunit/should
import glimpse
import glimpse/error
import typecheck/assertions

pub fn ok_module(contents: String) -> glance.Module {
glance.module(contents)
Expand Down Expand Up @@ -41,9 +42,7 @@ pub fn single_dependency_package_test() {
loaded_package.name
|> should.equal("main_module")

loaded_package.modules
|> dict.size
|> should.equal(2)
assertions.should_have_dict_size(loaded_package.modules, 2)

expect_modules_equal(
loaded_package,
Expand Down Expand Up @@ -71,9 +70,7 @@ pub fn diamond_dependency_package_test() {
loaded_package.name
|> should.equal("main_module")

loaded_package.modules
|> dict.size
|> should.equal(4)
assertions.should_have_dict_size(loaded_package.modules, 4)

expect_modules_equal(
loaded_package,
Expand Down
37 changes: 37 additions & 0 deletions test/typecheck/assertions.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import gleam/dict
import gleam/list
import gleeunit/should
import glimpse/internal/typecheck/environment.{type Environment}
import glimpse/internal/typecheck/types.{type Type}

pub fn should_have_dict_size(dict: dict.Dict(a, b), size: Int) {
dict |> dict.size |> should.equal(size)
}

pub fn should_have_list_length(list: List(a), size: Int) {
list |> list.length |> should.equal(size)
}

pub fn should_have_type(env: Environment, name: String) {
env.custom_types
|> dict.get(name)
|> should.be_ok
|> should.equal(types.CustomType(name))
}

pub fn should_be_callable(
env: Environment,
definition_name: String,
params: List(Type),
position_labels: List(#(String, Int)),
return: Type,
) -> Nil {
env.definitions
|> dict.get(definition_name)
|> should.be_ok
|> should.equal(types.CallableType(
params,
dict.from_list(position_labels),
return,
))
}
Loading

0 comments on commit 9176bc0

Please sign in to comment.