From c93d109ec3d52f9b79b758f060eabe0f978f7f96 Mon Sep 17 00:00:00 2001 From: Vincent Hanquez Date: Thu, 21 Dec 2023 11:50:51 +0800 Subject: [PATCH] core documentation --- werbolg-compile/src/code.rs | 19 +++++++++------- werbolg-core/src/basic.rs | 11 +++++++++ werbolg-core/src/id.rs | 31 +++++++++++++++++++++++-- werbolg-core/src/idvec.rs | 21 +++++++++++++++++ werbolg-core/src/ir.rs | 44 +++++++++++++++++++++++++++++++++++- werbolg-core/src/lib.rs | 3 +++ werbolg-core/src/location.rs | 11 +++++++++ 7 files changed, 129 insertions(+), 11 deletions(-) diff --git a/werbolg-compile/src/code.rs b/werbolg-compile/src/code.rs index ef815e2..016af09 100644 --- a/werbolg-compile/src/code.rs +++ b/werbolg-compile/src/code.rs @@ -1,6 +1,6 @@ use super::instructions::Instruction; use super::symbols::{IdVec, IdVecAfter}; -use werbolg_core::id::IdF; +use werbolg_core::id::{IdArith, IdF}; /// Instruction Address #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -15,7 +15,7 @@ impl Default for InstructionAddress { impl InstructionAddress { /// Increment the instruction address to the next instruction pub fn next(self) -> Self { - InstructionAddress::add(self, 1) + InstructionAddress::add(self, InstructionDiff(1)) } } @@ -35,19 +35,22 @@ impl IdF for InstructionAddress { fn remap(left: Self, right: Self) -> Self { Self(left.0 + right.0) } +} +impl IdArith for InstructionAddress { + type IdDiff = InstructionDiff; - fn add(left: Self, right: u32) -> Self { - Self(left.0.checked_add(right).expect("ID valid add")) + fn add(left: Self, right: InstructionDiff) -> Self { + Self(left.0.checked_add(right.0).expect("ID valid add")) } - fn diff(left: Self, right: Self) -> u32 { - left.0.checked_sub(right.0).expect("ID valid diff") + fn diff(left: Self, right: Self) -> InstructionDiff { + InstructionDiff(left.0.checked_sub(right.0).expect("ID valid diff")) } } impl core::ops::AddAssign for InstructionAddress { fn add_assign(&mut self, rhs: InstructionDiff) { - *self = InstructionAddress::add(*self, rhs.0) + *self = InstructionAddress::add(*self, rhs) } } @@ -55,7 +58,7 @@ impl core::ops::Sub for InstructionAddress { type Output = InstructionDiff; fn sub(self, rhs: Self) -> Self::Output { - InstructionDiff(InstructionAddress::diff(self, rhs)) + InstructionAddress::diff(self, rhs) } } diff --git a/werbolg-core/src/basic.rs b/werbolg-core/src/basic.rs index 44265ca..2925261 100644 --- a/werbolg-core/src/basic.rs +++ b/werbolg-core/src/basic.rs @@ -1,5 +1,9 @@ use alloc::{boxed::Box, string::String}; +/// An ident in the program +/// +/// Note that the ident can contains pretty much anything the frontend wants. +/// For example, Space or '::' could be inside the ident #[derive(Clone, PartialEq, Eq, Hash)] pub struct Ident(pub String); @@ -22,17 +26,24 @@ impl From for Ident { } impl Ident { + /// check if the Ident matches the string in parameter pub fn matches(&self, s: &str) -> bool { self.0 == s } } +/// Core Literal #[derive(Clone, Hash, PartialEq, Eq)] pub enum Literal { + /// Bool Bool(Box), + /// String String(Box), + /// Integral Number Number(Box), + /// Decimal Number Decimal(Box), + /// Bytes Bytes(Box<[u8]>), } diff --git a/werbolg-core/src/id.rs b/werbolg-core/src/id.rs index 2221359..6e26f35 100644 --- a/werbolg-core/src/id.rs +++ b/werbolg-core/src/id.rs @@ -1,16 +1,36 @@ +//! ID + +/// ID related trait pub trait IdF: core::fmt::Debug + core::hash::Hash + PartialEq + Eq + PartialOrd + Ord + Copy { + /// Id as an index fn as_index(self) -> usize; + /// Create an Id from a slice length fn from_slice_len(slice: &[T]) -> Self; + + /// Create an Id from a a collection length (usize) fn from_collection_len(len: usize) -> Self; + + /// Remap an index fn remap(left: Self, right: Self) -> Self; - fn add(left: Self, right: u32) -> Self; - fn diff(left: Self, right: Self) -> u32; +} + +/// ID Arithmetic related trait +pub trait IdArith: IdF { + /// Difference of Id + type IdDiff; + + /// Add a differential to an Id, and get the new Id + fn add(left: Self, right: Self::IdDiff) -> Self; + + /// Get the differential between two Ids + fn diff(left: Self, right: Self) -> Self::IdDiff; } macro_rules! define_id_remapper { ($constr:ident, $bt:ident, $n:literal, $c:expr) => { + /// Id #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct $constr($bt); @@ -30,6 +50,10 @@ macro_rules! define_id_remapper { fn remap(left: Self, right: Self) -> Self { Self(left.0 + right.0) } + } + + impl IdArith for $constr { + type IdDiff = $bt; fn add(left: Self, right: u32) -> Self { Self(left.0.checked_add(right).expect("ID valid add")) @@ -55,8 +79,11 @@ define_id_remapper!(NifId, u32, 32, 'N'); define_id_remapper!(GlobalId, u32, 32, 'G'); define_id_remapper!(InstructionAddress, u32, 32, '%'); +/// A general function id (NifId or FunId) #[derive(Clone, Copy, Debug)] pub enum ValueFun { + /// NIF ID Native(NifId), + /// Function ID Fun(FunId), } diff --git a/werbolg-core/src/idvec.rs b/werbolg-core/src/idvec.rs index 90513e5..5bc7ca1 100644 --- a/werbolg-core/src/idvec.rs +++ b/werbolg-core/src/idvec.rs @@ -1,7 +1,12 @@ +//! A Vector indexed by a specific ID + use super::id::IdF; use alloc::vec::Vec; use core::marker::PhantomData; +/// A Vector Indexed by a specific ID +/// +/// Note that it can be dereferenced using the array syntax `idec[id]` pub struct IdVec { vec: Vec, phantom: PhantomData, @@ -22,6 +27,7 @@ impl core::ops::IndexMut for IdVec { } impl IdVec { + /// Create a new empty IdVec pub fn new() -> Self { Self { vec: Vec::new(), @@ -29,6 +35,7 @@ impl IdVec { } } + /// Get the index pub fn get(&self, id: ID) -> Option<&T> { let idx = id.as_index(); if self.vec.len() > idx { @@ -38,20 +45,24 @@ impl IdVec { } } + /// Return the next Id that will be created on push pub fn next_id(&self) -> ID { ID::from_slice_len(&self.vec) } + /// Append a new element to this IdVec, and returns the Id associated pub fn push(&mut self, v: T) -> ID { let id = ID::from_slice_len(&self.vec); self.vec.push(v); id } + /// Create a mutable iterator for this IdVec pub fn iter_mut(&mut self) -> impl Iterator { self.vec.iter_mut() } + /// Create an reference Iterator for this IdVec, note that the Id is also given pub fn iter(&self) -> impl Iterator { self.vec .iter() @@ -59,6 +70,7 @@ impl IdVec { .map(|(i, t)| (ID::from_collection_len(i), t)) } + /// Create a value Iterator for this IdVec pub fn into_iter(self) -> impl Iterator { self.vec .into_iter() @@ -66,11 +78,14 @@ impl IdVec { .map(|(i, t)| (ID::from_collection_len(i), t)) } + /// Append a IdVecAfter to this IdVec pub fn concat(&mut self, after: &mut IdVecAfter) { assert!(self.vec.len() == after.ofs.as_index()); self.vec.append(&mut after.id_vec.vec) } + /// Consume the IdVec and create a new IdVec using the function 'f' to map + /// all the elements T of this IdVec. pub fn remap(self, f: F) -> IdVec where F: Fn(T) -> U, @@ -84,12 +99,15 @@ impl IdVec { } } +/// An IdVec that doesn't starts at Id=0 with the explicit goal to +/// append the underlying IdVec to another IdVec pub struct IdVecAfter { id_vec: IdVec, ofs: ID, } impl IdVecAfter { + /// Create a new IdVec starting at ID=first_id pub fn new(first_id: ID) -> Self { Self { id_vec: IdVec::new(), @@ -97,6 +115,7 @@ impl IdVecAfter { } } + /// Create an offset IdVec from another IdVec pub fn from_idvec(id_vec: IdVec, first_id: ID) -> Self { Self { id_vec, @@ -104,12 +123,14 @@ impl IdVecAfter { } } + /// Append to this IdVecAfter a value T and returns its Id pub fn push(&mut self, v: T) -> ID { let id = self.id_vec.push(v); let new_id = ID::remap(id, self.ofs); new_id } + /// Remap all element of this IdVec in place pub fn remap(&mut self, f: F) where F: Fn(&mut T) -> (), diff --git a/werbolg-core/src/ir.rs b/werbolg-core/src/ir.rs index cc05146..1d4de5a 100644 --- a/werbolg-core/src/ir.rs +++ b/werbolg-core/src/ir.rs @@ -5,6 +5,9 @@ //! //! The AST try the terminology of Rust AST, but offer less / more flexibility at time, //! as this is made for other languages to target also. +//! +//! The example in documentation use rust syntax, but the syntax supported is only defined +//! by the frontend, not in the core. use super::basic::*; use super::location::*; @@ -14,6 +17,7 @@ use alloc::{boxed::Box, vec::Vec}; /// AST for a module / source code unit #[derive(Clone, Debug)] pub struct Module { + /// Statement in this module pub statements: Vec, } @@ -21,14 +25,19 @@ pub struct Module { /// /// Current known types are: /// +/// * Use statement for namespace manipulation /// * Function definition /// * Struct definition /// * Naked expression #[derive(Clone, Debug)] pub enum Statement { + /// Use statement Use(Use), + /// Function definition Function(Span, FunDef), + /// Struct definition Struct(Span, StructDef), + /// A naked Expression Expr(Expr), } @@ -46,7 +55,9 @@ pub struct Use { /// AST for symbol privacy (public / private) #[derive(Clone, Copy, Debug)] pub enum Privacy { + /// Public privacy allow to define a function that will be reachable by other modules Public, + /// Private privacy keeps the function not reachable to other modules Private, } @@ -60,9 +71,13 @@ pub enum Privacy { /// #[derive(Clone, Debug)] pub struct FunDef { + /// The privacy associated with this function definition pub privacy: Privacy, + /// The name of this function pub name: Option, + /// The function parameters associated with this function pub vars: Vec, + /// The content of the function pub body: Expr, } @@ -76,7 +91,9 @@ pub struct FunDef { /// #[derive(Clone, Debug)] pub struct StructDef { + /// Name of the structure pub name: Spanned, + /// Fields of the structure pub fields: Vec>, } @@ -90,37 +107,62 @@ pub struct StructDef { /// #[derive(Clone, Debug)] pub struct EnumDef { + /// Name of the enumeration pub name: Spanned, + /// Variants for this enumeration pub variants: Vec, } +/// Define a variant for a enumeration #[derive(Clone, Debug)] pub struct Variant(StructDef); -/// A pattern "matching" +/// A pattern "matching" for a let #[derive(Clone, Debug)] pub enum Binder { + /// equivalent of `let () = ...` Unit, + /// equivalent of `let _ = ...` Ignore, + /// equivalent of `let $ident = ...` Ident(Ident), } +/// Expression #[derive(Clone, Debug)] pub enum Expr { + /// Literal, e.g. 1, or "abc" Literal(Span, Literal), + /// A Variable, e.g. `a` Ident(Span, Ident), + /// Structure Field access, e.g. `(some expr).$struct-name+$field` + /// + /// Note that this need to contains the name of the structure that we + /// want to access into. it's up to the frontend to provide this information + /// either by disambiguating at the frontend level by adding explicit struct name + /// or by other methods Field(Box, Spanned, Spanned), + /// A List expression List(Span, Vec), + /// A Let binding of the form `let $binder = $expr in $expr` Let(Binder, Box, Box), + /// An anonymous function definition expression, e.g. `|a| ...` or `\x -> ...` Lambda(Span, Box), + /// A function call, e.g. `print("hello", "werbolg")` Call(Span, Vec), + /// An If expression `if $cond { $then_expr } else { $else_expr }` If { + /// Span of the if span: Span, + /// Condition expression cond: Box>, + /// Then expression, to run if the conditional hold then_expr: Box>, + /// Else expression, to run if the conditional does not hold else_expr: Box>, }, } +/// A variable (function parameter) #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Variable(pub Spanned); diff --git a/werbolg-core/src/lib.rs b/werbolg-core/src/lib.rs index dd33117..41662e8 100644 --- a/werbolg-core/src/lib.rs +++ b/werbolg-core/src/lib.rs @@ -1,4 +1,7 @@ +//! Werbolg Core + #![no_std] +#![deny(missing_docs)] extern crate alloc; diff --git a/werbolg-core/src/location.rs b/werbolg-core/src/location.rs index a35fde9..c3dbd51 100644 --- a/werbolg-core/src/location.rs +++ b/werbolg-core/src/location.rs @@ -3,6 +3,7 @@ use core::ops::Deref; /// Span as a range of bytes in a file pub type Span = core::ops::Range; +/// Merge two spans together, note that the end span need to be after the start span pub fn span_merge(start: &Span, end: &Span) -> Span { assert!( start.end <= end.start, @@ -16,6 +17,7 @@ pub fn span_merge(start: &Span, end: &Span) -> Span { } } +/// Merge many span from an iterator together pub fn spans_merge<'a, I>(it: &mut I) -> Span where I: Iterator, @@ -35,9 +37,14 @@ where } /// A type T with an attached Span +/// +/// The Eq instance of Span, doesn't check that the span are equal, +/// for explicit checking using `span_eq` #[derive(Clone, Debug, Hash)] pub struct Spanned { + /// The span of T pub span: Span, + /// Inner value T pub inner: T, } @@ -58,15 +65,19 @@ impl PartialEq for Spanned { impl Eq for Spanned {} impl Spanned { + /// Check that the Spanned is equivalent to another pub fn span_eq(&self, other: &Self) -> bool { self.span == other.span && self.inner == other.inner } } impl Spanned { + /// Create a new spanned type from its inner components pub fn new(span: Span, inner: T) -> Self { Self { span, inner } } + + /// Consume the Spanned and return its inner type only pub fn unspan(self) -> T { self.inner }