use crate::lexer::Token;
use typed_arena::Arena;
pub use crate::parser::ast::*;
#[derive(Debug, Clone)]
pub struct ParseWarning {
pub message: String,
pub file: Option<String>,
pub line: Option<usize>,
pub column: Option<usize>,
pub is_error: bool,
}
pub struct Parser {
pub(crate) tokens: Vec<crate::lexer::TokenWithLocation>,
pub(crate) position: usize,
pub(crate) filename: String,
#[allow(dead_code)]
pub(crate) source: String,
pub(crate) warnings: Vec<ParseWarning>,
pub(crate) in_extern_fn: bool,
pub(crate) expr_arena: Arena<Expression<'static>>,
pub(crate) stmt_arena: Arena<Statement<'static>>,
pub(crate) pattern_arena: Arena<Pattern<'static>>,
}
impl Parser {
pub(crate) fn had_newline_before_current(&self) -> bool {
if self.position == 0 {
return false; }
let prev_token = self.tokens.get(self.position - 1);
let curr_token = self.tokens.get(self.position);
match (prev_token, curr_token) {
(Some(prev), Some(curr)) => {
curr.line > prev.line
}
_ => false,
}
}
pub fn new(tokens: Vec<crate::lexer::TokenWithLocation>) -> Self {
Parser {
tokens,
position: 0,
filename: String::new(),
source: String::new(),
warnings: Vec::new(),
in_extern_fn: false,
expr_arena: Arena::new(),
stmt_arena: Arena::new(),
pattern_arena: Arena::new(),
}
}
pub fn new_with_source(
tokens: Vec<crate::lexer::TokenWithLocation>,
filename: String,
source: String,
) -> Self {
Parser {
tokens,
position: 0,
filename,
source,
warnings: Vec::new(),
in_extern_fn: false,
expr_arena: Arena::new(),
stmt_arena: Arena::new(),
pattern_arena: Arena::new(),
}
}
pub fn warnings(&self) -> &[ParseWarning] {
&self.warnings
}
pub(crate) fn emit_warning(
&mut self,
message: String,
file: Option<String>,
line: Option<usize>,
column: Option<usize>,
) {
self.warnings.push(ParseWarning {
message,
file,
line,
column,
is_error: false,
});
}
pub(crate) fn emit_error_diagnostic(
&mut self,
message: String,
file: Option<String>,
line: Option<usize>,
column: Option<usize>,
) {
self.warnings.push(ParseWarning {
message,
file,
line,
column,
is_error: true,
});
}
pub(crate) fn alloc_expr<'ast>(&self, expr: Expression<'static>) -> &'ast Expression<'ast> {
unsafe {
let ptr = self.expr_arena.alloc(expr);
std::mem::transmute(ptr)
}
}
pub(crate) fn alloc_stmt<'ast>(&self, stmt: Statement<'static>) -> &'ast Statement<'ast> {
unsafe {
let ptr = self.stmt_arena.alloc(stmt);
std::mem::transmute(ptr)
}
}
pub(crate) fn alloc_pattern<'ast>(&self, pattern: Pattern<'static>) -> &'ast Pattern<'ast> {
unsafe {
let ptr = self.pattern_arena.alloc(pattern);
std::mem::transmute(ptr)
}
}
pub(crate) fn current_token(&self) -> &Token {
self.tokens
.get(self.position)
.map(|t| &t.token)
.unwrap_or(&Token::Eof)
}
pub(crate) fn current_location(&self) -> Option<crate::source_map::Location> {
self.tokens
.get(self.position)
.map(|t| crate::source_map::Location {
file: std::path::PathBuf::from(&self.filename),
line: t.line,
column: t.column,
})
}
pub(crate) fn advance(&mut self) {
if self.position < self.tokens.len() {
self.position += 1;
}
}
pub(crate) fn expect(&mut self, expected: Token) -> Result<(), String> {
if self.current_token() == &expected {
self.advance();
Ok(())
} else {
Err(format!(
"Expected {:?}, got {:?} (at token position {})",
expected,
self.current_token(),
self.position
))
}
}
pub(crate) fn expect_gt_or_split_shr(&mut self) -> Result<bool, String> {
match self.current_token() {
Token::Gt => {
self.advance();
Ok(false) }
Token::Shr => {
let current_location = self.tokens[self.position].clone();
let mut gt_token = current_location.clone();
gt_token.token = Token::Gt;
self.tokens[self.position] = gt_token.clone();
self.tokens.insert(self.position + 1, gt_token);
self.advance();
Ok(true) }
_ => Err(format!(
"Expected '>' or '>>', got {:?} (at token position {})",
self.current_token(),
self.position
)),
}
}
pub fn parse(&mut self) -> Result<Program<'static>, String> {
let mut items = Vec::new();
while self.current_token() != &Token::Eof {
items.push(self.parse_item()?);
}
Ok(Program { items })
}
pub(crate) fn parse_item(&mut self) -> Result<Item<'static>, String> {
while matches!(self.current_token(), Token::Newline) {
self.advance();
}
let mut doc_lines = Vec::new();
while let Token::DocComment(content) = self.current_token() {
doc_lines.push(content.clone());
self.advance();
}
let mut doc_comment = if doc_lines.is_empty() {
None
} else {
Some(doc_lines.join("\n"))
};
while matches!(self.current_token(), Token::Newline) {
self.advance();
}
let mut decorators = Vec::new();
while let Token::Decorator(_) = self.current_token() {
decorators.push(self.parse_decorator()?);
}
while matches!(self.current_token(), Token::Newline) {
self.advance();
}
let mut doc_lines_after = Vec::new();
while let Token::DocComment(content) = self.current_token() {
doc_lines_after.push(content.clone());
self.advance();
}
if !doc_lines_after.is_empty() {
doc_comment = Some(doc_lines_after.join("\n"));
}
while matches!(self.current_token(), Token::Newline) {
self.advance();
}
let is_pub = if self.current_token() == &Token::Pub {
self.advance();
true
} else {
false
};
match self.current_token() {
Token::Fn => {
self.advance(); let mut func = self.parse_function()?;
func.decorators = decorators.clone();
func.is_pub = is_pub;
func.doc_comment = doc_comment;
if decorators.iter().any(|d| d.name == "async") {
func.is_async = true;
}
Ok(Item::Function {
decl: func,
location: self.current_location(),
})
}
Token::Async => {
self.advance();
self.expect(Token::Fn)?;
let mut func = self.parse_function()?;
func.is_async = true;
func.is_pub = is_pub;
func.decorators = decorators;
func.doc_comment = doc_comment;
Ok(Item::Function {
decl: func,
location: self.current_location(),
})
}
Token::Struct => {
self.advance();
let mut struct_decl = self.parse_struct(false)?;
struct_decl.decorators = decorators;
struct_decl.is_pub = is_pub;
struct_decl.doc_comment = doc_comment;
Ok(Item::Struct {
decl: struct_decl,
location: self.current_location(),
})
}
Token::Enum => {
self.advance();
let mut enum_decl = self.parse_enum()?;
enum_decl.is_pub = is_pub;
enum_decl.doc_comment = doc_comment;
Ok(Item::Enum {
decl: enum_decl,
location: self.current_location(),
})
}
Token::Trait => {
self.advance();
let mut trait_decl = self.parse_trait()?;
trait_decl.doc_comment = doc_comment;
Ok(Item::Trait {
decl: trait_decl,
location: self.current_location(),
})
}
Token::Impl => {
self.advance();
let mut impl_block = self.parse_impl(false)?;
impl_block.decorators = decorators;
Ok(Item::Impl {
block: impl_block,
location: self.current_location(),
})
}
Token::Const => {
self.advance();
let (name, type_, value) = self.parse_const_or_static()?;
Ok(Item::Const {
name,
is_pub,
type_,
value,
location: self.current_location(),
})
}
Token::Static => {
self.advance();
let mutable = if self.current_token() == &Token::Mut {
self.advance();
true
} else {
false
};
let (name, type_, value) = self.parse_const_or_static()?;
Ok(Item::Static {
name,
mutable,
type_,
value,
location: self.current_location(),
})
}
Token::Extern => {
if self.peek(1) == Some(&Token::Let) {
self.advance(); self.advance();
let name = if let Token::Ident(n) = self.current_token() {
let n = n.clone();
self.advance();
n
} else {
return Err("Expected variable name after extern let".to_string());
};
self.expect(Token::Colon)?;
let type_ = self.parse_type()?;
if self.current_token() == &Token::Semicolon {
self.advance();
}
Ok(Item::ExternLet {
name,
type_,
decorators,
is_pub,
location: self.current_location(),
})
} else {
self.advance(); match self.current_token() {
Token::Struct => {
self.advance();
let mut struct_decl = self.parse_struct(true)?;
struct_decl.decorators = decorators;
struct_decl.is_pub = is_pub;
struct_decl.doc_comment = doc_comment;
Ok(Item::Struct {
decl: struct_decl,
location: self.current_location(),
})
}
Token::Impl => {
self.advance();
let mut impl_block = self.parse_impl(true)?;
impl_block.decorators = decorators;
Ok(Item::Impl {
block: impl_block,
location: self.current_location(),
})
}
Token::Fn => {
self.expect(Token::Fn)?; self.in_extern_fn = true;
let mut func = self.parse_function()?;
self.in_extern_fn = false;
func.is_extern = true; func.is_pub = is_pub;
func.decorators = decorators;
func.doc_comment = doc_comment;
Ok(Item::Function {
decl: func,
location: self.current_location(),
})
}
_ => {
Err("expected `let`, `struct`, `impl`, or `fn` after `extern`"
.to_string())
}
}
}
}
Token::Use => {
self.advance(); let (path, alias) = self.parse_use()?;
if self.current_token() == &Token::Semicolon {
self.advance();
}
Ok(Item::Use {
path,
alias,
is_pub, location: self.current_location(),
})
}
Token::Bound => {
self.advance(); self.parse_bound_alias()
}
Token::Mod => {
self.advance(); let (name, items, _) = self.parse_mod()?;
Ok(Item::Mod {
name,
items,
is_public: is_pub,
location: self.current_location(),
})
}
Token::Type => {
self.advance(); let name = if let Token::Ident(n) = self.current_token() {
let name = n.clone();
self.advance();
name
} else {
return Err("Expected type alias name".to_string());
};
self.expect(Token::Assign)?;
let target = self.parse_type()?;
if self.current_token() == &Token::Semicolon {
self.advance();
}
Ok(Item::TypeAlias {
name,
target,
is_pub,
location: self.current_location(),
})
}
_ => Err(format!(
"Unexpected token: {:?} (at token position {})",
self.current_token(),
self.position
)),
}
}
fn parse_bound_alias(&mut self) -> Result<Item<'static>, String> {
let name = if let Token::Ident(n) = self.current_token() {
let name = n.clone();
self.advance();
name
} else {
return Err("Expected bound alias name".to_string());
};
self.expect(Token::Assign)?;
let mut traits = Vec::new();
loop {
if let Token::Ident(trait_name) = self.current_token() {
traits.push(trait_name.clone());
self.advance();
} else {
return Err("Expected trait name in bound alias".to_string());
}
if self.current_token() == &Token::Plus {
self.advance(); } else {
break;
}
}
Ok(Item::BoundAlias {
name,
traits,
location: self.current_location(),
})
}
pub(crate) fn parse_const_or_static(
&mut self,
) -> Result<(String, Type, &'static Expression<'static>), String> {
let name = if let Token::Ident(n) = self.current_token() {
let name = n.clone();
self.advance();
name
} else {
return Err("Expected const/static name".to_string());
};
self.expect(Token::Colon)?;
let type_ = self.parse_type()?;
self.expect(Token::Assign)?;
let value = self.parse_expression()?;
Ok((name, type_, value))
}
pub fn parse_expression_public(&mut self) -> Result<&'static Expression<'static>, String> {
self.parse_expression()
}
pub fn parse_function_public(&mut self) -> Result<FunctionDecl<'static>, String> {
self.parse_function()
}
}