Skip to content
Merged
49 changes: 46 additions & 3 deletions src/ir/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ create_id!(BlockId);
create_id!(ExpressionId);
create_id!(FunctionId);
create_id!(StatementId);
create_id!(AstTypeId);

#[derive(Clone, Debug)]
pub struct Ast {
Expand All @@ -14,6 +15,8 @@ pub struct Ast {
pub blocks: IndexedVec<BlockId, Block>,
pub statements: IndexedVec<StatementId, Statement>,
pub expressions: IndexedVec<ExpressionId, Expression>,

pub types: IndexedVec<AstTypeId, AstType>,
}

impl Ast {
Expand All @@ -23,6 +26,7 @@ impl Ast {
blocks: IndexedVec::new(),
statements: IndexedVec::new(),
expressions: IndexedVec::new(),
types: IndexedVec::new(),
}
}
}
Expand Down Expand Up @@ -59,21 +63,38 @@ impl Index<StatementId> for Ast {
}
}

impl Index<AstTypeId> for Ast {
type Output = AstType;

fn index(&self, index: AstTypeId) -> &Self::Output {
&self.types[index]
}
}

/// Type representation used within the [`Ast`].
#[derive(Clone, Debug)]
pub enum AstType {
/// A type referenced by a single interned name (eg. `i8`, `bool`).
Named(StringId),
/// A tuple type (`(i8, bool, u8)`).
Tuple(Vec<AstTypeId>),
}

mod function {
use super::*;

#[derive(Clone, Debug)]
pub struct FunctionDeclaration {
pub name: StringId,
pub parameters: Vec<FunctionParameter>,
pub return_ty: Option<StringId>,
pub return_ty: Option<AstTypeId>,
pub body: BlockId,
}

#[derive(Clone, Debug)]
pub struct FunctionParameter {
pub name: StringId,
pub ty: StringId,
pub ty: AstTypeId,
}
}

Expand Down Expand Up @@ -144,6 +165,8 @@ mod expression {
Call(Call),
Block(BlockId),
Variable(Variable),
Tuple(Tuple),
Field(Field),
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -180,7 +203,6 @@ mod expression {
pub enum Literal {
Integer(usize),
Boolean(bool),
Unit,
}

#[derive(Clone, Debug)]
Expand All @@ -194,6 +216,25 @@ mod expression {
pub variable: StringId,
}

#[derive(Clone, Debug)]
pub struct Tuple {
pub values: Vec<ExpressionId>,
}
impl Tuple {
pub const UNIT: Self = Self { values: Vec::new() };
}

#[derive(Clone, Debug)]
pub struct Field {
pub lhs: ExpressionId,
pub field: FieldKey,
}

#[derive(Clone, Debug)]
pub enum FieldKey {
Unnamed(usize),
}

enum_conversion! {
[Expression]
Assign: Assign,
Expand All @@ -205,5 +246,7 @@ mod expression {
Call: Call,
Block: BlockId,
Variable: Variable,
Tuple: Tuple,
Field: Field,
}
}
75 changes: 58 additions & 17 deletions src/ir/cst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub use self::{
expression::{BinaryOperation, UnaryOperation, *},
function::*,
statement::*,
ty::*,
util::*,
};

Expand Down Expand Up @@ -70,7 +71,7 @@ mod function {
#[expect(dead_code, reason = "token field")]
pub tok_colon: tok::Colon,
/// Type of the parameter.
pub ty: tok::Ident,
pub ty: CstType,
}

/// Return type for a function declaration.
Expand All @@ -83,7 +84,7 @@ mod function {
#[expect(dead_code, reason = "token field")]
pub tok_thin_arrow: tok::ThinArrow,
/// Return type.
pub ty: tok::Ident,
pub ty: CstType,
}
}

Expand All @@ -98,9 +99,36 @@ pub struct Block {
pub tok_r_brace: tok::RBrace,
}

mod statement {
use crate::enum_conversion;
/// Tuple of items. Used for both a tuple of [`Expression`], and a tuple of [`CstType`].
#[derive(Clone, Debug)]
pub struct Tuple<T> {
#[expect(dead_code, reason = "token field")]
pub tok_l_parenthesis: tok::LParenthesis,
pub items: PunctuatedList<T, tok::Comma>,
#[expect(dead_code, reason = "token field")]
pub tok_r_parenthesis: tok::RParenthesis,
}

mod ty {
use super::*;

/// A type, such as for parameters or variable declarations.
#[derive(Clone, Debug)]
pub enum CstType {
/// A named type represented with a single [`tok::Ident`], such as `i8`.
Named(tok::Ident),
/// A tuple type, composed of many inner [`CstType`]s.
Tuple(Tuple<CstType>),
}

enum_conversion! {
[CstType]
Named: tok::Ident,
Tuple: Tuple<CstType>,
}
}

mod statement {
use super::*;

/// A statement present within a [`Block`].
Expand Down Expand Up @@ -166,8 +194,6 @@ mod statement {
}

mod expression {
use crate::enum_conversion;

use super::*;

/// All possible expressions.
Expand All @@ -184,6 +210,8 @@ mod expression {
Call(Call),
Block(Block),
Variable(Variable),
Tuple(Tuple<Expression>),
Field(Field),
}

/// Assignment.
Expand Down Expand Up @@ -315,8 +343,6 @@ mod expression {
Integer(IntegerLiteral),
/// A boolean.
Boolean(BooleanLiteral),
/// Unit value.
Unit(UnitLiteral),
}

/// An integer literal.
Expand Down Expand Up @@ -345,19 +371,10 @@ mod expression {
}
}

#[derive(Clone, Debug)]
pub struct UnitLiteral {
#[expect(dead_code, reason = "token field")]
pub tok_l_parenthesis: tok::LParenthesis,
#[expect(dead_code, reason = "token field")]
pub tok_r_parenthesis: tok::RParenthesis,
}

enum_conversion! {
[Literal]
Integer: IntegerLiteral,
Boolean: BooleanLiteral,
Unit: UnitLiteral,
}

/// An [`Expression`] wrapped in parentheses.
Expand Down Expand Up @@ -391,6 +408,23 @@ mod expression {
pub variable: tok::Ident,
}

/// Field access expression, such as `my_struct.field` or `my_tuple.0`.
#[derive(Clone, Debug)]
pub struct Field {
pub lhs: Box<Expression>,
#[expect(dead_code, reason = "token field")]
pub tok_dot: tok::Dot,
pub field: FieldKey,
}

/// Different accessors used within [`Field`].
#[derive(Clone, Debug)]
pub enum FieldKey {
Unnamed(tok::IntegerLiteral),
#[expect(dead_code, reason = "named fields will be implemented with struct")]
Named(tok::Ident),
}

enum_conversion! {
[Expression]
Assign: Assign,
Expand All @@ -403,6 +437,8 @@ mod expression {
Call: Call,
Block: Block,
Variable: Variable,
Tuple: Tuple<Expression>,
Field: Field,
}
}

Expand All @@ -423,6 +459,11 @@ mod util {
}
}

/// Determine if the list has trailing punctuation.
pub fn has_trailing(&self) -> bool {
!self.items.is_empty() && self.items.len() == self.punctuation.len()
}

/// Add an item to the list. Will return an error if not expecting an item.
pub fn add_item(&mut self, item: T) -> Result<(), PunctuatedListError> {
if !self.expecting_item() {
Expand Down
19 changes: 18 additions & 1 deletion src/ir/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ mod expression {
Block(BlockId),
Variable(Variable),
Unreachable,
Aggregate(Aggregate),
Field(Field),
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -167,7 +169,6 @@ mod expression {
pub enum Literal {
Integer(usize),
Boolean(bool),
Unit,
}

#[derive(Clone, Debug)]
Expand All @@ -181,6 +182,20 @@ mod expression {
pub binding: BindingId,
}

#[derive(Clone, Debug)]
pub struct Aggregate {
pub values: Vec<ExpressionId>,
}
impl Aggregate {
pub const UNIT: Self = Self { values: Vec::new() };
}

#[derive(Clone, Debug)]
pub struct Field {
pub lhs: ExpressionId,
pub field: usize,
}

enum_conversion! {
[Expression]
Assign: Assign,
Expand All @@ -192,5 +207,7 @@ mod expression {
Call: Call,
Block: BlockId,
Variable: Variable,
Aggregate: Aggregate,
Field: Field,
}
}
9 changes: 8 additions & 1 deletion src/ir/mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ mod place {
#[derive(Clone, Debug)]
pub enum Projection {
Deref,
Field(usize),
}
}

Expand All @@ -309,6 +310,7 @@ mod rvalue {
Ref(PlaceId),
Binary(Binary),
Unary(Unary),
Aggregate(Aggregate),
}

#[derive(Clone, Debug)]
Expand All @@ -331,6 +333,12 @@ mod rvalue {
Not,
Negative,
}

#[derive(Clone, Debug)]
pub struct Aggregate {
pub values: Vec<(OperandId, TypeId)>,
pub ty: TypeId,
}
}

mod operand {
Expand All @@ -347,7 +355,6 @@ mod operand {
U8(u8),
I8(i8),
Boolean(bool),
Unit,
Function(FunctionId),
}
}
4 changes: 4 additions & 0 deletions src/lex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ impl<'src> Lexer<'src> {
self.next_char();
Tok::Comma
}
'.' => {
self.next_char();
Tok::Dot
}
'(' => {
self.next_char();
Tok::LParenthesis
Expand Down
1 change: 1 addition & 0 deletions src/lex/tok.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ toks! {
Bar => "|",
Colon => ":",
SemiColon => ";",
Dot => ".",
Comma => ",",
Bang => "!",

Expand Down
Loading