conlang: Update type checker
- cl-typeck: Add modules, intrinsic types, unify definition ids - cl-ast: make attribute lists `Default` - cl-structures: Add functions to iterate through a pool - cl-repl: Create an example REPL for the type checker
This commit is contained in:
parent
614d20ea2c
commit
4a52d2bc6a
@ -37,7 +37,7 @@ pub struct File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Metadata decorators
|
// Metadata decorators
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct Attrs {
|
pub struct Attrs {
|
||||||
pub meta: Vec<Meta>,
|
pub meta: Vec<Meta>,
|
||||||
}
|
}
|
||||||
|
@ -20,3 +20,4 @@ argh = "0.1.12"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
cl-structures = { path = "../cl-structures" }
|
cl-structures = { path = "../cl-structures" }
|
||||||
|
cl-typeck = { path = "../cl-typeck" }
|
||||||
|
109
cl-repl/examples/typeck.rs
Normal file
109
cl-repl/examples/typeck.rs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
use cl_lexer::Lexer;
|
||||||
|
use cl_parser::Parser;
|
||||||
|
use cl_repl::repline::{error::Error as RlError, Repline};
|
||||||
|
use cl_typeck::{name_collector::NameCollector, project::Project};
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut prj = Project::default();
|
||||||
|
let mut tcol = NameCollector::new(&mut prj);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"--- {} v{} 💪🦈 ---",
|
||||||
|
env!("CARGO_BIN_NAME"),
|
||||||
|
env!("CARGO_PKG_VERSION"),
|
||||||
|
);
|
||||||
|
|
||||||
|
read_and(
|
||||||
|
"\x1b[33m",
|
||||||
|
"cl>",
|
||||||
|
"? >",
|
||||||
|
|line| -> Result<_, Box<dyn Error>> {
|
||||||
|
if line.trim_start().is_empty() {
|
||||||
|
query(&tcol)?;
|
||||||
|
return Ok(Response::Deny);
|
||||||
|
}
|
||||||
|
let mut parser = Parser::new(Lexer::new(line));
|
||||||
|
let code = match parser.file() {
|
||||||
|
Ok(code) => code,
|
||||||
|
Err(e) => Err(e)?,
|
||||||
|
};
|
||||||
|
tcol.file(&code)?;
|
||||||
|
Ok(Response::Accept)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Response {
|
||||||
|
Accept,
|
||||||
|
Deny,
|
||||||
|
Break,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_and(
|
||||||
|
color: &str,
|
||||||
|
begin: &str,
|
||||||
|
again: &str,
|
||||||
|
mut f: impl FnMut(&str) -> Result<Response, Box<dyn Error>>,
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut rl = Repline::new(color, begin, again);
|
||||||
|
loop {
|
||||||
|
let line = match rl.read() {
|
||||||
|
Err(RlError::CtrlC(_)) => break,
|
||||||
|
Err(RlError::CtrlD(line)) => {
|
||||||
|
rl.deny();
|
||||||
|
line
|
||||||
|
}
|
||||||
|
Ok(line) => line,
|
||||||
|
Err(e) => Err(e)?,
|
||||||
|
};
|
||||||
|
print!("\x1b[G\x1b[J");
|
||||||
|
match f(&line) {
|
||||||
|
Ok(Response::Accept) => rl.accept(),
|
||||||
|
Ok(Response::Deny) => rl.deny(),
|
||||||
|
Ok(Response::Break) => break,
|
||||||
|
Err(e) => print!("\x1b[40G\x1bJ\x1b[91m{e}\x1b[0m"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query(prj: &Project) -> Result<(), Box<dyn Error>> {
|
||||||
|
use cl_typeck::{
|
||||||
|
definition::{Def, DefKind},
|
||||||
|
type_kind::TypeKind,
|
||||||
|
};
|
||||||
|
read_and("\x1b[35m", "qy>", "? >", |line| {
|
||||||
|
if line.trim_start().is_empty() {
|
||||||
|
return Ok(Response::Break);
|
||||||
|
}
|
||||||
|
match line {
|
||||||
|
"$all\n" => println!("{prj:#?}"),
|
||||||
|
_ => {
|
||||||
|
// parse it as a path, and convert the path into a borrowed path
|
||||||
|
let path = Parser::new(Lexer::new(line)).path()?;
|
||||||
|
|
||||||
|
let Some((type_id, path)) = prj.get_type((&path).into(), prj.module_root) else {
|
||||||
|
return Ok(Response::Deny);
|
||||||
|
};
|
||||||
|
let Def { name, vis, meta: _, kind, source: _, module } = &prj[type_id];
|
||||||
|
match (kind, prj.get_value(path, type_id)) {
|
||||||
|
(_, Some((val, path))) => {
|
||||||
|
println!("value {}; {path}\n{:#?}", usize::from(val), prj[val])
|
||||||
|
}
|
||||||
|
(DefKind::Type(TypeKind::Module), None) => println!(
|
||||||
|
"{vis}mod \"{name}\" (#{}); {path}\n{:#?}",
|
||||||
|
usize::from(type_id),
|
||||||
|
module
|
||||||
|
),
|
||||||
|
(_, None) => println!(
|
||||||
|
"type {name}(#{}); {path}\n{:#?}",
|
||||||
|
usize::from(type_id),
|
||||||
|
prj.pool[type_id]
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Response::Accept)
|
||||||
|
})
|
||||||
|
}
|
@ -89,6 +89,13 @@ impl<T, ID: InternKey> Pool<T, ID> {
|
|||||||
self.pool.get_mut(index.get())
|
self.pool.get_mut(index.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||||
|
self.pool.iter()
|
||||||
|
}
|
||||||
|
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
||||||
|
self.pool.iter_mut()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, value: T) -> ID {
|
pub fn insert(&mut self, value: T) -> ID {
|
||||||
let id = self.pool.len();
|
let id = self.pool.len();
|
||||||
self.pool.push(value);
|
self.pool.push(value);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! # The Conlang Type Checker
|
//! # The Conlang Type Checker
|
||||||
//!
|
//!
|
||||||
//! As a statically typed language, Conlang requires a robust type checker to enforce correctness.
|
//! As a statically typed language, Conlang requires a robust type checker to enforce correctness.
|
||||||
|
#![feature(debug_closure_helpers)]
|
||||||
#![warn(clippy::all)]
|
#![warn(clippy::all)]
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -19,50 +19,161 @@ pub mod key {
|
|||||||
|
|
||||||
// define the index types
|
// define the index types
|
||||||
make_intern_key! {
|
make_intern_key! {
|
||||||
/// Uniquely represents a TypeDef in the TypeDef [Pool]
|
/// Uniquely represents a [Def][1] in the [Def][1] [Pool]
|
||||||
TypeID,
|
///
|
||||||
/// Uniquely represents a ValueDef in the ValueDef [Pool]
|
/// [1]: crate::definition::Def
|
||||||
ValueID,
|
DefID,
|
||||||
/// Uniquely represents a Module in the Module [Pool]
|
|
||||||
ModuleID,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod typedef {
|
pub mod definition {
|
||||||
//! A TypeDef represents an item in the Type Namespace (a component of a
|
use crate::{key::DefID, module::Module, type_kind::TypeKind, value_kind::ValueKind};
|
||||||
//! [Project](crate::project::Project)).
|
use cl_ast::{format::FmtPretty, Item, Meta, Visibility};
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
use crate::key::{TypeID, ValueID};
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
use cl_ast::{Item, Visibility};
|
pub struct Def {
|
||||||
|
|
||||||
/// A TypeDef represents an item in the Type Namespace (a component of a
|
|
||||||
/// [Project](crate::project::Project)).
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub struct TypeDef {
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// The expanded form of the definition, with all fields properly typed.
|
pub vis: Visibility,
|
||||||
/// This is filled in once all types are been enumerated.
|
pub meta: Vec<Meta>,
|
||||||
pub kind: Option<TypeKind>,
|
pub kind: DefKind,
|
||||||
pub definition: Item,
|
pub source: Option<Item>,
|
||||||
pub associated_values: Vec<ValueID>,
|
pub module: Module,
|
||||||
// TODO: Generic type parameters
|
}
|
||||||
|
|
||||||
|
impl Default for Def {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
name: Default::default(),
|
||||||
|
vis: Default::default(),
|
||||||
|
meta: Default::default(),
|
||||||
|
kind: DefKind::Type(TypeKind::Module),
|
||||||
|
source: Default::default(),
|
||||||
|
module: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Def {
|
||||||
|
pub fn new_module(
|
||||||
|
name: String,
|
||||||
|
vis: Visibility,
|
||||||
|
meta: Vec<Meta>,
|
||||||
|
parent: Option<DefID>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
vis,
|
||||||
|
meta,
|
||||||
|
kind: DefKind::Type(TypeKind::Module),
|
||||||
|
source: None,
|
||||||
|
module: Module { parent, ..Default::default() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Def {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let Self { name, vis, meta, kind, source, module } = self;
|
||||||
|
f.debug_struct("Def")
|
||||||
|
.field("name", &name)
|
||||||
|
.field("vis", &vis)
|
||||||
|
.field_with("meta", |f| write!(f, "{meta:?}"))
|
||||||
|
.field("kind", &kind)
|
||||||
|
.field_with("source", |f| match source {
|
||||||
|
Some(item) => write!(f.pretty(), "{{\n{item}\n}}"),
|
||||||
|
None => todo!(),
|
||||||
|
})
|
||||||
|
.field("module", &module)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum DefKind {
|
||||||
|
/// A type, such as a ``
|
||||||
|
Type(TypeKind),
|
||||||
|
/// A value, such as a `const`, `static`, or `fn`
|
||||||
|
Value(ValueKind),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefKind {
|
||||||
|
pub fn is_type(&self) -> bool {
|
||||||
|
matches!(self, Self::Type(_))
|
||||||
|
}
|
||||||
|
pub fn ty(&self) -> Option<&TypeKind> {
|
||||||
|
match self {
|
||||||
|
DefKind::Type(t) => Some(t),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn is_value(&self) -> bool {
|
||||||
|
matches!(self, Self::Value(_))
|
||||||
|
}
|
||||||
|
pub fn value(&self) -> Option<&ValueKind> {
|
||||||
|
match self {
|
||||||
|
DefKind::Value(v) => Some(v),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod type_kind {
|
||||||
|
//! A [TypeKind] represents an item in the Type Namespace
|
||||||
|
//! (a component of a [Project](crate::project::Project)).
|
||||||
|
|
||||||
|
use cl_ast::Visibility;
|
||||||
|
use std::{fmt::Debug, str::FromStr};
|
||||||
|
|
||||||
|
use crate::key::DefID;
|
||||||
|
|
||||||
|
/// The kind of a type
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum TypeKind {
|
pub enum TypeKind {
|
||||||
|
/// A type which has not yet been resolved
|
||||||
|
Undecided,
|
||||||
|
/// An alias for an already-defined type
|
||||||
|
Alias(Option<DefID>),
|
||||||
/// A primitive type, built-in to the compiler
|
/// A primitive type, built-in to the compiler
|
||||||
Intrinsic(Intrinsic),
|
Intrinsic(Intrinsic),
|
||||||
/// A user-defined structural product type
|
/// A user-defined abstract data type
|
||||||
Struct(Vec<(String, Visibility, TypeID)>),
|
Adt(Adt),
|
||||||
/// A user-defined union-like enum type
|
/// A reference to an already-defined type: &T
|
||||||
Enum(Vec<(String, TypeID)>),
|
Ref(DefID),
|
||||||
/// An alias for an already-defined type
|
/// A contiguous view of dynamically sized memory
|
||||||
Alias(TypeID),
|
Slice(DefID),
|
||||||
|
/// A function pointer which accepts multiple inputs and produces an output
|
||||||
|
FnPtr { args: Vec<DefID>, rety: DefID },
|
||||||
/// The unit type
|
/// The unit type
|
||||||
Empty,
|
Empty,
|
||||||
|
/// The never type
|
||||||
|
Never,
|
||||||
/// The Self type
|
/// The Self type
|
||||||
SelfTy,
|
SelfTy,
|
||||||
// TODO: union types, tuples, tuple structs maybe?
|
/// An untyped module
|
||||||
|
Module,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A user-defined Abstract Data Type
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Adt {
|
||||||
|
/// A union-like enum type
|
||||||
|
Enum(Vec<(String, DefID)>),
|
||||||
|
CLikeEnum(Vec<(String, u128)>),
|
||||||
|
/// An enum with no fields, which can never be constructed
|
||||||
|
FieldlessEnum,
|
||||||
|
|
||||||
|
/// A structural product type with named members
|
||||||
|
Struct(Vec<(String, Visibility, DefID)>),
|
||||||
|
/// A structural product type with unnamed members
|
||||||
|
TupleStruct(Vec<(Visibility, DefID)>),
|
||||||
|
/// A structural product type of neither named nor unnamed members
|
||||||
|
UnitStruct,
|
||||||
|
|
||||||
|
/// A choose your own undefined behavior type
|
||||||
|
/// TODO: should unions be a language feature?
|
||||||
|
Union(Vec<(String, DefID)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The set of compiler-intrinsic types.
|
/// The set of compiler-intrinsic types.
|
||||||
@ -70,37 +181,70 @@ pub mod typedef {
|
|||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Intrinsic {
|
pub enum Intrinsic {
|
||||||
/// A 32-bit two's complement integer
|
/// An 8-bit signed integer: `#[intrinsic = "i8"]`
|
||||||
i32,
|
I8,
|
||||||
/// A 32-bit unsigned integer
|
/// A 16-bit signed integer: `#[intrinsic = "i16"]`
|
||||||
u32,
|
I16,
|
||||||
/// A boolean (`true` or `false`)
|
/// A 32-bit signed integer: `#[intrinsic = "i32"]`
|
||||||
bool,
|
I32,
|
||||||
|
/// A 64-bit signed integer: `#[intrinsic = "i32"]`
|
||||||
|
I64,
|
||||||
|
// /// A 128-bit signed integer: `#[intrinsic = "i32"]`
|
||||||
|
// I128,
|
||||||
|
/// An 8-bit unsigned integer: `#[intrinsic = "u8"]`
|
||||||
|
U8,
|
||||||
|
/// A 16-bit unsigned integer: `#[intrinsic = "u16"]`
|
||||||
|
U16,
|
||||||
|
/// A 32-bit unsigned integer: `#[intrinsic = "u32"]`
|
||||||
|
U32,
|
||||||
|
/// A 64-bit unsigned integer: `#[intrinsic = "u64"]`
|
||||||
|
U64,
|
||||||
|
// /// A 128-bit unsigned integer: `#[intrinsic = "u128"]`
|
||||||
|
// U128,
|
||||||
|
/// A boolean (`true` or `false`): `#[intrinsic = "bool"]`
|
||||||
|
Bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Intrinsic {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(match s {
|
||||||
|
"i8" => Intrinsic::I8,
|
||||||
|
"i16" => Intrinsic::I16,
|
||||||
|
"i32" => Intrinsic::I32,
|
||||||
|
"i64" => Intrinsic::I64,
|
||||||
|
"u8" => Intrinsic::U8,
|
||||||
|
"u16" => Intrinsic::U16,
|
||||||
|
"u32" => Intrinsic::U32,
|
||||||
|
"u64" => Intrinsic::U64,
|
||||||
|
"bool" => Intrinsic::Bool,
|
||||||
|
_ => Err(())?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Float {
|
||||||
|
F32 = 0x20,
|
||||||
|
F64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod valdef {
|
pub mod value_kind {
|
||||||
//! A [ValueDef] represents an item in the Value Namespace (a component of a
|
//! A [ValueKind] represents an item in the Value Namespace
|
||||||
//! [Project](crate::project::Project)).
|
//! (a component of a [Project](crate::project::Project)).
|
||||||
|
|
||||||
use crate::typeref::TypeRef;
|
use crate::typeref::TypeRef;
|
||||||
use cl_ast::{Block, Item};
|
use cl_ast::Block;
|
||||||
|
|
||||||
/// A [ValueDef] represents an item in the Value Namespace (a component of a
|
|
||||||
/// [Project](crate::project::Project)).
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub struct ValueDef {
|
|
||||||
pub name: String,
|
|
||||||
/// The expanded form of the definition, with all fields properly typed
|
|
||||||
pub kind: Option<ValueKind>,
|
|
||||||
pub definition: Item,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ValueKind {
|
pub enum ValueKind {
|
||||||
|
Undecided,
|
||||||
Const(TypeRef),
|
Const(TypeRef),
|
||||||
Static(TypeRef),
|
Static(TypeRef),
|
||||||
Fn {
|
Fn {
|
||||||
|
// TODO: Store the variable bindings here!
|
||||||
args: Vec<TypeRef>,
|
args: Vec<TypeRef>,
|
||||||
rety: TypeRef,
|
rety: TypeRef,
|
||||||
body: Block,
|
body: Block,
|
||||||
@ -111,57 +255,532 @@ pub mod valdef {
|
|||||||
pub mod module {
|
pub mod module {
|
||||||
//! A [Module] is a node in the Module Tree (a component of a
|
//! A [Module] is a node in the Module Tree (a component of a
|
||||||
//! [Project](crate::project::Project))
|
//! [Project](crate::project::Project))
|
||||||
use crate::key::{ModuleID, TypeID, ValueID};
|
use crate::key::DefID;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// A [Module] is a node in the Module Tree (a component of a
|
/// A [Module] is a node in the Module Tree (a component of a
|
||||||
/// [Project](crate::project::Project)).
|
/// [Project](crate::project::Project)).
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub parent: Option<ModuleID>,
|
pub parent: Option<DefID>,
|
||||||
pub types: HashMap<String, TypeID>,
|
pub types: HashMap<String, DefID>,
|
||||||
pub values: HashMap<String, ValueID>,
|
pub values: HashMap<String, DefID>,
|
||||||
pub submodules: HashMap<String, ModuleID>,
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
pub fn new(parent: DefID) -> Self {
|
||||||
|
Self { parent: Some(parent), ..Default::default() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod path {
|
||||||
|
use cl_ast::{Path as AstPath, PathPart};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Path<'p> {
|
||||||
|
pub absolute: bool,
|
||||||
|
pub parts: &'p [PathPart],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p> Path<'p> {
|
||||||
|
pub fn new(path: &'p AstPath) -> Self {
|
||||||
|
let AstPath { absolute, parts } = path;
|
||||||
|
Self { absolute: *absolute, parts }
|
||||||
|
}
|
||||||
|
pub fn relative(self) -> Self {
|
||||||
|
Self { absolute: false, ..self }
|
||||||
|
}
|
||||||
|
pub fn pop_front(self) -> Option<Self> {
|
||||||
|
let Self { absolute, parts } = self;
|
||||||
|
Some(Self { absolute, parts: parts.get(1..)? })
|
||||||
|
}
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.parts.is_empty()
|
||||||
|
}
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.parts.len()
|
||||||
|
}
|
||||||
|
pub fn front(&self) -> Option<&PathPart> {
|
||||||
|
self.parts.first()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p> From<&'p AstPath> for Path<'p> {
|
||||||
|
fn from(value: &'p AstPath) -> Self {
|
||||||
|
Self::new(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for Path<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
const SEPARATOR: &str = "::";
|
||||||
|
let Self { absolute, parts } = self;
|
||||||
|
if *absolute {
|
||||||
|
write!(f, "{SEPARATOR}")?
|
||||||
|
}
|
||||||
|
for (idx, part) in parts.iter().enumerate() {
|
||||||
|
write!(f, "{}{part}", if idx > 0 { SEPARATOR } else { "" })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod project {
|
pub mod project {
|
||||||
|
use crate::{
|
||||||
|
definition::{Def, DefKind},
|
||||||
|
key::DefID,
|
||||||
|
path::Path,
|
||||||
|
type_kind::TypeKind,
|
||||||
|
};
|
||||||
|
use cl_ast::{Identifier, PathPart, Visibility};
|
||||||
use cl_structures::intern_pool::Pool;
|
use cl_structures::intern_pool::Pool;
|
||||||
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Project {
|
||||||
|
pub pool: Pool<Def, DefID>,
|
||||||
|
pub module_root: DefID,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Project {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for Project {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut pool = Pool::default();
|
||||||
|
let module_root = pool.insert(Def::default());
|
||||||
|
// Insert the Never(!) type
|
||||||
|
let never = pool.insert(Def {
|
||||||
|
name: String::from("!"),
|
||||||
|
vis: Visibility::Public,
|
||||||
|
kind: DefKind::Type(TypeKind::Never),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
pool[module_root]
|
||||||
|
.module
|
||||||
|
.types
|
||||||
|
.insert(String::from("!"), never);
|
||||||
|
Self { pool, module_root }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Project {
|
||||||
|
pub fn parent_of(&self, module: DefID) -> Option<DefID> {
|
||||||
|
self[module].module.parent
|
||||||
|
}
|
||||||
|
pub fn root_of(&self, module: DefID) -> DefID {
|
||||||
|
match self.parent_of(module) {
|
||||||
|
Some(module) => self.root_of(module),
|
||||||
|
None => module,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Resolves a path within a module tree, finding the innermost module.
|
||||||
|
/// Returns the remaining path parts.
|
||||||
|
pub fn get_type<'a>(&self, path: Path<'a>, within: DefID) -> Option<(DefID, Path<'a>)> {
|
||||||
|
// TODO: Cache module lookups
|
||||||
|
if path.absolute {
|
||||||
|
self.get_type(path.relative(), self.root_of(within))
|
||||||
|
} else if let Some(front) = path.front() {
|
||||||
|
let module = &self[within].module;
|
||||||
|
match front {
|
||||||
|
PathPart::SelfKw => self.get_type(path.pop_front()?, within),
|
||||||
|
PathPart::SuperKw => self.get_type(path.pop_front()?, module.parent?),
|
||||||
|
PathPart::Ident(Identifier(name)) => match module.types.get(name) {
|
||||||
|
Some(&submodule) => self.get_type(path.pop_front()?, submodule),
|
||||||
|
None => Some((within, path)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Some((within, path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_value<'a>(&self, path: Path<'a>, within: DefID) -> Option<(DefID, Path<'a>)> {
|
||||||
|
match path.front()? {
|
||||||
|
PathPart::Ident(Identifier(name)) => Some((
|
||||||
|
self[within].module.values.get(name).copied()?,
|
||||||
|
path.pop_front()?,
|
||||||
|
)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub fn insert_type(&mut self, name: String, value: Def, parent: DefID) -> Option<DefID> {
|
||||||
|
let id = self.pool.insert(value);
|
||||||
|
self[parent].module.types.insert(name, id)
|
||||||
|
}
|
||||||
|
#[rustfmt::skip]
|
||||||
|
pub fn insert_value(&mut self, name: String, value: Def, parent: DefID) -> Option<DefID> {
|
||||||
|
let id = self.pool.insert(value);
|
||||||
|
self[parent].module.values.insert(name, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implements [Index] and [IndexMut] for [Project]: `self.table[ID] -> Definition`
|
||||||
|
macro_rules! impl_index {
|
||||||
|
($(self.$table:ident[$idx:ty] -> $out:ty),*$(,)?) => {$(
|
||||||
|
impl Index<$idx> for Project {
|
||||||
|
type Output = $out;
|
||||||
|
fn index(&self, index: $idx) -> &Self::Output {
|
||||||
|
&self.$table[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl IndexMut<$idx> for Project {
|
||||||
|
fn index_mut(&mut self, index: $idx) -> &mut Self::Output {
|
||||||
|
&mut self.$table[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*};
|
||||||
|
}
|
||||||
|
impl_index! {
|
||||||
|
self.pool[DefID] -> Def,
|
||||||
|
// self.types[TypeID] -> TypeDef,
|
||||||
|
// self.values[ValueID] -> ValueDef,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod name_collector {
|
||||||
|
//! Performs step 1 of type checking: Collecting all the names of things into [Module] units
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
key::{ModuleID, TypeID, ValueID},
|
definition::{Def, DefKind},
|
||||||
module::Module,
|
key,
|
||||||
typedef::TypeDef,
|
project::Project,
|
||||||
valdef::ValueDef,
|
type_kind::{Adt, TypeKind},
|
||||||
|
value_kind::ValueKind,
|
||||||
};
|
};
|
||||||
|
use cl_ast::*;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
/// Collects types for future use
|
||||||
pub struct Project {
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub types: Pool<TypeDef, TypeID>,
|
pub struct NameCollector<'prj> {
|
||||||
pub values: Pool<ValueDef, ValueID>,
|
/// A stack of the current modules
|
||||||
pub modules: Pool<Module, ModuleID>,
|
pub mod_stack: Vec<key::DefID>,
|
||||||
|
/// The [Project], the type checker and resolver's central data store
|
||||||
|
pub project: &'prj mut Project,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'prj> NameCollector<'prj> {
|
||||||
|
pub fn new(project: &'prj mut Project) -> Self {
|
||||||
|
// create a root module
|
||||||
|
Self { mod_stack: vec![project.module_root], project }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the currently traversed parent module
|
||||||
|
pub fn parent(&self) -> Option<key::DefID> {
|
||||||
|
self.mod_stack.last().copied()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for NameCollector<'_> {
|
||||||
|
type Target = Project;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.project
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl DerefMut for NameCollector<'_> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.project
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NameCollector<'_> {
|
||||||
|
pub fn file(&mut self, f: &File) -> Result<(), &'static str> {
|
||||||
|
let parent = self.parent().ok_or("No parent to add item to")?;
|
||||||
|
|
||||||
|
for item in &f.items {
|
||||||
|
let def = match &item.kind {
|
||||||
|
// modules
|
||||||
|
// types
|
||||||
|
ItemKind::Module(_) => {
|
||||||
|
self.module(item)?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ItemKind::Enum(_) => Some(self.ty_enum(item)?),
|
||||||
|
ItemKind::Alias(_) => Some(self.ty_alias(item)?),
|
||||||
|
ItemKind::Struct(_) => Some(self.ty_struct(item)?),
|
||||||
|
// values processed by the value collector
|
||||||
|
ItemKind::Const(_) => Some(self.val_const(item)?),
|
||||||
|
ItemKind::Static(_) => Some(self.val_static(item)?),
|
||||||
|
ItemKind::Function(_) => Some(self.val_function(item)?),
|
||||||
|
ItemKind::Impl(_) => None,
|
||||||
|
};
|
||||||
|
let Some(def) = def else { continue };
|
||||||
|
match def.kind {
|
||||||
|
DefKind::Type(_) => {
|
||||||
|
if let Some(v) = self.insert_type(def.name.clone(), def, parent) {
|
||||||
|
panic!("Redefinition of type {} ({v:?})!", self[v].name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefKind::Value(_) => {
|
||||||
|
if let Some(v) = self.insert_value(def.name.clone(), def, parent) {
|
||||||
|
panic!("Redefinition of value {} ({v:?})!", self[v].name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects a [Module]
|
||||||
|
pub fn module(&mut self, m: &Item) -> Result<(), &'static str> {
|
||||||
|
let Item { kind: ItemKind::Module(Module { name, kind }), vis, attrs, .. } = m else {
|
||||||
|
Err("module called on Item which was not an ItemKind::Module")?
|
||||||
|
};
|
||||||
|
let ModuleKind::Inline(kind) = kind else {
|
||||||
|
Err("Out-of-line modules not yet supported")?
|
||||||
|
};
|
||||||
|
let parent = self.parent().ok_or("No parent to add module to")?;
|
||||||
|
|
||||||
|
let module = self.pool.insert(Def::new_module(
|
||||||
|
name.0.clone(),
|
||||||
|
*vis,
|
||||||
|
attrs.meta.clone(),
|
||||||
|
Some(parent),
|
||||||
|
));
|
||||||
|
|
||||||
|
self[parent]
|
||||||
|
.module
|
||||||
|
.types
|
||||||
|
.insert(name.0.clone(), module)
|
||||||
|
.is_some()
|
||||||
|
.then(|| panic!("Error: redefinition of module {name}"));
|
||||||
|
|
||||||
|
self.mod_stack.push(module);
|
||||||
|
let out = self.file(kind);
|
||||||
|
self.mod_stack.pop();
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Type collection
|
||||||
|
impl NameCollector<'_> {
|
||||||
|
/// Collects an [Item] of type [ItemKind::Enum]
|
||||||
|
pub fn ty_enum(&mut self, item: &Item) -> Result<Def, &'static str> {
|
||||||
|
let Item { kind: ItemKind::Enum(Enum { name, kind }), vis, attrs, .. } = item else {
|
||||||
|
Err("Enum called on item which was not ItemKind::Enum")?
|
||||||
|
};
|
||||||
|
let kind = match kind {
|
||||||
|
EnumKind::NoVariants => DefKind::Type(TypeKind::Adt(Adt::FieldlessEnum)),
|
||||||
|
EnumKind::Variants(_) => DefKind::Type(TypeKind::Undecided),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Def {
|
||||||
|
name: name.0.clone(),
|
||||||
|
vis: *vis,
|
||||||
|
meta: attrs.meta.clone(),
|
||||||
|
kind,
|
||||||
|
source: Some(item.clone()),
|
||||||
|
module: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects an [Item] of type [ItemKind::Alias]
|
||||||
|
pub fn ty_alias(&mut self, item: &Item) -> Result<Def, &'static str> {
|
||||||
|
let Item { kind: ItemKind::Alias(Alias { to: name, from }), vis, attrs, .. } = item
|
||||||
|
else {
|
||||||
|
Err("Alias called on Item which was not ItemKind::Alias")?
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut kind = match from {
|
||||||
|
Some(_) => DefKind::Type(TypeKind::Undecided),
|
||||||
|
None => DefKind::Type(TypeKind::Alias(None)),
|
||||||
|
};
|
||||||
|
|
||||||
|
for meta in &attrs.meta {
|
||||||
|
let Meta { name: meta_name, kind: meta_kind } = meta;
|
||||||
|
match (meta_name.0.as_str(), meta_kind) {
|
||||||
|
("intrinsic", MetaKind::Equals(Literal::String(intrinsic))) => {
|
||||||
|
kind = DefKind::Type(TypeKind::Intrinsic(
|
||||||
|
intrinsic.parse().map_err(|_| "unknown intrinsic type")?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
("intrinsic", MetaKind::Plain) => {
|
||||||
|
kind = DefKind::Type(TypeKind::Intrinsic(
|
||||||
|
name.0.parse().map_err(|_| "Unknown intrinsic type")?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Def {
|
||||||
|
name: name.0.clone(),
|
||||||
|
vis: *vis,
|
||||||
|
meta: attrs.meta.clone(),
|
||||||
|
kind,
|
||||||
|
source: Some(item.clone()),
|
||||||
|
module: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Collects an [Item] of type [ItemKind::Struct]
|
||||||
|
pub fn ty_struct(&mut self, item: &Item) -> Result<Def, &'static str> {
|
||||||
|
let Item { kind: ItemKind::Struct(Struct { name, kind }), vis, attrs, .. } = item
|
||||||
|
else {
|
||||||
|
Err("Struct called on item which was not ItemKind::Struct")?
|
||||||
|
};
|
||||||
|
let kind = match kind {
|
||||||
|
StructKind::Empty => DefKind::Type(TypeKind::Adt(Adt::UnitStruct)),
|
||||||
|
StructKind::Tuple(_) => DefKind::Type(TypeKind::Undecided),
|
||||||
|
StructKind::Struct(_) => DefKind::Type(TypeKind::Undecided),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Def {
|
||||||
|
name: name.0.clone(),
|
||||||
|
vis: *vis,
|
||||||
|
meta: attrs.meta.clone(),
|
||||||
|
kind,
|
||||||
|
source: Some(item.clone()),
|
||||||
|
module: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Value collection
|
||||||
|
impl NameCollector<'_> {
|
||||||
|
pub fn val_const(&mut self, item: &Item) -> Result<Def, &'static str> {
|
||||||
|
let Item { kind: ItemKind::Const(Const { name, .. }), vis, attrs, .. } = item else {
|
||||||
|
Err("Const called on Item which was not ItemKind::Const")?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Def {
|
||||||
|
name: name.0.clone(),
|
||||||
|
vis: *vis,
|
||||||
|
meta: attrs.meta.clone(),
|
||||||
|
kind: DefKind::Value(ValueKind::Undecided),
|
||||||
|
source: Some(item.clone()),
|
||||||
|
module: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn val_static(&mut self, item: &Item) -> Result<Def, &'static str> {
|
||||||
|
let Item { kind: ItemKind::Static(Static { name, .. }), vis, attrs, .. } = item else {
|
||||||
|
Err("Static called on Item which was not ItemKind::Static")?
|
||||||
|
};
|
||||||
|
Ok(Def {
|
||||||
|
name: name.0.clone(),
|
||||||
|
vis: *vis,
|
||||||
|
meta: attrs.meta.clone(),
|
||||||
|
kind: DefKind::Type(TypeKind::Undecided),
|
||||||
|
source: Some(item.clone()),
|
||||||
|
module: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn val_function(&mut self, item: &Item) -> Result<Def, &'static str> {
|
||||||
|
// TODO: treat function bodies like modules with internal items
|
||||||
|
let Item { kind: ItemKind::Function(Function { name, .. }), vis, attrs, .. } = item
|
||||||
|
else {
|
||||||
|
Err("val_function called on Item which was not ItemKind::Function")?
|
||||||
|
};
|
||||||
|
Ok(Def {
|
||||||
|
name: name.0.clone(),
|
||||||
|
vis: *vis,
|
||||||
|
meta: attrs.meta.clone(),
|
||||||
|
kind: DefKind::Value(ValueKind::Undecided),
|
||||||
|
source: Some(item.clone()),
|
||||||
|
module: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod type_resolver {
|
||||||
|
//! Performs step 2 of type checking: Evaluating type definitions
|
||||||
|
#![allow(unused)]
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use cl_ast::*;
|
||||||
|
|
||||||
|
use crate::{definition::Def, key::DefID, project::Project};
|
||||||
|
|
||||||
|
pub struct TypeResolver<'prj> {
|
||||||
|
pub project: &'prj mut Project,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for TypeResolver<'_> {
|
||||||
|
type Target = Project;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.project
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl DerefMut for TypeResolver<'_> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.project
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeResolver<'_> {
|
||||||
|
pub fn resolve(&mut self) -> Result<bool, &str> {
|
||||||
|
#![allow(unused)]
|
||||||
|
for typedef in self.pool.iter_mut().filter(|v| v.kind.is_type()) {
|
||||||
|
let Def { name, vis, meta: attr, kind, source: Some(ref definition), module: _ } =
|
||||||
|
typedef
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
match &definition.kind {
|
||||||
|
ItemKind::Alias(Alias { to: _, from: Some(from) }) => match &from.kind {
|
||||||
|
TyKind::Never => todo!(),
|
||||||
|
TyKind::Empty => todo!(),
|
||||||
|
TyKind::SelfTy => todo!(),
|
||||||
|
TyKind::Path(_) => todo!(),
|
||||||
|
TyKind::Tuple(_) => todo!(),
|
||||||
|
TyKind::Ref(_) => todo!(),
|
||||||
|
TyKind::Fn(_) => todo!(),
|
||||||
|
},
|
||||||
|
ItemKind::Alias(_) => {}
|
||||||
|
ItemKind::Const(_) => todo!(),
|
||||||
|
ItemKind::Static(_) => todo!(),
|
||||||
|
ItemKind::Module(_) => todo!(),
|
||||||
|
ItemKind::Function(_) => {}
|
||||||
|
ItemKind::Struct(_) => {}
|
||||||
|
ItemKind::Enum(_) => {}
|
||||||
|
ItemKind::Impl(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type(&self, kind: &TyKind) -> Option<DefID> {
|
||||||
|
match kind {
|
||||||
|
TyKind::Never => todo!(),
|
||||||
|
TyKind::Empty => todo!(),
|
||||||
|
TyKind::SelfTy => todo!(),
|
||||||
|
TyKind::Path(_) => todo!(),
|
||||||
|
TyKind::Tuple(_) => todo!(),
|
||||||
|
TyKind::Ref(_) => todo!(),
|
||||||
|
TyKind::Fn(_) => todo!(),
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod typeref {
|
pub mod typeref {
|
||||||
//! Stores type and referencce info
|
//! Stores type and reference info
|
||||||
|
|
||||||
use crate::key::TypeID;
|
use crate::key::DefID;
|
||||||
|
|
||||||
/// The Type struct represents all valid types, and can be trivially equality-compared
|
/// The Type struct represents all valid types, and can be trivially equality-compared
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct TypeRef {
|
pub struct TypeRef {
|
||||||
/// You can only have a pointer chain 65535 pointers long.
|
/// You can only have a pointer chain 65535 pointers long.
|
||||||
ref_depth: u16,
|
ref_depth: u16,
|
||||||
/// Types can be [Generic](TKind::Generic) or [Concrete](TKind::Concrete)
|
/// Types can be [Generic](RefKind::Generic) or [Concrete](RefKind::Concrete)
|
||||||
kind: RefKind,
|
kind: RefKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Types can be [Generic](TKind::Generic) or [Concrete](TKind::Concrete)
|
/// Types can be [Generic](RefKind::Generic) or [Concrete](RefKind::Concrete)
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum RefKind {
|
pub enum RefKind {
|
||||||
/// A Concrete type has an associated [TypeDef](super::typedef::TypeDef)
|
/// A Concrete type has an associated [Def](super::definition::Def)
|
||||||
Concrete(TypeID),
|
Concrete(DefID),
|
||||||
/// A Generic type is a *locally unique* comparable value,
|
/// A Generic type is a *locally unique* comparable value,
|
||||||
/// valid only until the end of its typing context.
|
/// valid only until the end of its typing context.
|
||||||
/// This is usually the surrounding function.
|
/// This is usually the surrounding function.
|
||||||
@ -233,7 +852,58 @@ let rules: Hashmap<Operation, Vec<Rule>> {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
pub mod rule {
|
||||||
Potential solution:
|
use crate::{key::DefID, typeref::TypeRef};
|
||||||
Store reference to type field of each type expression in the AST
|
|
||||||
*/
|
pub struct Rule {
|
||||||
|
/// What is this Rule for?
|
||||||
|
pub operation: (),
|
||||||
|
/// What inputs does it take?
|
||||||
|
pub inputs: Vec<TypeRef>,
|
||||||
|
/// What output does it produce?
|
||||||
|
pub output: TypeRef,
|
||||||
|
/// Where did this rule come from?
|
||||||
|
pub through: Origin,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Genericize
|
||||||
|
pub enum Operation {
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Rem,
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
|
||||||
|
Deref,
|
||||||
|
Neg,
|
||||||
|
Not,
|
||||||
|
At,
|
||||||
|
Tilde,
|
||||||
|
|
||||||
|
Index,
|
||||||
|
|
||||||
|
If,
|
||||||
|
While,
|
||||||
|
For,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Origin {
|
||||||
|
/// This rule is built into the compiler
|
||||||
|
Intrinsic,
|
||||||
|
/// This rule is derived from an implementation on a type
|
||||||
|
Extrinsic(DefID),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod typeck {
|
||||||
|
#![allow(unused)]
|
||||||
|
use cl_ast::*;
|
||||||
|
|
||||||
|
pub struct Context {
|
||||||
|
rules: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
trait TypeCheck {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user