Compare commits
No commits in common. "882f30371e9d1244c9b692e32c45ffb806a1feba" and "45cc444221179b2fc512f32460cc4f606a28bf11" have entirely different histories.
882f30371e
...
45cc444221
|
|
@ -81,6 +81,7 @@ impl Radix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
pub fn map_digit(self, c: char) -> u8 {
|
pub fn map_digit(self, c: char) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
Radix::Hex => match c {
|
Radix::Hex => match c {
|
||||||
|
|
@ -104,6 +105,7 @@ impl Radix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
pub fn folding_method(self) -> fn(u64, char) -> u64 {
|
pub fn folding_method(self) -> fn(u64, char) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
Radix::Hex => {
|
Radix::Hex => {
|
||||||
|
|
@ -233,6 +235,7 @@ fn try_parse_exp_part(source: &mut Source) -> Result<Option<()>> {
|
||||||
// `.` DEC_DIGITS EXP_PART? FloatingType?
|
// `.` DEC_DIGITS EXP_PART? FloatingType?
|
||||||
// DEC_DIGITS `.` DEC_DIGITS? EXP_PART? FloatingType?
|
// DEC_DIGITS `.` DEC_DIGITS? EXP_PART? FloatingType?
|
||||||
fn parse_constant_inner(source: &mut Source) -> Result<ConstantKind> {
|
fn parse_constant_inner(source: &mut Source) -> Result<ConstantKind> {
|
||||||
|
let start = source.count;
|
||||||
let zero = source.next_if(|&c| c == '0').is_some();
|
let zero = source.next_if(|&c| c == '0').is_some();
|
||||||
|
|
||||||
let radix = zero
|
let radix = zero
|
||||||
|
|
@ -422,6 +425,9 @@ pub(crate) fn parse_comment<'a>(source: &'a mut Source) -> Result<bool> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
|
use crate::complex_tokens::parse_comment;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn make_source(s: &'_ str) -> Source<'_> {
|
fn make_source(s: &'_ str) -> Source<'_> {
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ pub mod is_things {
|
||||||
ch == '0' || ch == '1'
|
ch == '0' || ch == '1'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
pub fn is_nonzero_digit(ch: char) -> bool {
|
pub fn is_nonzero_digit(ch: char) -> bool {
|
||||||
('1'..='9').contains(&ch)
|
('1'..='9').contains(&ch)
|
||||||
}
|
}
|
||||||
|
|
@ -310,14 +311,14 @@ impl Token<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::{marker::PhantomData, ops::Range, sync::Arc};
|
use std::{marker::PhantomData, ops::Range};
|
||||||
|
|
||||||
use trie::Tree;
|
use trie::Tree;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct TokenItem<'a> {
|
pub struct TokenItem<'a> {
|
||||||
pub token: Token<'a>,
|
pub token: Token<'a>,
|
||||||
pub span: Range<u32>,
|
pub offset: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
@ -377,9 +378,8 @@ impl<I: Iterator<Item = char>> CharCountingIterator<core::iter::Peekable<I>> {
|
||||||
|
|
||||||
type Source<'a> = CharCountingIterator<core::iter::Peekable<core::str::Chars<'a>>>;
|
type Source<'a> = CharCountingIterator<core::iter::Peekable<core::str::Chars<'a>>>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TokenIterator<'a> {
|
pub struct TokenIterator<'a> {
|
||||||
trie: Arc<Tree<char, Token<'static>>>,
|
trie: Tree<char, Token<'static>>,
|
||||||
source: &'a str,
|
source: &'a str,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
}
|
}
|
||||||
|
|
@ -392,8 +392,6 @@ impl<'a> TokenIterator<'a> {
|
||||||
trie.insert(token_str.chars(), *token);
|
trie.insert(token_str.chars(), *token);
|
||||||
}
|
}
|
||||||
|
|
||||||
let trie = Arc::new(trie);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
trie,
|
trie,
|
||||||
source,
|
source,
|
||||||
|
|
@ -537,7 +535,7 @@ impl<'a> TokenIterator<'a> {
|
||||||
let (token, range) = self.next_token()?;
|
let (token, range) = self.next_token()?;
|
||||||
Some(TokenItem {
|
Some(TokenItem {
|
||||||
token,
|
token,
|
||||||
span: range.start as u32..range.end as u32,
|
offset: range.start as u32,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -554,7 +552,6 @@ impl<'a> Iterator for TokenIterator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TokenItemIterator<'a> {
|
pub struct TokenItemIterator<'a> {
|
||||||
inner: TokenIterator<'a>,
|
inner: TokenIterator<'a>,
|
||||||
}
|
}
|
||||||
|
|
@ -576,7 +573,6 @@ pub trait TokenConsumer<'a> {
|
||||||
) -> Result<Self::Product, Self::Error>;
|
) -> Result<Self::Product, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
struct SimpleTokenConsumer<S, T: Default = ()>(S, PhantomData<T>);
|
struct SimpleTokenConsumer<S, T: Default = ()>(S, PhantomData<T>);
|
||||||
|
|
||||||
impl<'a, S, T> TokenConsumer<'a> for SimpleTokenConsumer<S, T>
|
impl<'a, S, T> TokenConsumer<'a> for SimpleTokenConsumer<S, T>
|
||||||
|
|
@ -604,7 +600,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
struct TokenSequenceListConsumer<L: TokenSequenceList> {
|
struct TokenSequenceListConsumer<L: TokenSequenceList> {
|
||||||
list: L,
|
list: L,
|
||||||
}
|
}
|
||||||
|
|
@ -636,7 +631,6 @@ impl<'a, L: TokenSequenceList> TokenConsumer<'a> for TokenSequenceListConsumer<L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
struct StealingIterator<T, I: Iterator<Item = T>> {
|
struct StealingIterator<T, I: Iterator<Item = T>> {
|
||||||
pub iter: I,
|
pub iter: I,
|
||||||
pub yielded: Vec<T>,
|
pub yielded: Vec<T>,
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,5 @@ internment = "0.8.6"
|
||||||
|
|
||||||
lexer = { path = "../lexer", version = "0.1.0" }
|
lexer = { path = "../lexer", version = "0.1.0" }
|
||||||
|
|
||||||
chumsky = "0.11"
|
logos = "0.15"
|
||||||
|
pomelo = "0.2"
|
||||||
|
|
@ -1,15 +1,9 @@
|
||||||
use std::{hash::Hash, ops::Range};
|
use std::hash::Hash;
|
||||||
|
|
||||||
use chumsky::{
|
|
||||||
IterParser, Parser,
|
|
||||||
error::EmptyErr,
|
|
||||||
extra::{self, SimpleState},
|
|
||||||
input::{IterInput, MapExtra},
|
|
||||||
prelude::{choice, just, recursive},
|
|
||||||
select, text,
|
|
||||||
};
|
|
||||||
use internment::Intern;
|
use internment::Intern;
|
||||||
use lexer::{Token, TokenItemIterator, TokenIterator};
|
use lexer::{Token, TokenConsumer, TokenItem, TokenItemIterator};
|
||||||
|
use logos::Logos;
|
||||||
|
use pomelo::pomelo;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -38,14 +32,14 @@ pub enum InnerType {
|
||||||
float_type: FloatType,
|
float_type: FloatType,
|
||||||
},
|
},
|
||||||
Pointer {
|
Pointer {
|
||||||
pointee: Type,
|
pointee: Box<Type>,
|
||||||
},
|
},
|
||||||
Array {
|
Array {
|
||||||
element: Type,
|
element: Box<Type>,
|
||||||
size: usize,
|
size: usize,
|
||||||
},
|
},
|
||||||
Function {
|
Function {
|
||||||
return_type: Type,
|
return_type: Box<Type>,
|
||||||
parameter_types: Vec<Type>,
|
parameter_types: Vec<Type>,
|
||||||
},
|
},
|
||||||
Tuple {
|
Tuple {
|
||||||
|
|
@ -125,7 +119,10 @@ pub enum AstNode {
|
||||||
ParameterList {
|
ParameterList {
|
||||||
parameters: Vec<Index>,
|
parameters: Vec<Index>,
|
||||||
},
|
},
|
||||||
Parameter(Parameter),
|
Parameter {
|
||||||
|
name: String,
|
||||||
|
param_type: Type,
|
||||||
|
},
|
||||||
FunctionDecl(FunctionDecl),
|
FunctionDecl(FunctionDecl),
|
||||||
Block {
|
Block {
|
||||||
statements: Vec<Index>,
|
statements: Vec<Index>,
|
||||||
|
|
@ -335,178 +332,287 @@ impl Ast {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionDecl {
|
struct FunctionDecl {
|
||||||
attrs: Option<Index>,
|
attrs: Option<Index>,
|
||||||
name: String,
|
name: String,
|
||||||
visibility: Visibility,
|
visibility: Visibility,
|
||||||
return_type: Type,
|
return_type: Type,
|
||||||
parameter_list: ParameterList,
|
parameter_list: Option<ParameterList>,
|
||||||
body: Index,
|
body: Index,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Parameter {
|
struct Parameter {
|
||||||
mutable: bool,
|
mutable: bool,
|
||||||
name: String,
|
name: String,
|
||||||
param_type: Type,
|
param_type: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParameterList {
|
struct ParameterList {
|
||||||
parameters: Vec<Index>,
|
parameters: Vec<Index>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse() {
|
#[derive(Debug)]
|
||||||
todo!()
|
struct ExtraToken<'a> {
|
||||||
|
lexeme: &'a str,
|
||||||
|
offset: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SpannedToken<'a> {
|
pomelo! {
|
||||||
token: Token<'a>,
|
%include {
|
||||||
span: std::ops::Range<usize>,
|
use super::AstNode;
|
||||||
}
|
use internment::Intern;
|
||||||
|
use super::{
|
||||||
|
Parameter, Ast, ParameterList, FunctionDecl, Type, InnerType,
|
||||||
|
FloatType, ExtraToken, Index, IntSize, Visibility, Value,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
%extra_argument Ast;
|
||||||
|
%parser pub struct Parser<'a>{};
|
||||||
|
%token #[derive(Debug)] pub enum Token<'a> {};
|
||||||
|
|
||||||
#[derive(Clone)]
|
%type Ident &'a str;
|
||||||
struct SpannedTokenInput<'a> {
|
%type DocComment &'a str;
|
||||||
inner: TokenItemIterator<'a>,
|
%type Comment &'a str;
|
||||||
}
|
%type fn_decl FunctionDecl;
|
||||||
|
%type parameter Parameter;
|
||||||
|
%type parameter_list ParameterList;
|
||||||
|
%type typ Type;
|
||||||
|
%type return_type Type;
|
||||||
|
%type block Index;
|
||||||
|
%type decl Index;
|
||||||
|
%type decl_list Vec<Index>;
|
||||||
|
%type file Index;
|
||||||
|
|
||||||
impl<'a> Iterator for SpannedTokenInput<'a> {
|
file ::= decl_list?(list) {
|
||||||
type Item = (Token<'a>, Range<u32>);
|
let decls = list.unwrap_or_default();
|
||||||
|
extra.push(AstNode::File { decls })
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
};
|
||||||
self.inner.next().map(|item| (item.token, item.span))
|
decl_list ::= decl(decl) { vec![decl] };
|
||||||
}
|
decl_list ::= decl_list(dl) decl(decl) {
|
||||||
}
|
let mut list = dl;
|
||||||
|
list.push(decl);
|
||||||
type TokenInput<'a> = IterInput<SpannedTokenInput<'a>, Range<u32>>;
|
list
|
||||||
|
|
||||||
fn new_token_input<'a>(input: &'a str) -> TokenInput<'a> {
|
|
||||||
let num_bytes = input.len() as u32;
|
|
||||||
let token_iter = TokenIterator::new(input).into_token_items();
|
|
||||||
let spanned_input = SpannedTokenInput { inner: token_iter };
|
|
||||||
IterInput::new(spanned_input, num_bytes..num_bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn type_parser<'a, E>() -> impl Parser<'a, TokenInput<'a>, Type, E>
|
|
||||||
where
|
|
||||||
E: chumsky::extra::ParserExtra<'a, TokenInput<'a>> + 'a,
|
|
||||||
{
|
|
||||||
let primitives = select! {
|
|
||||||
Token::Void => InnerType::Unit,
|
|
||||||
Token::F32 => InnerType::Float { float_type: FloatType::F32 },
|
|
||||||
Token::F64 => InnerType::Float { float_type: FloatType::F64 },
|
|
||||||
Token::Bool => InnerType::Bool,
|
|
||||||
Token::U1 => InnerType::Int { signed: false, size: IntSize::Bits(1) },
|
|
||||||
Token::U8 => InnerType::Int { signed: false, size: IntSize::Bits(8) },
|
|
||||||
Token::U16 => InnerType::Int { signed: false, size: IntSize::Bits(16) },
|
|
||||||
Token::U32 => InnerType::Int { signed: false, size: IntSize::Bits(32) },
|
|
||||||
Token::U64 => InnerType::Int { signed: false, size: IntSize::Bits(64) },
|
|
||||||
Token::USize => InnerType::Int { signed: false, size: IntSize::Pointer },
|
|
||||||
Token::I8 => InnerType::Int { signed: true, size: IntSize::Bits(8) },
|
|
||||||
Token::I16 => InnerType::Int { signed: true, size: IntSize::Bits(16) },
|
|
||||||
Token::I32 => InnerType::Int { signed: true, size: IntSize::Bits(32) },
|
|
||||||
Token::I64 => InnerType::Int { signed: true, size: IntSize::Bits(64) },
|
|
||||||
Token::ISize => InnerType::Int { signed: true, size: IntSize::Pointer },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let custom_int_inner = choice((just::<_, _, extra::Default>('u'), just('i')))
|
%type attrs Index;
|
||||||
.then(text::int(10).to_slice().from_str::<u16>().unwrapped())
|
attrs ::= DocComment(text) {
|
||||||
.map(|(sign, size)| InnerType::Int {
|
let idx = extra.push(AstNode::Doc { text: text.to_string() });
|
||||||
signed: sign == 'i',
|
extra.push(AstNode::Attributes { attrs: vec![idx] })
|
||||||
size: IntSize::Bits(size),
|
};
|
||||||
});
|
|
||||||
|
|
||||||
let custom_int =
|
typ ::= Bool { Intern::new(InnerType::Bool) };
|
||||||
select! {Token::Ident(ident) => ident}.map(move |s| custom_int_inner.parse(s).unwrap());
|
typ ::= I1 { Intern::new(InnerType::Int { signed: true, size: IntSize::Bits(1) }) };
|
||||||
|
typ ::= I8 { Intern::new(InnerType::Int { signed: true, size: IntSize::Bits(8) }) };
|
||||||
|
typ ::= I16 { Intern::new(InnerType::Int { signed: true, size: IntSize::Bits(16) }) };
|
||||||
|
typ ::= I32 { Intern::new(InnerType::Int { signed: true, size: IntSize::Bits(32) }) };
|
||||||
|
typ ::= I64 { Intern::new(InnerType::Int { signed: true, size: IntSize::Bits(64) }) };
|
||||||
|
typ ::= U1 { Intern::new(InnerType::Int { signed: false, size: IntSize::Bits(1) }) };
|
||||||
|
typ ::= U8 { Intern::new(InnerType::Int { signed: false, size: IntSize::Bits(8) }) };
|
||||||
|
typ ::= U16 { Intern::new(InnerType::Int { signed: false, size: IntSize::Bits(16) }) };
|
||||||
|
typ ::= U32 { Intern::new(InnerType::Int { signed: false, size: IntSize::Bits(32) }) };
|
||||||
|
typ ::= U64 { Intern::new(InnerType::Int { signed: false, size: IntSize::Bits(64) }) };
|
||||||
|
typ ::= ISize { Intern::new(InnerType::Int { signed: true, size: IntSize::Pointer }) };
|
||||||
|
typ ::= USize { Intern::new(InnerType::Int { signed: false, size: IntSize::Pointer }) };
|
||||||
|
typ ::= F32 { Intern::new(InnerType::Float { float_type: FloatType::F32 }) };
|
||||||
|
typ ::= F64 { Intern::new(InnerType::Float { float_type: FloatType::F64 }) };
|
||||||
|
typ ::= Bang { Intern::new(InnerType::Bottom) };
|
||||||
|
typ ::= unit { Intern::new(InnerType::Unit) };
|
||||||
|
typ ::= Void { Intern::new(InnerType::Unit) };
|
||||||
|
|
||||||
recursive(|ty| {
|
unit ::= LParen RParen;
|
||||||
let pointer = just(Token::Star)
|
|
||||||
.ignore_then(choice((
|
|
||||||
just(Token::Mutable).to(true),
|
|
||||||
just(Token::Const).to(false),
|
|
||||||
)))
|
|
||||||
.then(ty)
|
|
||||||
.map(|(_mutable, pointee)| InnerType::Pointer { pointee });
|
|
||||||
|
|
||||||
choice((primitives, custom_int, pointer)).map(|p| Intern::new(p))
|
%type immediate (Intern<Value>, Type);
|
||||||
})
|
immediate ::= unit { (Intern::new(Value::Unit), Intern::new(InnerType::Unit)) };
|
||||||
}
|
immediate ::= False { (Intern::new(Value::Bool(false)), Intern::new(InnerType::Bool)) };
|
||||||
|
immediate ::= True { (Intern::new(Value::Bool(true)), Intern::new(InnerType::Bool)) };
|
||||||
|
%type Constant lexer::Token<'a>;
|
||||||
|
immediate ::= Constant(token) {
|
||||||
|
crate::constants::parse_constant(token)
|
||||||
|
};
|
||||||
|
|
||||||
fn visibility<'a>() -> impl Parser<'a, TokenInput<'a>, Visibility, ParserExtra> {
|
%type expr Index;
|
||||||
choice((just(Token::Pub).to(Visibility::Public),))
|
%type stmt Index;
|
||||||
.or_not()
|
%type stmts Vec<Index>;
|
||||||
.map(|v| v.unwrap_or(Visibility::Private))
|
expr ::= immediate((value, ty)) {
|
||||||
}
|
extra.push(AstNode::Constant { ty, value })
|
||||||
|
};
|
||||||
|
stmt ::= Semi { extra.push(AstNode::NoopExpr) };
|
||||||
|
stmt ::= Comment(text) { extra.push(AstNode::Comment { text: text.to_string() }) };
|
||||||
|
stmt ::= expr(expr) Semi { extra.push(AstNode::Stmt { expr }) };
|
||||||
|
|
||||||
fn func_parser() {
|
stmts ::= stmt(s) { vec![s] };
|
||||||
let ident = select! {Token::Ident(ident) => ident};
|
stmts ::= stmts(ss) stmt(s) {
|
||||||
|
let mut v = ss;
|
||||||
|
v.push(s);
|
||||||
|
v
|
||||||
|
};
|
||||||
|
|
||||||
let param = just(Token::Mutable)
|
%type block_inner (Vec<Index>, Option<Index>);
|
||||||
.to(())
|
block_inner ::= {(vec![], None)};
|
||||||
.or_not()
|
block_inner ::= expr(expr) {(vec![], Some(expr))};
|
||||||
.then(ident)
|
block_inner ::= stmts(ss) {(ss, None)};
|
||||||
.then_ignore(just(Token::Colon))
|
block_inner ::= stmts(ss) expr(expr) {(ss, Some(expr))};
|
||||||
.then(type_parser::<ParserExtra>())
|
|
||||||
.map_with(|((mutable, name), param_type), e| {
|
|
||||||
e.state().push(AstNode::Parameter(Parameter {
|
|
||||||
mutable: mutable.is_some(),
|
|
||||||
name: name.to_string(),
|
|
||||||
param_type,
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
let params = param
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.delimited_by(just(Token::OpenParens), just(Token::CloseParens))
|
|
||||||
.labelled("function parameters")
|
|
||||||
.map(|params| ParameterList { parameters: params });
|
|
||||||
|
|
||||||
let func = visibility()
|
block ::= LBrace block_inner((ss, expr)) RBrace {
|
||||||
.then_ignore(just(Token::Fn))
|
extra.push(AstNode::Block {
|
||||||
.then(ident)
|
statements: ss,
|
||||||
.then(params)
|
expr
|
||||||
// optional return type
|
|
||||||
.then(
|
|
||||||
just(Token::MinusGreater)
|
|
||||||
.ignore_then(type_parser())
|
|
||||||
.or_not(),
|
|
||||||
)
|
|
||||||
.then(block())
|
|
||||||
.map_with(|((((vis, ident), params), ret), body), e| {
|
|
||||||
e.state().push(AstNode::FunctionDecl(FunctionDecl {
|
|
||||||
attrs: None,
|
|
||||||
name: ident.to_string(),
|
|
||||||
visibility: vis,
|
|
||||||
return_type: ret.unwrap_or_else(|| Intern::new(InnerType::Unit)),
|
|
||||||
parameter_list: params,
|
|
||||||
body,
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
type ParserExtra = chumsky::extra::Full<EmptyErr, SimpleState<Ast>, ()>;
|
|
||||||
|
|
||||||
fn block<'a>() -> impl Parser<'a, TokenInput<'a>, Index, ParserExtra> {
|
|
||||||
just(Token::OpenBrace)
|
|
||||||
.ignored()
|
|
||||||
.then_ignore(just(Token::CloseBrace))
|
|
||||||
.map_with(|_, e: &mut MapExtra<'_, '_, _, ParserExtra>| {
|
|
||||||
e.state().push(AstNode::Block {
|
|
||||||
statements: vec![],
|
|
||||||
expr: None,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
%type vis Visibility;
|
||||||
|
vis ::= Pub { Visibility::Public };
|
||||||
|
|
||||||
|
%type mutable bool;
|
||||||
|
mutable ::= Mutable { true };
|
||||||
|
mutable ::= { false };
|
||||||
|
|
||||||
|
return_type ::= Arrow typ(return_type) { return_type };
|
||||||
|
parameter ::= mutable(mutable) Ident(name) Colon typ(param_type) {
|
||||||
|
Parameter { mutable, name: name.to_string(), param_type }
|
||||||
|
};
|
||||||
|
parameter_list ::= parameter(p) {
|
||||||
|
let idx = extra.push(AstNode::Parameter { name: p.name, param_type: p.param_type });
|
||||||
|
ParameterList { parameters: vec![idx] }
|
||||||
|
};
|
||||||
|
parameter_list ::= parameter_list(pl) Comma parameter(p) {
|
||||||
|
let idx = extra.push(AstNode::Parameter { name: p.name, param_type: p.param_type });
|
||||||
|
let mut parameters = pl.parameters;
|
||||||
|
parameters.push(idx);
|
||||||
|
ParameterList { parameters }
|
||||||
|
};
|
||||||
|
parameter_list ::= parameter_list(pl) Comma {
|
||||||
|
pl
|
||||||
|
};
|
||||||
|
|
||||||
|
decl ::= Comment(text) { extra.push(AstNode::Comment { text: text.to_string() }) };
|
||||||
|
decl ::= fn_decl(f) { extra.push(AstNode::FunctionDecl(f)) };
|
||||||
|
fn_decl ::= attrs?(attrs) vis?(visibility) Fn Ident(name) LParen parameter_list?(parameters) RParen return_type(rtype) block(body) {
|
||||||
|
let name = name.to_string();
|
||||||
|
FunctionDecl {
|
||||||
|
attrs,
|
||||||
|
name,
|
||||||
|
visibility: visibility.unwrap_or_default(),
|
||||||
|
return_type: rtype,
|
||||||
|
parameter_list: parameters,
|
||||||
|
body,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<lexer::Token<'a>> for parser::Token<'a> {
|
||||||
|
fn from(value: lexer::Token<'a>) -> Self {
|
||||||
|
use lexer::Token;
|
||||||
|
match value {
|
||||||
|
Token::Fn => Self::Fn,
|
||||||
|
Token::OpenParens => Self::LParen,
|
||||||
|
Token::CloseParens => Self::RParen,
|
||||||
|
Token::OpenBrace => Self::LBrace,
|
||||||
|
Token::CloseBrace => Self::RBrace,
|
||||||
|
Token::Ident(ident) => Self::Ident(ident),
|
||||||
|
Token::Comment(text) => Self::Comment(text),
|
||||||
|
Token::DocComment(text) => Self::DocComment(text),
|
||||||
|
Token::OpenSquareBracket => todo!(), // Self::LBracket,
|
||||||
|
Token::CloseSquareBracket => todo!(), // Self::RBracket,
|
||||||
|
Token::Comma => Self::Comma,
|
||||||
|
Token::Colon => Self::Colon,
|
||||||
|
Token::Semi => Self::Semi,
|
||||||
|
Token::Elipsis3 => todo!(),
|
||||||
|
Token::Elipsis2 => todo!(),
|
||||||
|
Token::Equal => todo!(),
|
||||||
|
Token::Void => Self::Void,
|
||||||
|
Token::Bool => Self::Bool,
|
||||||
|
Token::F32 => Self::F32,
|
||||||
|
Token::F64 => Self::F64,
|
||||||
|
Token::ISize => Self::ISize,
|
||||||
|
Token::USize => Self::USize,
|
||||||
|
Token::U1 => Self::U1,
|
||||||
|
Token::U8 => Self::U8,
|
||||||
|
Token::U16 => Self::U16,
|
||||||
|
Token::U32 => Self::U32,
|
||||||
|
Token::U64 => Self::U64,
|
||||||
|
Token::I1 => Self::I1,
|
||||||
|
Token::I8 => Self::I8,
|
||||||
|
Token::I16 => Self::I16,
|
||||||
|
Token::I32 => Self::I32,
|
||||||
|
Token::I64 => Self::I64,
|
||||||
|
Token::True => Self::True,
|
||||||
|
Token::False => Self::False,
|
||||||
|
Token::Const => todo!(), // Self::Const,
|
||||||
|
Token::Mutable => Self::Mutable,
|
||||||
|
Token::Volatile => todo!(),
|
||||||
|
Token::Noalias => todo!(),
|
||||||
|
Token::Let => todo!(),
|
||||||
|
Token::Var => todo!(),
|
||||||
|
Token::If => todo!(),
|
||||||
|
Token::As => todo!(),
|
||||||
|
Token::Else => todo!(),
|
||||||
|
Token::Return => todo!(),
|
||||||
|
Token::Struct => todo!(),
|
||||||
|
Token::Type => todo!(),
|
||||||
|
Token::Union => todo!(),
|
||||||
|
Token::Enum => todo!(),
|
||||||
|
Token::Packed => todo!(),
|
||||||
|
Token::Extern => todo!(),
|
||||||
|
Token::Pub => Self::Pub,
|
||||||
|
Token::Module => todo!(),
|
||||||
|
Token::Dot => todo!(),
|
||||||
|
Token::MinusGreater => Self::Arrow,
|
||||||
|
Token::Bang => Self::Bang,
|
||||||
|
Token::Tilde => todo!(),
|
||||||
|
Token::Plus => todo!(),
|
||||||
|
Token::Minus => todo!(),
|
||||||
|
Token::Star => todo!(),
|
||||||
|
Token::Slash => todo!(),
|
||||||
|
Token::Percent => todo!(),
|
||||||
|
Token::Less => todo!(),
|
||||||
|
Token::Greater => todo!(),
|
||||||
|
Token::LessEqual => todo!(),
|
||||||
|
Token::GreaterEqual => todo!(),
|
||||||
|
Token::EqualEqual => todo!(),
|
||||||
|
Token::BangEqual => todo!(),
|
||||||
|
Token::PipePipe => todo!(),
|
||||||
|
Token::AmpersandAmpersand => todo!(),
|
||||||
|
Token::Ampersand => todo!(),
|
||||||
|
Token::Caret => todo!(),
|
||||||
|
Token::Pipe => todo!(),
|
||||||
|
Token::LessLess => todo!(),
|
||||||
|
Token::GreaterGreater => todo!(),
|
||||||
|
Token::Question => todo!(),
|
||||||
|
Token::PlusEqual => todo!(),
|
||||||
|
Token::MinusEqual => todo!(),
|
||||||
|
Token::StarEqual => todo!(),
|
||||||
|
Token::SlashEqual => todo!(),
|
||||||
|
Token::PercentEqual => todo!(),
|
||||||
|
Token::AmpersandEqual => todo!(),
|
||||||
|
Token::PipeEqual => todo!(),
|
||||||
|
Token::CaretEqual => todo!(),
|
||||||
|
Token::LessLessEqual => todo!(),
|
||||||
|
Token::GreaterGreaterEqual => todo!(),
|
||||||
|
Token::Eof(_) => todo!(),
|
||||||
|
Token::ParseError(_) => todo!(),
|
||||||
|
Token::CharConstant(_) => todo!(),
|
||||||
|
Token::IntegerConstant(_) => Self::Constant(value),
|
||||||
|
Token::IntegerHexConstant(_) => Self::Constant(value),
|
||||||
|
Token::IntegerBinConstant(_) => Self::Constant(value),
|
||||||
|
Token::IntegerOctConstant(_) => Self::Constant(value),
|
||||||
|
Token::FloatingConstant(_) => Self::Constant(value),
|
||||||
|
Token::FloatingExpConstant(_) => Self::Constant(value),
|
||||||
|
Token::DotFloatingConstant(_) => Self::Constant(value),
|
||||||
|
Token::DotFloatingExpConstant(_) => Self::Constant(value),
|
||||||
|
Token::StringConstant(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod constants;
|
mod constants;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use chumsky::Parser;
|
use crate::AstNode;
|
||||||
|
|
||||||
use crate::{AstNode, new_token_input, type_parser};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn print_ast_node_size() {
|
fn print_ast_node_size() {
|
||||||
|
|
@ -514,55 +620,46 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_types() {
|
fn parse_constant() {
|
||||||
let ty = type_parser::<chumsky::extra::Default>()
|
use crate::parser::{Parser, Token};
|
||||||
.parse(new_token_input("i32"))
|
let input = r#"
|
||||||
.unwrap();
|
fn a() -> u32 {
|
||||||
assert_eq!(
|
42u32
|
||||||
*ty,
|
}
|
||||||
crate::InnerType::Int {
|
fn b() -> u32 {
|
||||||
signed: true,
|
42i8
|
||||||
size: crate::IntSize::Bits(32)
|
}
|
||||||
}
|
fn c() -> f32 {
|
||||||
);
|
42e4
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let mut lex = lexer::TokenIterator::new(input);
|
||||||
|
let mut mapped = lex.map(Token::from);
|
||||||
|
let mut ast = crate::Ast::new();
|
||||||
|
let mut parser = Parser::new(ast);
|
||||||
|
while let Some(token) = mapped.next() {
|
||||||
|
parser.parse(token).unwrap();
|
||||||
|
}
|
||||||
|
let (out, ast) = parser.end_of_input().unwrap();
|
||||||
|
eprintln!("AST: {:#?}", ast);
|
||||||
|
}
|
||||||
|
|
||||||
let ty = type_parser::<chumsky::extra::Default>()
|
#[test]
|
||||||
.parse(new_token_input("*const i32"))
|
fn parse() {
|
||||||
.unwrap();
|
use crate::parser::{Parser, Token};
|
||||||
assert_eq!(
|
let input = r#"
|
||||||
*ty,
|
// A simple test case
|
||||||
crate::InnerType::Pointer {
|
/// A function that takes two u32 parameters and returns a u32
|
||||||
pointee: crate::Intern::new(crate::InnerType::Int {
|
fn main(a: u32, b: u32) -> u32 {}
|
||||||
signed: true,
|
"#;
|
||||||
size: crate::IntSize::Bits(32)
|
let mut lex = lexer::TokenIterator::new(input);
|
||||||
})
|
let mut mapped = lex.map(Token::from);
|
||||||
}
|
let mut ast = crate::Ast::new();
|
||||||
);
|
let mut parser = Parser::new(ast);
|
||||||
|
while let Some(token) = mapped.next() {
|
||||||
let ty = type_parser::<chumsky::extra::Default>()
|
parser.parse(token).unwrap();
|
||||||
.parse(new_token_input("*mut *const u8"))
|
}
|
||||||
.unwrap();
|
let (out, ast) = parser.end_of_input().unwrap();
|
||||||
assert_eq!(
|
eprintln!("AST: {:#?}", ast);
|
||||||
*ty,
|
|
||||||
crate::InnerType::Pointer {
|
|
||||||
pointee: crate::Intern::new(crate::InnerType::Pointer {
|
|
||||||
pointee: crate::Intern::new(crate::InnerType::Int {
|
|
||||||
signed: false,
|
|
||||||
size: crate::IntSize::Bits(8)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let ty = type_parser::<chumsky::extra::Default>()
|
|
||||||
.parse(new_token_input("i10"))
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
*ty,
|
|
||||||
crate::InnerType::Int {
|
|
||||||
signed: true,
|
|
||||||
size: crate::IntSize::Bits(10)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue