From d0287d418bfefdff96adf28dcd6b9217ecb57c7c Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 17 Oct 2022 17:14:36 -0400 Subject: [PATCH] feat: add prelude --- crates/cli/src/project.rs | 9 +- crates/lang/src/builtins.rs | 272 +++++++++++++++++++++++++++++++++- crates/lang/src/lib.rs | 17 +++ crates/lang/src/tipo.rs | 15 +- crates/lang/src/tipo/infer.rs | 7 +- 5 files changed, 310 insertions(+), 10 deletions(-) diff --git a/crates/cli/src/project.rs b/crates/cli/src/project.rs index c1682ac6..badb0cbe 100644 --- a/crates/cli/src/project.rs +++ b/crates/cli/src/project.rs @@ -4,7 +4,7 @@ use std::{ path::{Path, PathBuf}, }; -use aiken_lang::{ast::ModuleKind, builtins, tipo}; +use aiken_lang::{ast::ModuleKind, builtins, tipo, IdGenerator}; use crate::{ config::Config, @@ -38,6 +38,7 @@ impl Warning { pub struct Project { config: Config, defined_modules: HashMap, + id_gen: IdGenerator, module_types: HashMap, root: PathBuf, sources: Vec, @@ -46,13 +47,16 @@ pub struct Project { impl Project { pub fn new(config: Config, root: PathBuf) -> Project { + let id_gen = IdGenerator::new(); + let mut module_types = HashMap::new(); - module_types.insert("aiken".to_string(), builtins::prelude()); + module_types.insert("aiken".to_string(), builtins::prelude(&id_gen)); Project { config, defined_modules: HashMap::new(), + id_gen, module_types, root, sources: vec![], @@ -161,6 +165,7 @@ impl Project { let mut type_warnings = Vec::new(); let ast = tipo::infer::module( + &self.id_gen, ast, kind, &self.config.name, diff --git a/crates/lang/src/builtins.rs b/crates/lang/src/builtins.rs index 5e8e7b37..3e73eae4 100644 --- a/crates/lang/src/builtins.rs +++ b/crates/lang/src/builtins.rs @@ -1,10 +1,24 @@ -use std::collections::HashMap; +use std::{cell::RefCell, collections::HashMap, sync::Arc}; -use crate::{ast::ModuleKind, tipo}; +use crate::{ + ast::{ModuleKind, Span}, + tipo::{self, Type, TypeConstructor, TypeVar, ValueConstructor, ValueConstructorVariant}, + IdGenerator, +}; -pub fn prelude() -> tipo::Module { +const BYTE_ARRAY: &str = "ByteArray"; +const BOOL: &str = "Bool"; +const INT: &str = "Int"; +const LIST: &str = "List"; +const NIL: &str = "Nil"; +const RESULT: &str = "Result"; +const STRING: &str = "String"; + +/// Build a prelude that can be injected +/// into a compiler pipeline +pub fn prelude(id_gen: &IdGenerator) -> tipo::Module { let mut prelude = tipo::Module { - name: vec!["gleam".to_string()], + name: vec!["aiken".to_string()], package: "".to_string(), kind: ModuleKind::Lib, types: HashMap::new(), @@ -13,5 +27,255 @@ pub fn prelude() -> tipo::Module { accessors: HashMap::new(), }; + // Int + prelude.types.insert( + INT.to_string(), + TypeConstructor { + parameters: vec![], + tipo: int(), + origin: Span::empty(), + module: vec![], + public: true, + }, + ); + + // ByteArray + prelude.types.insert( + BYTE_ARRAY.to_string(), + TypeConstructor { + origin: Span::empty(), + parameters: vec![], + tipo: byte_array(), + module: vec![], + public: true, + }, + ); + + // Bool + prelude.types_constructors.insert( + BOOL.to_string(), + vec!["True".to_string(), "False".to_string()], + ); + + prelude.values.insert( + "True".to_string(), + ValueConstructor::public( + bool(), + ValueConstructorVariant::Record { + module: "".into(), + name: "True".to_string(), + field_map: None, + arity: 0, + location: Span::empty(), + constructors_count: 2, + }, + ), + ); + + prelude.values.insert( + "False".to_string(), + ValueConstructor::public( + bool(), + ValueConstructorVariant::Record { + module: "".into(), + name: "False".to_string(), + field_map: None, + arity: 0, + location: Span::empty(), + constructors_count: 2, + }, + ), + ); + + prelude.types.insert( + BOOL.to_string(), + TypeConstructor { + origin: Span::empty(), + parameters: vec![], + tipo: bool(), + module: vec![], + public: true, + }, + ); + + // List(a) + let list_parameter = generic_var(id_gen.next()); + prelude.types.insert( + LIST.to_string(), + TypeConstructor { + origin: Span::empty(), + parameters: vec![list_parameter.clone()], + tipo: list(list_parameter), + module: vec![], + public: true, + }, + ); + + // String + prelude.types.insert( + STRING.to_string(), + TypeConstructor { + origin: Span::empty(), + parameters: vec![], + tipo: string(), + module: vec![], + public: true, + }, + ); + + // Nil + prelude.values.insert( + NIL.to_string(), + ValueConstructor::public( + nil(), + ValueConstructorVariant::Record { + module: "".into(), + name: NIL.to_string(), + arity: 0, + field_map: None, + location: Span::empty(), + constructors_count: 1, + }, + ), + ); + + prelude.types.insert( + NIL.to_string(), + TypeConstructor { + origin: Span::empty(), + parameters: vec![], + tipo: nil(), + module: vec![], + public: true, + }, + ); + + // Result(value, error) + let result_value = generic_var(id_gen.next()); + let result_error = generic_var(id_gen.next()); + + prelude.types.insert( + RESULT.to_string(), + TypeConstructor { + origin: Span::empty(), + parameters: vec![result_value.clone(), result_error.clone()], + tipo: result(result_value, result_error), + module: vec![], + public: true, + }, + ); + + prelude.types_constructors.insert( + RESULT.to_string(), + vec!["Ok".to_string(), "Err".to_string()], + ); + + let ok = generic_var(id_gen.next()); + let error = generic_var(id_gen.next()); + let _ = prelude.values.insert( + "Ok".to_string(), + ValueConstructor::public( + function(vec![ok.clone()], result(ok, error)), + ValueConstructorVariant::Record { + module: "".into(), + name: "Ok".to_string(), + field_map: None, + arity: 1, + location: Span::empty(), + constructors_count: 2, + }, + ), + ); + + let ok = generic_var(id_gen.next()); + let error = generic_var(id_gen.next()); + let _ = prelude.values.insert( + "Error".to_string(), + ValueConstructor::public( + function(vec![error.clone()], result(ok, error)), + ValueConstructorVariant::Record { + module: "".into(), + name: "Error".to_string(), + field_map: None, + arity: 1, + location: Span::empty(), + constructors_count: 2, + }, + ), + ); + prelude } + +pub fn int() -> Arc { + Arc::new(Type::App { + public: true, + name: INT.to_string(), + module: vec![], + args: vec![], + }) +} + +pub fn byte_array() -> Arc { + Arc::new(Type::App { + args: vec![], + public: true, + name: BYTE_ARRAY.to_string(), + module: vec![], + }) +} + +pub fn bool() -> Arc { + Arc::new(Type::App { + args: vec![], + public: true, + name: BOOL.to_string(), + module: vec![], + }) +} + +pub fn list(t: Arc) -> Arc { + Arc::new(Type::App { + public: true, + name: LIST.to_string(), + module: vec![], + args: vec![t], + }) +} + +pub fn string() -> Arc { + Arc::new(Type::App { + args: vec![], + public: true, + name: STRING.to_string(), + module: vec![], + }) +} + +pub fn nil() -> Arc { + Arc::new(Type::App { + args: vec![], + public: true, + name: NIL.to_string(), + module: vec![], + }) +} + +pub fn result(a: Arc, e: Arc) -> Arc { + Arc::new(Type::App { + public: true, + name: RESULT.to_string(), + module: vec![], + args: vec![a, e], + }) +} + +pub fn function(args: Vec>, ret: Arc) -> Arc { + Arc::new(Type::Fn { ret, args }) +} + +pub fn generic_var(id: u64) -> Arc { + let tipo = Arc::new(RefCell::new(TypeVar::Generic { id })); + + Arc::new(Type::Var { tipo }) +} diff --git a/crates/lang/src/lib.rs b/crates/lang/src/lib.rs index eedb7b8f..0d36e5ca 100644 --- a/crates/lang/src/lib.rs +++ b/crates/lang/src/lib.rs @@ -1,3 +1,5 @@ +use std::sync::atomic::{AtomicU64, Ordering}; + pub mod ast; pub mod builtins; pub mod error; @@ -7,5 +9,20 @@ pub mod parser; pub mod tipo; pub mod token; +#[derive(Debug, Default)] +pub struct IdGenerator { + id: AtomicU64, +} + +impl IdGenerator { + pub fn new() -> Self { + Self::default() + } + + pub fn next(&self) -> u64 { + self.id.fetch_add(1, Ordering::Relaxed) + } +} + #[cfg(test)] mod tests; diff --git a/crates/lang/src/tipo.rs b/crates/lang/src/tipo.rs index a66b3688..078ede63 100644 --- a/crates/lang/src/tipo.rs +++ b/crates/lang/src/tipo.rs @@ -26,7 +26,7 @@ pub enum Type { /// Fn { args: Vec>, - retrn: Arc, + ret: Arc, }, /// A type variable. See the contained `TypeVar` enum for more information. @@ -74,6 +74,16 @@ pub struct ValueConstructor { pub tipo: Arc, } +impl ValueConstructor { + pub fn public(tipo: Arc, variant: ValueConstructorVariant) -> ValueConstructor { + ValueConstructor { + public: true, + variant, + tipo, + } + } +} + #[derive(Debug, Clone, PartialEq)] pub enum ValueConstructorVariant { /// A locally defined variable or function parameter @@ -102,6 +112,7 @@ pub enum ValueConstructorVariant { field_map: Option, location: Span, module: String, + constructors_count: u16, }, } @@ -122,7 +133,7 @@ pub struct TypeConstructor { pub origin: Span, pub module: Vec, pub parameters: Vec>, - pub typ: Arc, + pub tipo: Arc, } #[derive(Debug, Clone)] diff --git a/crates/lang/src/tipo/infer.rs b/crates/lang/src/tipo/infer.rs index a7cb368b..95007a24 100644 --- a/crates/lang/src/tipo/infer.rs +++ b/crates/lang/src/tipo/infer.rs @@ -1,6 +1,9 @@ use std::collections::HashMap; -use crate::ast::{ModuleKind, TypedModule, UntypedModule}; +use crate::{ + ast::{ModuleKind, TypedModule, UntypedModule}, + IdGenerator, +}; use super::{ error::{Error, Warning}, @@ -8,7 +11,7 @@ use super::{ }; pub fn module( - // ids: &UniqueIdGenerator, + id_gen: &IdGenerator, mut module: UntypedModule, kind: ModuleKind, package: &str,