Big restructure pt.1
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/target
|
||||
@@ -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"
|
||||
@@ -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>,
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user