feat: some boilerplate for typechecking

This commit is contained in:
rvcas 2022-10-13 18:34:25 -04:00 committed by Lucas
parent ed2ef4fa9b
commit 4df3de0a03
13 changed files with 264 additions and 34 deletions

View File

@ -4,7 +4,7 @@ use std::{
path::PathBuf,
};
use aiken_lang::error::ParseError;
use aiken_lang::{error::ParseError, tipo};
use miette::{EyreContext, LabeledSpan, MietteHandlerOpts, RgbColors, SourceCode};
#[allow(dead_code)]
@ -16,10 +16,17 @@ pub enum Error {
first: PathBuf,
second: PathBuf,
},
#[error("file operation failed")]
FileIo { error: io::Error, path: PathBuf },
#[error("cyclical module imports")]
ImportCycle { modules: Vec<String> },
/// Useful for returning many [`Error::Parse`] at once
#[error("a list of errors")]
List(Vec<Self>),
#[error("failed to parse")]
Parse {
path: PathBuf,
@ -29,9 +36,13 @@ pub enum Error {
#[source]
error: Box<ParseError>,
},
/// Useful for returning many [`Error::Parse`] at once
#[error("a list of errors")]
List(Vec<Self>),
#[error("type checking failed")]
Type {
path: PathBuf,
src: String,
error: tipo::error::Error,
},
}
impl Debug for Error {
@ -56,11 +67,12 @@ impl Debug for Error {
impl miette::Diagnostic for Error {
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
match self {
Error::DuplicateModule { .. } => Some(Box::new("aiken::project::duplicate_module")),
Error::DuplicateModule { .. } => Some(Box::new("aiken::module::duplicate")),
Error::FileIo { .. } => None,
Error::ImportCycle { .. } => Some(Box::new("aiken::project::cyclical_import")),
Error::Parse { .. } => Some(Box::new("aiken::parser")),
Error::ImportCycle { .. } => Some(Box::new("aiken::module::cyclical")),
Error::List(_) => None,
Error::Parse { .. } => Some(Box::new("aiken::parser")),
Error::Type { .. } => Some(Box::new("aiken::typecheck")),
}
}
@ -76,8 +88,9 @@ impl miette::Diagnostic for Error {
"try moving the shared code to a separate module that the others can depend on\n- {}",
modules.join("\n- ")
))),
Error::Parse { error, .. } => error.kind.help(),
Error::List(_) => None,
Error::Parse { error, .. } => error.kind.help(),
Error::Type { .. } => None,
}
}
@ -86,8 +99,9 @@ impl miette::Diagnostic for Error {
Error::DuplicateModule { .. } => None,
Error::FileIo { .. } => None,
Error::ImportCycle { .. } => None,
Error::Parse { error, .. } => error.labels(),
Error::List(_) => None,
Error::Parse { error, .. } => error.labels(),
Error::Type { error, .. } => error.labels(),
}
}
@ -96,8 +110,9 @@ impl miette::Diagnostic for Error {
Error::DuplicateModule { .. } => None,
Error::FileIo { .. } => None,
Error::ImportCycle { .. } => None,
Error::Parse { src, .. } => Some(src),
Error::List(_) => None,
Error::Parse { src, .. } => Some(src),
Error::Type { src, .. } => Some(src),
}
}
}

View File

@ -2,3 +2,6 @@ pub mod config;
pub mod error;
pub mod module;
pub mod project;
pub use aiken_lang;
pub use uplc;

View File

@ -1,16 +1,15 @@
use std::{
collections::{HashMap, HashSet},
ops::Deref,
ops::{Deref, DerefMut},
path::PathBuf,
};
use aiken_lang::ast::{ModuleKind, UntypedModule};
use aiken_lang::ast::{ModuleKind, TypedModule, UntypedModule};
use petgraph::{algo, graph::NodeIndex, Direction, Graph};
use crate::error::Error;
#[derive(Debug)]
#[allow(dead_code)]
pub struct ParsedModule {
pub path: PathBuf,
pub name: String,
@ -120,6 +119,12 @@ impl Deref for ParsedModules {
}
}
impl DerefMut for ParsedModules {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
fn find_cycle(
origin: NodeIndex,
parent: NodeIndex,
@ -149,3 +154,13 @@ fn find_cycle(
false
}
#[derive(Debug)]
pub struct CheckedModule {
pub name: String,
pub code: String,
pub input_path: PathBuf,
pub kind: ModuleKind,
pub ast: TypedModule,
// pub extra: ModuleExtra,
}

View File

@ -4,12 +4,12 @@ use std::{
path::{Path, PathBuf},
};
use aiken_lang::ast::ModuleKind;
use aiken_lang::{ast::ModuleKind, builtins, tipo};
use crate::{
config::Config,
error::Error,
module::{ParsedModule, ParsedModules},
module::{CheckedModule, ParsedModule, ParsedModules},
};
#[derive(Debug)]
@ -20,20 +20,43 @@ pub struct Source {
pub kind: ModuleKind,
}
#[derive(Debug, PartialEq)]
pub enum Warning {
Type {
path: PathBuf,
src: String,
warning: tipo::error::Warning,
},
}
impl Warning {
pub fn from_type_warning(warning: tipo::error::Warning, path: PathBuf, src: String) -> Warning {
Warning::Type { path, warning, src }
}
}
pub struct Project {
config: Config,
defined_modules: HashMap<String, PathBuf>,
module_types: HashMap<String, tipo::Module>,
root: PathBuf,
sources: Vec<Source>,
defined_modules: HashMap<String, PathBuf>,
warnings: Vec<Warning>,
}
impl Project {
pub fn new(config: Config, root: PathBuf) -> Project {
let mut module_types = HashMap::new();
module_types.insert("aiken".to_string(), builtins::prelude());
Project {
config,
defined_modules: HashMap::new(),
module_types,
root,
sources: vec![],
defined_modules: HashMap::new(),
warnings: vec![],
}
}
@ -44,6 +67,20 @@ impl Project {
let processing_sequence = parsed_modules.sequence()?;
let checked_modules = self.type_check(parsed_modules, processing_sequence)?;
println!("{:?}", checked_modules);
Ok(())
}
fn read_source_files(&mut self) -> Result<(), Error> {
let lib = self.root.join("lib");
let scripts = self.root.join("scripts");
self.aiken_files(&scripts, ModuleKind::Script)?;
self.aiken_files(&lib, ModuleKind::Lib)?;
Ok(())
}
@ -104,14 +141,62 @@ impl Project {
}
}
fn read_source_files(&mut self) -> Result<(), Error> {
let lib = self.root.join("lib");
let scripts = self.root.join("scripts");
fn type_check(
&mut self,
mut parsed_modules: ParsedModules,
processing_sequence: Vec<String>,
) -> Result<Vec<CheckedModule>, Error> {
let mut modules = Vec::with_capacity(parsed_modules.len() + 1);
self.aiken_files(&scripts, ModuleKind::Script)?;
self.aiken_files(&lib, ModuleKind::Lib)?;
for name in processing_sequence {
if let Some(ParsedModule {
name,
path,
code,
kind,
package,
ast,
}) = parsed_modules.remove(&name)
{
let mut type_warnings = Vec::new();
Ok(())
let ast = tipo::infer::module(
ast,
kind,
&self.config.name,
&self.module_types,
&mut type_warnings,
)
.map_err(|error| Error::Type {
path: path.clone(),
src: code.clone(),
error,
})?;
// Register any warnings emitted as type warnings
let type_warnings = type_warnings
.into_iter()
.map(|w| Warning::from_type_warning(w, path.clone(), code.clone()));
self.warnings.extend(type_warnings);
// Register the types from this module so they can be imported into
// other modules.
self.module_types
.insert(name.clone(), ast.type_info.clone());
modules.push(CheckedModule {
kind,
// extra,
name,
code,
ast,
input_path: path,
});
}
}
Ok(modules)
}
fn aiken_files(&mut self, dir: &Path, kind: ModuleKind) -> Result<(), Error> {

View File

@ -481,6 +481,7 @@ pub struct IfBranch<Expr> {
pub location: Span,
}
#[derive(Debug)]
pub struct TypedRecordUpdateArg {
pub label: String,
pub location: Span,

View File

@ -1,4 +0,0 @@
pub enum Origin {
Src,
Test,
}

View File

@ -0,0 +1,17 @@
use std::collections::HashMap;
use crate::{ast::ModuleKind, tipo};
pub fn prelude() -> tipo::Module {
let mut prelude = tipo::Module {
name: vec!["gleam".to_string()],
package: "".to_string(),
kind: ModuleKind::Lib,
types: HashMap::new(),
types_constructors: HashMap::new(),
values: HashMap::new(),
accessors: HashMap::new(),
};
prelude
}

View File

@ -10,6 +10,7 @@ use crate::{
tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor},
};
#[derive(Debug)]
pub enum TypedExpr {
Int {
location: Span,

View File

@ -1,5 +1,5 @@
pub mod ast;
pub mod build;
pub mod builtins;
pub mod error;
pub mod expr;
pub mod lexer;

View File

@ -1,9 +1,9 @@
use std::{cell::RefCell, collections::HashMap, sync::Arc};
use crate::{
ast::{Constant, FieldMap, Span, TypedConstant},
build::Origin,
};
use crate::ast::{Constant, FieldMap, ModuleKind, Span, TypedConstant};
pub mod error;
pub mod infer;
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
@ -105,9 +105,10 @@ pub enum ValueConstructorVariant {
},
}
#[derive(Debug, Clone)]
pub struct Module {
pub name: Vec<String>,
pub origin: Origin,
pub kind: ModuleKind,
pub package: String,
pub types: HashMap<String, TypeConstructor>,
pub types_constructors: HashMap<String, Vec<String>>,
@ -115,6 +116,7 @@ pub struct Module {
pub accessors: HashMap<String, AccessorsMap>,
}
#[derive(Debug, Clone)]
pub struct TypeConstructor {
pub public: bool,
pub origin: Span,
@ -123,12 +125,14 @@ pub struct TypeConstructor {
pub typ: Arc<Type>,
}
#[derive(Debug, Clone)]
pub struct AccessorsMap {
pub public: bool,
pub tipo: Arc<Type>,
pub accessors: HashMap<String, RecordAccessor>,
}
#[derive(Debug, Clone)]
pub struct RecordAccessor {
// TODO: smaller int. Doesn't need to be this big
pub index: u64,
@ -136,6 +140,7 @@ pub struct RecordAccessor {
pub tipo: Arc<Type>,
}
#[derive(Debug)]
pub enum PatternConstructor {
Record {
name: String,
@ -143,6 +148,7 @@ pub enum PatternConstructor {
},
}
#[derive(Debug)]
pub enum ModuleValueConstructor {
Record {
name: String,

View File

@ -0,0 +1,72 @@
use std::sync::Arc;
use miette::Diagnostic;
use crate::ast::{Span, TodoKind};
use super::Type;
#[derive(Debug, thiserror::Error, Diagnostic)]
pub enum Error {}
#[derive(Debug, PartialEq, Clone)]
pub enum Warning {
Todo {
kind: TodoKind,
location: Span,
typ: Arc<Type>,
},
ImplicitlyDiscardedResult {
location: Span,
},
UnusedLiteral {
location: Span,
},
NoFieldsRecordUpdate {
location: Span,
},
AllFieldsRecordUpdate {
location: Span,
},
UnusedType {
location: Span,
imported: bool,
name: String,
},
UnusedConstructor {
location: Span,
imported: bool,
name: String,
},
UnusedImportedValue {
location: Span,
name: String,
},
UnusedImportedModule {
location: Span,
name: String,
},
UnusedPrivateModuleConstant {
location: Span,
name: String,
},
UnusedPrivateFunction {
location: Span,
name: String,
},
UnusedVariable {
location: Span,
name: String,
},
}

View File

@ -0,0 +1,19 @@
use std::collections::HashMap;
use crate::ast::{ModuleKind, TypedModule, UntypedModule};
use super::{
error::{Error, Warning},
Module,
};
pub fn module(
// ids: &UniqueIdGenerator,
mut module: UntypedModule,
kind: ModuleKind,
package: &str,
modules: &HashMap<String, Module>,
warnings: &mut Vec<Warning>,
) -> Result<TypedModule, Error> {
todo!()
}

View File

@ -5,7 +5,7 @@ pub type Datum {
}
pub type Redeemer {
Buy,
Buy
Sell
}