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
struct_field_align_threshold = 16
imports_granularity = "one"

View file

@ -3,15 +3,23 @@
mod syntax;
mod utils;
use bumpalo::Bump;
use std::io::{stdin, Read};
use utils::default;
use {
bumpalo::Bump,
std::io::{stdin, Read},
utils::default,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut buf = default();
stdin().read_to_string(&mut buf)?;
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(())
}

View file

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

View file

@ -1,19 +1,43 @@
use bumpalo::Bump;
use logos::Logos;
use super::{
ast::{Definition, Spanned},
use {
super::{
ast::{DefKind, Definition, Expr, ExprList, Ident, Spanned, Type},
token::Token,
},
crate::syntax::token::T,
bumpalo::{vec, Bump},
logos::Logos,
};
type Lexer<'a> = logos::Lexer<'a, Token>;
macro_rules! extract {
($self:expr, $pat:pat) => {
let $pat = $self.next()? else {
return Err($self.error(ErrorKind::UnexpectedToken));
};
};
}
macro_rules! let_until {
(
$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())
}
/// 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!
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(&[]))
}
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)]
pub enum ErrorKind {
InvalidToken,
UnexpectedEnd,
UnexpectedToken,
}
pub type Error = Spanned<ErrorKind>;

View file

@ -12,7 +12,7 @@ macro_rules! token_def {
keyword { $($kw:tt),* $(,)* }
else { $($e_tt:tt)* }
) => {
literify::literify! (paste::paste! {
literify::literify!(paste::paste! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Logos)]
#[logos(extras = Extras)]
#[logos(skip r"[ \t\n\f]+")]
@ -35,6 +35,8 @@ macro_rules! token_def {
$($(
($u_tok) => { $crate::syntax::token::Token::$u_name };
)*)*
$((~($kw)) => { $crate::syntax::token::Token::[<$kw:camel>] };)*
}
});
};