2026-02-26 19:40:27 +01:00
|
|
|
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! {
|
2026-03-06 15:21:44 +01:00
|
|
|
lhs:(@) __ op:$("as") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Cast(op), rhs })) }
|
|
|
|
|
--
|
|
|
|
|
lhs:@ __ op:$("=") __ rhs:expr() { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Assign(op), rhs })) }
|
2026-02-26 19:40:27 +01:00
|
|
|
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 })) }
|
|
|
|
|
--
|
2026-03-06 15:21:44 +01:00
|
|
|
lhs:(@) __ op:$("==") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Eq(op), rhs })) }
|
|
|
|
|
lhs:(@) __ op:$("!=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Ne(op), rhs })) }
|
2026-02-27 15:48:16 +01:00
|
|
|
lhs:(@) __ op:$("<") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Lt(op), rhs })) }
|
|
|
|
|
lhs:(@) __ op:$(">") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Gt(op), rhs })) }
|
|
|
|
|
lhs:(@) __ op:$("<=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Le(op), rhs })) }
|
|
|
|
|
lhs:(@) __ op:$(">=") __ rhs:@ { Expr::Binary(Box::new(BinaryExpr { lhs, op: BinaryOp::Ge(op), rhs })) }
|
|
|
|
|
--
|
2026-02-26 19:40:27 +01:00
|
|
|
block:block() { Expr::Block(block)}
|
|
|
|
|
for_loop:for_loop() { Expr::For(Box::new(for_loop))}
|
2026-02-27 15:48:16 +01:00
|
|
|
while_loop:while_loop() { Expr::While(Box::new(while_loop))}
|
2026-02-26 19:40:27 +01:00
|
|
|
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) }
|
2026-03-06 15:21:44 +01:00
|
|
|
"[" __ list:(expr() ** ("," __)) __ "]" { Expr::List(list) }
|
2026-02-26 19:40:27 +01:00
|
|
|
"(" __ v:expr() __ ")" { v }
|
2026-02-27 15:48:16 +01:00
|
|
|
"*" __ m:"mut"? __ v:expr() { Expr::Type(Box::new(Type::Ptr { base:v, mutable: m.is_some() })) }
|
2026-02-26 19:40:27 +01:00
|
|
|
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
|
2026-02-27 15:48:16 +01:00
|
|
|
= s:position!() t:$"fn" __ "(" __ args:name_value_pairs() __ ")" __ ret:("->" __ e:expr() {e})? __ block:block()? e:position!()
|
2026-02-26 19:40:27 +01:00
|
|
|
{ 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 } }
|
|
|
|
|
|
2026-02-27 15:48:16 +01:00
|
|
|
rule while_loop() -> While =
|
|
|
|
|
"while" _ value:expr() _ block:block()
|
|
|
|
|
{ While { value, block } }
|
|
|
|
|
|
2026-02-26 19:40:27 +01:00
|
|
|
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;
|