cl 0.0.2: MAJOR ERGONOMIC BOOST

Broke frontend into its own library, "cl-frontend"
- Frontend is pretty :D
- Included sample fibonacci implementation

Deprecated conlang::ast::Visitor in favor of bespoke traits
- Rust traits are super cool.
- The Interpreter is currently undergoing a major rewrite

Added preliminary type-path support to the parser
- Currently incomplete: type paths must end in Never..?

Pretty printer is now even prettier
- conlang::ast now exports all relevant AST nodes, since there are no namespace collisions any more
This commit is contained in:
2024-01-04 02:18:09 -06:00
parent 9b7cf9c017
commit 79fda16788
14 changed files with 1284 additions and 563 deletions

View File

@@ -11,19 +11,16 @@
//! See [statement], [literal], and [expression] for more information.
pub mod preamble {
#![allow(deprecated)]
//! Common imports for working with the [ast](super)
pub use super::{
expression::{
self,
call::*,
control,
math::{self, operator},
tuple::*,
},
literal,
expression::{call::*, control::*, math::*, tuple::*, *},
literal::*,
path::*,
statement::*,
types::*,
visitor::Visitor,
Identifier, Program, Start,
*,
};
}
@@ -43,47 +40,9 @@ pub struct Program(pub Vec<statement::Stmt>);
/// # Syntax
/// [`Identifier`]` := `[`IDENTIFIER`](crate::token::token_type::Type::Identifier)
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Identifier(pub String);
pub mod todo {
//! temporary storage for pending expression work. \
//! when an item is in progress, remove it from todo.
//!
//! # General TODOs:
//! - [x] Implement support for storing items in the AST
//! - [ ] Keep track of the source location of each node
//! - [ ] Implement paths
//! - [x] Implement functions
//! - [ ] Implement structs
//! - [ ] Implement enums
//! - [ ] Implement implementation
//! - [ ] Store token spans in AST
pub mod path {
//! Path support
//! - [ ] Add namespace syntax (i.e. `::crate::foo::bar` | `foo::bar::Baz` | `foo::bar::*`)
//!
//! Path resolution will be vital to the implementation of structs, enums, impl blocks,
//! traits, modules, etc.
}
pub mod structure {
//! Struct support
//! - [ ] Add struct declaration expression (returns a struct declaration)
//! - [ ] Add struct value expression (returns a struct value)
//! - [ ] Add struct update syntax (yippee!!)
}
pub mod enumeration {
//! Enum support
//! - [ ] Add enum declaration expression (returns an enum declaration)
//! - [ ] Add enum value expression (returns an enum value)
}
pub mod implementation {
//! Impl block support
//! - [ ] Add impl block expression? Statement?
//! - [ ] Add member function call expression
}
pub struct Identifier {
pub name: String,
pub index: Option<usize>,
}
pub mod literal {
@@ -150,6 +109,7 @@ pub mod statement {
use super::{
expression::{Block, Expr},
types::TypeExpr,
Identifier,
};
@@ -164,7 +124,7 @@ pub mod statement {
Let(Let),
/// Contains a function declaration
/// # Syntax
/// [`Fn`](Stmt::Fn) := `"fn"` [`Identifier`] `'('` [`Tuple`] `')'` [`Block`]
/// [`Fn`](Stmt::Fn) := `"fn"` [`Identifier`] `'('` `Args...` `')'` [`Block`]
Fn(FnDecl),
/// Contains an expression statement
/// # Syntax
@@ -177,26 +137,104 @@ pub mod statement {
/// [`Let`] := `let` [`Identifier`] (`:`) `Type`)? (`=` [`Expr`])? `;`
#[derive(Clone, Debug)]
pub struct Let {
pub name: Identifier,
pub mutable: bool,
pub ty: Option<Identifier>,
pub name: Name,
pub init: Option<Expr>,
}
/// Contains a function declaration
/// # Syntax
/// [`FnDecl`] := `"fn"` [`Identifier`] `'('` [`Tuple`] `')'`
/// [`FnDecl`] := `"fn"` [`Identifier`] `'('` `Args...` `')'`
#[derive(Clone, Debug)]
pub struct FnDecl {
pub name: Identifier,
pub args: Vec<Identifier>,
pub name: Name,
pub args: Vec<Name>,
pub body: Block,
// TODO: Store type information
}
/// Contains the name, mutability, and type information for a [Let] or [FnDecl]
/// # Syntax
#[derive(Clone, Debug)]
pub struct Name {
pub name: Identifier,
/// The mutability of the [Name]. Functions are never mutable.
pub mutable: bool,
/// The [type](TypeExpr)
pub ty: Option<TypeExpr>,
}
// TODO: Create closure, transmute fndecl into a name and closure
}
pub mod path {
//! Paths
//!
//! A Path Expression refers to an item, either local or module-scoped.
use super::Identifier;
/// A path to an item in a module
/// # Syntax
/// [`Path`]` := "::"? `[`PathPart`]` ("::" `[`PathPart`]`)*`
#[derive(Clone, Debug)]
pub struct Path {
pub absolute: bool,
pub parts: Vec<PathPart>,
}
/// A component of a [`TypePath`]
/// # Syntax
/// [`PathPart`]` := "super" | `[`Identifier`]
#[derive(Clone, Debug)]
pub enum PathPart {
PathSuper,
PathSelf,
PathIdent(Identifier),
}
}
pub mod types {
//! # Types
//!
//! The [Type Expresson](TypeExpr) powers Conlang's type checker.
//!
//! # Syntax
//! [`TypeExpr`]` := `[`TupleType`]` | `[`TypePath`]` | `[`Never`]
pub use super::path::Path as TypePath;
/// Contains a [Type Expression](self)
///
/// # Syntax
/// [`TypeExpr`]` := `[`TupleType`]` | `[`TypePath`]` | `[`Empty`]` | `[`Never`]
#[derive(Clone, Debug)]
pub enum TypeExpr {
TupleType(TupleType),
TypePath(TypePath),
Empty(Empty),
Never(Never),
}
/// A [TupleType] represents the [TypeExpr] of a Tuple value
#[derive(Clone, Debug)]
pub struct TupleType {
pub types: Vec<TypeExpr>,
}
/// The empty type. You get nothing! You lose!
/// # Syntax
/// [`Empty`]` := '(' ')'`
#[derive(Clone, Copy, Debug, Default)]
pub struct Empty;
/// The never type. This type can never be constructed, and can only appear if a block of code
/// doesn't terminate
/// # Syntax
/// [`Never`]` := '!'`
#[derive(Clone, Copy, Debug, Default)]
pub struct Never;
}
pub mod expression {
//! # Expressions
//!
@@ -219,17 +257,19 @@ pub mod expression {
//! | 9 | [`control::Flow`] | Branch expressions (`if`, `while`, `for`, `return`, `break`, `continue`)
//! | 9 | [`Group`] | Group expressions `(` [Expr]? `)` /* Can evaluate to Empty! */
//! | 9 | [`Block`] | Block expressions `{` [Expr] `}`
//! | 9 | [`Primary`] | Contains an [Identifier], [Literal](literal::Literal), [Block], [Group], or [Flow](control::Flow)
//! | 9 | [`Primary`] | Contains an [Identifier], [Literal], [Block], [Group], or [Flow]
//!
//! ## Syntax
//! [`Expr`]` := `[`math::Operation`] \
//! [`Block`]` := '{' `[`Expr`]` '}'` \
//! [`Group`]` := '(' `[`Expr`]`? ')'` \
//! [`Primary`]` := `[`Identifier`]` | `[`Literal`](literal::Literal)` | `[`Block`]` |
//! `[`Group`]` | `[`control::Flow`]
//! [`Primary`]` := `[`Identifier`]` | `[`Literal`]` | `[`Block`]` |
//! `[`Group`]` | `[`Flow`]
//!
//! See [control] and [math] for their respective production rules.
use super::{statement::Stmt, *};
use super::{literal::Literal, statement::Stmt, *};
use control::Flow;
use tuple::Group;
/// Contains an expression
///
@@ -241,18 +281,18 @@ pub mod expression {
/// A [Primary] Expression is the expression with the highest precedence (i.e. the deepest
/// derivation)
/// # Syntax
/// [`Primary`]` := `[`IDENTIFIER`](Identifier)`
/// | `[`Literal`](literal::Literal)`
/// | `[`Block`]`
/// | `[`Group`](tuple::Group)`
/// | `[`Branch`](control::Flow)
/// [`Primary`]` := `[`Identifier`]`
/// | `[`Literal`]`
/// | `[`Block`]`
/// | `[`Group`]`
/// | `[`Branch`](Flow)
#[derive(Clone, Debug)]
pub enum Primary {
Identifier(Identifier),
Literal(literal::Literal),
Literal(Literal),
Block(Block),
Group(tuple::Group),
Branch(control::Flow),
Group(Group),
Branch(Flow),
}
/// Contains a Block Expression
@@ -260,6 +300,7 @@ pub mod expression {
/// [`Block`] := `'{'` [`Expr`] `'}'`
#[derive(Clone, Debug)]
pub struct Block {
pub let_count: Option<usize>,
pub statements: Vec<Stmt>,
pub expr: Option<Box<Expr>>,
}
@@ -352,7 +393,7 @@ pub mod expression {
//! [`Shift`][2]` := `[`Term`][2]` (`[`ShiftOp`][5]` `[`Term`][2]` )*` \
//! [`Term`][2]` := `[`Factor`][2]` (`[`TermOp`][5]` `[`Factor`][2]` )*` \
//! [`Factor`][2]` := `[`Unary`][1]` (`[`FactorOp`][5]` `[`Unary`][1]` )*` \
//! [`Unary`][1]` := (`[`UnaryOp`][4]`)* `[`FnCall`][7]
//! [`Unary`][1]` := (`[`UnaryOp`][4]`)* `[`Call`]
//!
//! [1]: Operation::Unary
//! [2]: Operation::Binary
@@ -704,10 +745,10 @@ pub mod expression {
pub mod visitor {
//! A [`Visitor`] visits every kind of node in the [Abstract Syntax Tree](super)
//!
//!
//! This trait is mostly here to ensure that every branch of the tree is accounted for.
//!
//! Default implementations are provided for
//!
//! Default implementations are provided for
use super::{
expression::{call::*, control::*, math::*, tuple::*, Block, *},
literal::*,
@@ -716,6 +757,7 @@ pub mod visitor {
};
/// A Visitor traverses every kind of node in the [Abstract Syntax Tree](super)
#[deprecated]
pub trait Visitor<R> {
/// Visit the start of an AST
fn visit(&mut self, start: &Start) -> R {
@@ -733,9 +775,9 @@ pub mod visitor {
}
}
/// Visit a [Let statement](Let)
fn visit_let(&mut self, stmt: &Let) -> R;
fn visit_let(&mut self, decl: &Let) -> R;
/// Visit a [Fn declaration](FnDecl)
fn visit_fn_decl(&mut self, function: &FnDecl) -> R;
fn visit_fn_decl(&mut self, decl: &FnDecl) -> R;
/// Visit an [Expression](Expr)
fn visit_expr(&mut self, expr: &Expr) -> R {
@@ -781,10 +823,11 @@ pub mod visitor {
/// Visit a [Unary] Operation
fn visit_unary(&mut self, unary: &Unary) -> R;
// Math operators
/// Visit an [Assignment](Assign) [operator](operator::Assign)
fn visit_assign_op(&mut self, op: &operator::Assign) -> R;
/// Visit a [Binary](Operation::Binary) [operator](operator::Binary)
/// Visit a [Binary] [operator](operator::Binary)
fn visit_binary_op(&mut self, op: &operator::Binary) -> R;
/// Visit a [Unary](Operation::Unary) [operator](operator::Unary)
/// Visit a [Unary] [operator](operator::Unary)
fn visit_unary_op(&mut self, op: &operator::Unary) -> R;
/// Visit a [Primary] expression
@@ -796,7 +839,7 @@ pub mod visitor {
Primary::Literal(v) => self.visit_literal(v),
Primary::Block(v) => self.visit_block(v),
Primary::Group(v) => self.visit_group(v),
Primary::Branch(v) => self.visit_branch_expr(v),
Primary::Branch(v) => self.visit_branch(v),
}
}
@@ -804,8 +847,8 @@ pub mod visitor {
///
/// [`Flow`]` := `[`While`]` | `[`If`]` | `[`For`]`
/// | `[`Continue`]` | `[`Return`]` | `[`Break`]
fn visit_branch_expr(&mut self, expr: &Flow) -> R {
match expr {
fn visit_branch(&mut self, flow: &Flow) -> R {
match flow {
Flow::While(e) => self.visit_while(e),
Flow::If(e) => self.visit_if(e),
Flow::For(e) => self.visit_for(e),
@@ -859,3 +902,46 @@ pub mod visitor {
fn visit_empty(&mut self) -> R;
}
}
pub mod todo {
//! temporary storage for pending expression work. \
//! when an item is in progress, remove it from todo.
//!
//! # General TODOs:
//! - [ ] REMOVE VISITOR TRAIT
//! - [ ]
//! - [x] Implement support for storing items in the AST
//! - [ ] Keep track of the source location of each node
//! - [ ] Implement paths
//! - [x] Implement functions
//! - [ ] Implement structs
//! - [ ] Implement enums
//! - [ ] Implement implementation
//! - [ ] Store token spans in AST
pub mod path {
//! Path support
//! - [ ] Add namespace syntax (i.e. `::crate::foo::bar` | `foo::bar::Baz` | `foo::bar::*`)
//!
//! Path resolution will be vital to the implementation of structs, enums, impl blocks,
//! traits, modules, etc.
}
pub mod structure {
//! Struct support
//! - [ ] Add struct declaration expression (returns a struct declaration)
//! - [ ] Add struct value expression (returns a struct value)
//! - [ ] Add struct update syntax (yippee!!)
}
pub mod enumeration {
//! Enum support
//! - [ ] Add enum declaration expression (returns an enum declaration)
//! - [ ] Add enum value expression (returns an enum value)
}
pub mod implementation {
//! Impl block support
//! - [ ] Add impl block expression? Statement?
//! - [ ] Add member function call expression
}
}