Skip to content

Commit

Permalink
Parse custom types as part of module
Browse files Browse the repository at this point in the history
  • Loading branch information
dusty-phillips committed Sep 15, 2024
1 parent a2a9914 commit f24a6af
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 13 deletions.
17 changes: 14 additions & 3 deletions src/glimpse/typecheck.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,26 @@ import glimpse/internal/typecheck/types
pub fn module(
package: glimpse.Package,
module_name: String,
) -> Result(glimpse.Package, error.TypeCheckError) {
) -> Result(#(glimpse.Package, Environment), error.TypeCheckError) {
let glimpse_module_result =
dict.get(package.modules, module_name)
|> result.replace_error(error.NoSuchModule(module_name))

use glimpse_module <- result.try(glimpse_module_result)

let environment = environment.new()
// TODO: Put custom types, imports, consts in the env

let custom_type_result =
glimpse_module.module.custom_types
|> list.fold_until(Ok(environment), fn(state, glance_custom_type) {
case state {
Error(error) -> list.Stop(Error(error))
Ok(environment) ->
list.Continue(custom_type(environment, glance_custom_type.definition))
}
})

use environment <- result.try(custom_type_result)

// I'm pretty sure functions cannot update the global environment,
// so we don't need to reassign it.
Expand All @@ -47,7 +58,7 @@ pub fn module(
let glimpse_module = glimpse.Module(..glimpse_module, module: glance_module)
let module_dict = dict.insert(package.modules, module_name, glimpse_module)
let package = glimpse.Package(..package, modules: module_dict)
Ok(package)
Ok(#(package, environment))
// TODO: Pretty sure this needs to also return an updated environment
// that contains the public types and functions of the module
}
Expand Down
75 changes: 72 additions & 3 deletions test/typecheck/custom_types_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import gleam/dict
import gleeunit/should
import glimpse/internal/typecheck/types
import glimpse/internal/typecheck/variants
import pprint
import typecheck/helpers

pub fn simple_custom_type_test() {
Expand All @@ -16,6 +15,11 @@ pub fn simple_custom_type_test() {
|> dict.size
|> should.equal(1)

env.custom_types
|> dict.get("MyType")
|> should.be_ok
|> should.equal(types.CustomType("MyType"))

env.constructors
|> dict.size
|> should.equal(1)
Expand Down Expand Up @@ -46,6 +50,11 @@ pub fn positional_variant_custom_type_test() {
|> dict.size
|> should.equal(1)

env.custom_types
|> dict.get("MyType")
|> should.be_ok
|> should.equal(types.CustomType("MyType"))

env.constructors
|> dict.size
|> should.equal(1)
Expand Down Expand Up @@ -77,6 +86,11 @@ pub fn multi_variant_custom_type_test() {
|> dict.size
|> should.equal(1)

env.custom_types
|> dict.get("MyType")
|> should.be_ok
|> should.equal(types.CustomType("MyType"))

env.constructors
|> dict.size
|> should.equal(2)
Expand Down Expand Up @@ -112,12 +126,15 @@ pub fn recursive_custom_type_test() {
}"
|> helpers.ok_custom_type

pprint.debug(env)

env.custom_types
|> dict.size
|> should.equal(1)

env.custom_types
|> dict.get("MyType")
|> should.be_ok
|> should.equal(types.CustomType("MyType"))

env.constructors
|> dict.size
|> should.equal(2)
Expand All @@ -144,3 +161,55 @@ pub fn recursive_custom_type_test() {
constructor2.fields
|> should.equal([variants.NamedField("next", types.CustomType("MyType"))])
}

pub fn custom_type_from_module_test() {
let #(_module, env) =
"type MyType {
MyTypeConstructor(name: String)
}
type MyOtherType {
MyOtherType(name: String)
}"
|> helpers.ok_module_typecheck

env.custom_types
|> dict.size
|> should.equal(2)

env.custom_types
|> dict.get("MyType")
|> should.be_ok
|> should.equal(types.CustomType("MyType"))

env.custom_types
|> dict.get("MyOtherType")
|> should.be_ok
|> should.equal(types.CustomType("MyOtherType"))

env.constructors
|> dict.size
|> should.equal(2)

let constructor1 =
env.constructors
|> dict.get("MyTypeConstructor")
|> should.be_ok
constructor1.name
|> should.equal("MyTypeConstructor")
constructor1.custom_type
|> should.equal("MyType")
constructor1.fields
|> should.equal([variants.NamedField("name", types.StringType)])

let constructor2 =
env.constructors
|> dict.get("MyOtherType")
|> should.be_ok
constructor2.name
|> should.equal("MyOtherType")
constructor2.custom_type
|> should.equal("MyOtherType")
constructor2.fields
|> should.equal([variants.NamedField("name", types.StringType)])
}
15 changes: 9 additions & 6 deletions test/typecheck/helpers.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import gleam/list
import gleeunit/should
import glimpse
import glimpse/error
import glimpse/internal/typecheck/environment
import glimpse/internal/typecheck/environment.{type Environment}
import glimpse/typecheck

pub fn glance_custom_type(definition: String) -> glance.CustomType {
Expand Down Expand Up @@ -50,16 +50,19 @@ pub fn error_function_typecheck(definition: String) -> error.TypeCheckError {
|> should.be_error
}

pub fn ok_module_typecheck(definition: String) -> glimpse.Module {
let inferred_package =
pub fn ok_module_typecheck(definition: String) -> #(glimpse.Module, Environment) {
let #(inferred_package, environment) =
glimpse.load_package("main_module", fn(_) { Ok(definition) })
|> should.be_ok
|> typecheck.module("main_module")
|> should.be_ok

inferred_package.modules
|> dict.get("main_module")
|> should.be_ok
let main_mod =
inferred_package.modules
|> dict.get("main_module")
|> should.be_ok

#(main_mod, environment)
}

pub fn error_module_typecheck(definition: String) -> error.TypeCheckError {
Expand Down
2 changes: 1 addition & 1 deletion test/typecheck/infer_module_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import glimpse/error
import typecheck/helpers

pub fn module_with_two_functions_test() {
let inferred_module =
let #(inferred_module, _env) =
helpers.ok_module_typecheck(
"
pub fn add(a: Int, b:Int) {a + b}
Expand Down

0 comments on commit f24a6af

Please sign in to comment.