Big restructure pt.1

This commit is contained in:
Mia
2026-02-26 19:40:27 +01:00
parent 02f2ddfc67
commit f4334e79f6
32 changed files with 905 additions and 842 deletions
+1
View File
@@ -0,0 +1 @@
/target
+9
View File
@@ -0,0 +1,9 @@
[package]
name = "leaf_parser"
version = "0.1.0"
edition = "2024"
[dependencies]
arcstr = "1.2.0"
derive_more = { version = "2.1.0", features = ["deref", "debug", "display"] }
peg = "0.8.5"
+140
View File
@@ -0,0 +1,140 @@
use arcstr::Substr;
use derive_more::Deref;
#[derive(Debug, Deref)]
pub struct Ident(pub Substr);
#[derive(Debug, Deref)]
pub struct Import(pub Expr);
#[derive(Debug)]
pub struct Number {
pub text: Substr,
pub r#type: Option<Ident>,
}
#[derive(derive_more::Debug)]
pub enum Expr {
#[debug("uninit")]
Uninit(Substr),
#[debug("Ident({:?})", _0.0)]
Ident(Ident),
#[debug("{_0:?}")]
Number(Number),
String(Substr),
#[debug("{_0:?}")]
Binary(Box<BinaryExpr>),
Index(Box<IndexingExpr>),
Tuple(Vec<Expr>),
List(Vec<Expr>),
Struct(Box<StructCtor>),
#[debug("{_0:?}")]
Block(Block),
#[debug("{_0:?}")]
Func(Box<Function>),
#[debug("{_0:?}")]
ConstDecl(Box<ConstDecl>),
#[debug("{_0:?}")]
VarDecl(Box<VarDecl>),
#[debug("{_0:?}")]
For(Box<For>),
Call {
func: Box<Expr>,
args: Vec<Expr>,
},
}
#[derive(Debug)]
pub struct BinaryExpr {
pub lhs: Expr,
pub op: BinaryOp,
pub rhs: Expr,
}
#[derive(Debug)]
pub struct IndexingExpr {
pub value: Expr,
pub index: Expr,
}
#[rustfmt::skip]
#[derive(derive_more::Debug)]
pub enum BinaryOp {
#[debug("{_0:?}")] Add(Substr),
#[debug("{_0:?}")] Sub(Substr),
#[debug("{_0:?}")] Mul(Substr),
#[debug("{_0:?}")] Div(Substr),
#[debug("{_0:?}")] Mod(Substr),
#[debug("{_0:?}")] Dot(Substr),
#[debug("{_0:?}")] Range(Substr),
#[debug("{_0:?}")] Assign(Substr),
}
#[derive(Debug)]
pub struct ConstDecl {
pub names: NamePattern,
pub r#type: Option<Expr>,
pub value: Expr,
}
#[derive(Debug)]
pub struct VarDecl {
pub names: NamePattern,
pub r#type: Option<Expr>,
pub value: Expr,
}
#[derive(Debug)]
pub enum NamePattern {
Single(Ident),
Tuple(Vec<Ident>),
List(Vec<Ident>),
}
impl NamePattern {
pub fn as_slice(&self) -> &[Ident] {
match self {
NamePattern::Single(ident) => std::slice::from_ref(ident),
NamePattern::Tuple(idents) => idents.as_slice(),
NamePattern::List(idents) => idents.as_slice(),
}
}
}
#[derive(Debug)]
pub struct Function {
pub text: Substr,
pub args: Vec<NameValuePair>,
pub ret: Expr,
pub block: Option<Block>,
}
#[derive(Debug)]
pub struct NameValuePair {
pub name: Ident,
pub r#type: Expr,
}
#[derive(Debug)]
pub struct StructCtor {
pub r#type: Expr,
pub r#values: Vec<NameValuePair>,
}
#[derive(Debug)]
pub struct Block(pub Vec<Expr>);
#[derive(Debug)]
pub struct For {
pub names: NamePattern,
pub value: Expr,
pub block: Block,
}
#[derive(Debug)]
pub struct CompilationUnit {
pub imports: Vec<Import>,
pub decls: Vec<ConstDecl>,
}
+19
View File
@@ -0,0 +1,19 @@
use arcstr::ArcStr;
pub use parser::{compilation_unit as parse, *};
use std::{fmt::Debug, path::PathBuf};
pub mod ast;
mod parser;
pub struct SourceCode {
pub text: ArcStr,
pub file: PathBuf,
}
impl Debug for SourceCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SourceCode")
.field("text", &self.text)
.finish_non_exhaustive()
}
}
+12
View File
@@ -0,0 +1,12 @@
use arcstr::ArcStr;
use leaf_parser::SourceCode;
use std::path::PathBuf;
fn main() {
let source = SourceCode {
text: ArcStr::from(std::fs::read_to_string("../test.leaf").unwrap()),
file: PathBuf::from("../test.leaf"),
};
let unit = leaf_parser::parse(&source);
let _ = dbg!(unit);
}
+146
View File
@@ -0,0 +1,146 @@
use crate::SourceCode;
use crate::ast::*;
use arcstr::Substr;
use peg::{Parse, ParseElem, ParseLiteral, ParseSlice};
pub use peg::{error::*, str::LineCol};
impl Parse for SourceCode {
type PositionRepr = LineCol;
#[inline]
fn start<'input>(&'input self) -> usize {
self.text.as_str().start()
}
#[inline]
fn is_eof<'input>(&'input self, p: usize) -> bool {
self.text.as_str().is_eof(p)
}
#[inline]
fn position_repr<'input>(&'input self, p: usize) -> Self::PositionRepr {
self.text.as_str().position_repr(p)
}
}
impl<'input> ParseElem<'input> for SourceCode {
type Element = char;
#[inline]
fn parse_elem(&'input self, pos: usize) -> peg::RuleResult<Self::Element> {
self.text.as_str().parse_elem(pos)
}
}
impl ParseLiteral for SourceCode {
#[inline]
fn parse_string_literal(&self, pos: usize, literal: &str) -> peg::RuleResult<()> {
self.text.as_str().parse_string_literal(pos, literal)
}
}
impl<'input> ParseSlice<'input> for SourceCode {
type Slice = Substr;
#[inline]
fn parse_slice(&'input self, p1: usize, p2: usize) -> Self::Slice {
self.text.substr(p1..p2)
}
}
peg::parser! {
grammar leaf_parser() for SourceCode {
// #### ATOMS ####
rule number() -> Number
= text:$(['0'..='9']+) r#type:ident()? { Number { text, r#type } }
/ "0x" text:$(['0'..='9'|'a'..='f'|'A'..'F']+) r#type:ident()? { Number { text, r#type } }
/ "0b" text:$(['0'|'1']+) r#type:ident()? { Number { text, r#type } }
rule ident() -> Ident
= text:$(['_'|'a'..='z'|'A'..='Z']['_'|'a'..='z'|'A'..='Z'|'0'..='9']*) { Ident(text) }
rule string() -> Substr
= str:$("\"" char()* "\"") { str }
rule char() -> char = normal()
rule normal() -> char = [^'\\'|'"']
// ### EXPRESSIONS ####
rule expr() -> Expr = precedence! {
lhs:(@) __ op:$("=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Assign(op), rhs })) }
lhs:(@) __ op:$(".") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Dot(op), rhs })) }
lhs:(@) "(" __ args:(expr() ** ("," __)) __ ")" { Expr::Call { func: Box::new(lhs), args } }
value:(@) "[" __ index:expr() __ "]" { Expr::Index(Box::new(IndexingExpr { value, index })) }
r#type:(@) _ "{" __ values:name_value_pairs() __ "}" { Expr::Struct(Box::new(StructCtor { r#type, values })) }
--
lhs:(@) __ op:$("+") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Add(op), rhs })) }
lhs:(@) __ op:$("-") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Sub(op), rhs })) }
--
lhs:(@) __ op:$("*") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Mul(op), rhs })) }
lhs:(@) __ op:$("/") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Div(op), rhs })) }
lhs:(@) __ op:$("%") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Mod(op), rhs })) }
--
lhs:(@) __ op:$("..") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Range(op), rhs })) }
--
block:block() { Expr::Block(block)}
for_loop:for_loop() { Expr::For(Box::new(for_loop))}
func:func() { Expr::Func(Box::new(func))}
var_decl:var_decl() { Expr::VarDecl(Box::new(var_decl)) }
const_decl:const_decl() { Expr::ConstDecl(Box::new(const_decl)) }
"(" __ tuple:(expr() **<2,> ("," __)) __ ")" { Expr::Tuple(tuple) }
"[" __ list:(expr() **<0,> ("," __)) __ "]" { Expr::List(list) }
"(" __ v:expr() __ ")" { v }
v:string() { Expr::String(v) }
v:number() { Expr::Number(v) }
v:ident() { Expr::Ident(v) }
}
rule block() -> Block
= "{" __ exprs:(i:expr() statement_separator() {i})* __ "}" { Block(exprs) }
rule func() -> Function
= s:position!() t:$"fn" __ "(" __ args:name_value_pairs() __ ")" __ ret:expr() __ block:block()? e:position!()
{ Function { args, ret, block, text: t.parent().substr(s..e), } }
rule name_value_pair() -> NameValuePair
= name:ident() __ ":" __ r#type:expr() { NameValuePair { name, r#type } }
rule name_value_pairs() -> Vec<NameValuePair>
= v:(name_value_pair() ** ("," __)) { v }
rule import() -> Import
= "import" _ expr:expr() { Import(expr) }
rule name_pattern() -> NamePattern
= "(" __ tuple:(ident() ** ("," __)) __ ")" { NamePattern::Tuple(tuple) }
/ "[" __ slice:(ident() ** ("," __)) __ "]" { NamePattern::List(slice) }
/ ident:ident() { NamePattern::Single(ident) }
rule const_decl() -> ConstDecl =
names:name_pattern() _? ":" r#type:(_ t:expr() _ {t})? ":" _ value:expr()
{ ConstDecl { names, r#type, value } }
rule var_decl() -> VarDecl =
names:name_pattern() _? ":" r#type:(_ t:expr() _ {t})? "=" _ value:expr()
{ VarDecl { names, r#type, value } }
rule for_loop() -> For =
"for" _ names:name_pattern() _ "in" _ value:expr() _ block:block()
{ For { names, value, block } }
pub rule compilation_unit() -> CompilationUnit =
__ imports:(i:import() statement_separator() {i})*
__ decls:(d:const_decl() statement_separator() {d})*
__
{ CompilationUnit { imports, decls } }
// #### MISC ####
rule _ = quiet! { [' '|'\t']+ }
rule __ = quiet! { [' '|'\t'|'\n']* }
rule statement_separator() = quiet! { [';'|'\n'] __ }
}
}
pub use leaf_parser::compilation_unit;