Added some syntax

This commit is contained in:
Erin 2023-10-04 02:38:27 +02:00 committed by ondra05
parent 840c75f891
commit 47d44dcd04
5 changed files with 183 additions and 30 deletions

View file

@ -1,2 +1,3 @@
enum_discrim_align_threshold = 16 enum_discrim_align_threshold = 16
struct_field_align_threshold = 16 struct_field_align_threshold = 16
imports_granularity = "one"

View file

@ -3,15 +3,23 @@
mod syntax; mod syntax;
mod utils; mod utils;
use bumpalo::Bump; use {
use std::io::{stdin, Read}; bumpalo::Bump,
use utils::default; std::io::{stdin, Read},
utils::default,
};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut buf = default(); let mut buf = default();
stdin().read_to_string(&mut buf)?; stdin().read_to_string(&mut buf)?;
let arena = Bump::new(); let arena = Bump::new();
println!("{:?}", syntax::parser::parse(&buf, &arena)); match syntax::parser::parse(&buf, &arena) {
Ok(ast) => println!("{ast:?}"),
Err(e) => {
eprintln!("[ERROR] {e:?}");
eprintln!(" Caused at: `{}`", &buf[e.span.start..e.span.end])
}
}
Ok(()) Ok(())
} }

View file

@ -59,6 +59,7 @@ pub enum Expr<'a> {
}, },
Break(Option<ExprRef<'a>>), Break(Option<ExprRef<'a>>),
Return(Option<ExprRef<'a>>), Return(Option<ExprRef<'a>>),
Uninit,
Continue, Continue,
} }
@ -68,10 +69,10 @@ pub enum Definition<'a> {
kind: DefKind, kind: DefKind,
ident: Spanned<Ident>, ident: Spanned<Ident>,
ty: Option<Spanned<Type>>, ty: Option<Spanned<Type>>,
init: Option<ExprRef<'a>>, init: ExprRef<'a>,
}, },
Func { Func {
ident: Spanned<Ident>, name: Spanned<Ident>,
params: &'a [(Spanned<Ident>, Spanned<Type>)], params: &'a [(Spanned<Ident>, Spanned<Type>)],
ret: Spanned<Type>, ret: Spanned<Type>,
body: ExprList<'a>, body: ExprList<'a>,

View file

@ -1,19 +1,43 @@
use bumpalo::Bump; use {
use logos::Logos; super::{
ast::{DefKind, Definition, Expr, ExprList, Ident, Spanned, Type},
use super::{ token::Token,
ast::{Definition, Spanned}, },
token::Token, crate::syntax::token::T,
bumpalo::{vec, Bump},
logos::Logos,
}; };
type Lexer<'a> = logos::Lexer<'a, Token>; type Lexer<'a> = logos::Lexer<'a, Token>;
macro_rules! extract { macro_rules! extract {
($self:expr, $pat:pat) => {
let $pat = $self.next()? else {
return Err($self.error(ErrorKind::UnexpectedToken));
};
};
}
macro_rules! let_until {
( (
$self:expr, $self:expr,
$(pat:pat),* $(,)? let $bind:pat,
until |$next:pat_param| $cond:expr,
$expr:expr
$(,)?
) => { ) => {
loop {
let $next = $self.next()?;
if $cond {
break;
}
let $bind = $self.next()? else {
return Err($self.error(ErrorKind::UnexpectedToken));
};
$expr;
}
}; };
} }
@ -39,16 +63,133 @@ impl<'a, 'l> Parser<'a, 'l> {
Spanned::new(kind, self.lexer.span()) Spanned::new(kind, self.lexer.span())
} }
/// Mark with current span
#[inline]
fn spanned<T>(&self, item: T) -> Spanned<T> {
Spanned::new(item, self.lexer.span())
}
/// Require a token to be
fn require(&mut self, token: Token) -> Result<()> {
if self.next()? != token {
Err(self.error(ErrorKind::UnexpectedToken))
} else {
Ok(())
}
}
/// Parse everything or DIE! /// Parse everything or DIE!
fn run(self) -> Result<&'a [Definition<'a>]> { fn run(mut self) -> Result<&'a [Definition<'a>]> {
let mut defs = vec![in self.arena];
loop {
match self.lexer.next() {
Some(Ok(Token::Func)) => {
defs.push(self.func()?);
}
Some(Ok(Token::Const)) => defs.push(self.var_def(DefKind::Const)?),
Some(Ok(Token::Var)) => defs.push(self.var_def(DefKind::Var)?),
Some(Ok(_)) => return Err(self.error(ErrorKind::UnexpectedToken)),
Some(Err(())) => return Err(self.error(ErrorKind::InvalidToken)),
None => return Ok(defs.into_bump_slice()),
}
}
}
fn ident(&mut self) -> Result<Spanned<Ident>> {
extract!(self, Token::Ident(id));
Ok(self.spanned(id))
}
fn ty(&mut self) -> Result<Spanned<Type>> {
extract!(self, Token::Ident(id));
Ok(self.spanned(Type::Ident(id)))
}
fn block(&mut self) -> Result<ExprList<'a>> {
self.require(T!["{"])?;
// TODO
self.require(T!["}"])?;
Ok(self.arena.alloc_slice_copy(&[])) Ok(self.arena.alloc_slice_copy(&[]))
} }
fn var_def(&mut self, kind: DefKind) -> Result<Definition<'a>> {
// <kind> <ident> [: <ty>] = <expr>;
// ^^^^^^
extract!(self, Token::Ident(id));
let ident = self.spanned(id);
let ty = match self.next()? {
Token::Colon => {
let r = Some(self.ty()?);
self.require(T!["="])?;
r
}
Token::Equ => None,
_ => return Err(self.error(ErrorKind::UnexpectedToken)),
};
self.require(T!["uninit"])?;
self.require(T![";"])?;
Ok(Definition::Binding {
kind,
ident,
ty,
init: self.arena.alloc(self.spanned(Expr::Uninit)),
})
}
fn func(&mut self) -> Result<Definition<'a>> {
// func <ident> ($(<ident>: <ty>),*) → <ty> { … }
// ^^^^
let name = self.ident()?;
// Parameter list
let mut params = vec![in self.arena];
self.require(T!["("])?;
let mut next = self.next()?;
if next != T![")"] {
loop {
let Token::Ident(id) = next else {
return Err(self.error(ErrorKind::UnexpectedToken));
};
let id = self.spanned(id);
self.require(T![":"])?;
params.push((id, self.ty()?));
match self.next()? {
Token::RightParen => break,
Token::Comma => (),
_ => return Err(self.error(ErrorKind::UnexpectedToken)),
}
next = self.next()?;
}
}
self.require(T![""])?;
let ret = self.ty()?;
let body = self.block()?;
Ok(Definition::Func {
name,
params: params.into_bump_slice(),
ret,
body,
})
}
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ErrorKind { pub enum ErrorKind {
InvalidToken, InvalidToken,
UnexpectedEnd, UnexpectedEnd,
UnexpectedToken,
} }
pub type Error = Spanned<ErrorKind>; pub type Error = Spanned<ErrorKind>;

View file

@ -12,7 +12,7 @@ macro_rules! token_def {
keyword { $($kw:tt),* $(,)* } keyword { $($kw:tt),* $(,)* }
else { $($e_tt:tt)* } else { $($e_tt:tt)* }
) => { ) => {
literify::literify! (paste::paste! { literify::literify!(paste::paste! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Logos)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Logos)]
#[logos(extras = Extras)] #[logos(extras = Extras)]
#[logos(skip r"[ \t\n\f]+")] #[logos(skip r"[ \t\n\f]+")]
@ -35,6 +35,8 @@ macro_rules! token_def {
$($( $($(
($u_tok) => { $crate::syntax::token::Token::$u_name }; ($u_tok) => { $crate::syntax::token::Token::$u_name };
)*)* )*)*
$((~($kw)) => { $crate::syntax::token::Token::[<$kw:camel>] };)*
} }
}); });
}; };
@ -72,23 +74,23 @@ token_def!(
return, break, continue, uninit, asm } return, break, continue, uninit, asm }
else { else {
#[regex( #[regex(
r"\p{XID_Start}\p{XID_Continue}*", r"\p{XID_Start}\p{XID_Continue}*",
|l| intern(l, l.slice()), |l| intern(l, l.slice()),
)] Ident(Spur), )] Ident(Spur),
#[regex( #[regex(
"\"[^\"]*\"", "\"[^\"]*\"",
|l| { |l| {
let s = l.slice(); let s = l.slice();
intern(l, &s[1..s.len() - 1]) intern(l, &s[1..s.len() - 1])
}, },
)] String(Spur), )] String(Spur),
#[regex( #[regex(
"[0-9]+", "[0-9]+",
|l| l.slice().parse::<u64>().ok() |l| l.slice().parse::<u64>().ok()
)] Int(u64), )] Int(u64),
} }
); );