Something went wrong. Try again.
An experiment in static, refcounted, procedural language with ownership
Something went wrong. Try again.
7.7 kB · 255 lines
Rust
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256use std::ops::ControlFlow;
use compiler_helpers::create_bool_enum;
use compiler_ast::{ Attr, AttrArgs, AttrId, Attrs, ExternLet, Fn, FnKind, FnParam, FnSig, Item, Let, LetKind,};use compiler_core::{ diagnostics::{Diagnostic, DiagnosticResult, Label}, middle::CallConv, span::{Span, Spanned}, word::Word,};
use crate::{ errors, parser::{Parser, RequireSigTy}, token::{Kw, Token, TokenKind},};
impl<'a> Parser<'a> { pub(super) fn parse_item(&mut self) -> DiagnosticResult<Item> { let attrs = self.parse_attrs()?;
if self.is_kw(Kw::Fn) { return self.parse_fn_item(attrs); }
if self.is_kw(Kw::Let) { return if self.is_kw(Kw::Extern) { self.parse_extern_let(attrs).map(Item::ExternLet) } else { self.parse_let(attrs, LetKind::Let, AllowVis::Yes, RequireTy::Yes).map(Item::Let) }; }
if self.is_kw(Kw::Const) { return self .parse_let(attrs, LetKind::Const, AllowVis::Yes, RequireTy::Yes) .map(Item::Let); }
if self.is_kw(Kw::Type) { return self.parse_tydef(attrs).map(Item::Type); }
if self.is_kw(Kw::Mod) { let start = self.last_span();
if self.is_kw(Kw::Extern) { return self.parse_extern_import(&attrs, start).map(Item::ExternImport); }
return self.parse_mod(&attrs).map(Item::Import); }
if self.is_kw(Kw::Use) { return self.parse_import(&attrs).map(Item::Import); }
if !attrs.is_empty() { return Err(self.unexpected_token("an item after attribute")); }
Err(self.unexpected_token("an item")) }
fn parse_fn_item(&mut self, attrs: Attrs) -> DiagnosticResult<Item> { if self.is_kw(Kw::Extern) { let fun = self.parse_extern_fn(attrs)?; return Ok(Item::Fn(fun)); }
let name = self.eat_ident()?;
if self.is(TokenKind::Dot) { let fn_name = self.eat_ident()?; let fun = self.parse_bare_fn(attrs, fn_name)?; return Ok(Item::Assoc(name.word(), Box::new(Item::Fn(fun)))); }
let fun = self.parse_bare_fn(attrs, name)?;
Ok(Item::Fn(fun)) }
fn parse_extern_fn(&mut self, attrs: Attrs) -> DiagnosticResult<Fn> { let callconv = self.parse_callconv()?; let name = self.eat_ident()?; let vis = self.parse_vis(); let (sig, is_c_variadic) = self.parse_fn_sig(name.word(), RequireSigTy::Yes)?;
Ok(Fn { attrs, vis, sig, kind: FnKind::Extern { callconv, is_c_variadic }, span: name.span, }) }
pub(super) fn parse_callconv(&mut self) -> DiagnosticResult<CallConv> { let callconv = self.eat_str_lit()?; let callconv_str = callconv.as_str(); CallConv::try_from(callconv_str).map_err(|()| { Diagnostic::error(format!("unknown calling convention `{callconv_str}`")) .with_label(Label::primary(callconv.span(), "unknown calling convention")) }) }
fn parse_bare_fn(&mut self, attrs: Attrs, name: Token) -> DiagnosticResult<Fn> { let vis = self.parse_vis(); let (sig, is_c_variadic) = self.parse_fn_sig(name.word(), RequireSigTy::Yes)?;
if is_c_variadic { return Err(errors::invalid_c_variadic(name.span)); }
self.eat(TokenKind::Eq)?; let body = self.parse_expr()?;
Ok(Fn { attrs, vis, sig, kind: FnKind::Bare { body: Box::new(body) }, span: name.span }) }
pub(super) fn parse_fn_sig( &mut self, word: Word, require_sig_ty: RequireSigTy, ) -> DiagnosticResult<(FnSig, bool)> { let tparams = self.parse_optional_tparams()?; let (params, is_c_variadic) = self.parse_fn_params(require_sig_ty)?; let ret = if require_sig_ty == RequireSigTy::Yes || self.is_ty_start() { Some(self.parse_ty()?) } else { None }; Ok((FnSig { word, tparams, params, ret }, is_c_variadic)) }
pub(super) fn parse_fn_params( &mut self, require_sig_ty: RequireSigTy, ) -> DiagnosticResult<(Vec<FnParam>, bool)> { let mut is_c_variadic = false;
let (params, _) = self.parse_list(TokenKind::OpenParen, TokenKind::CloseParen, |this| { if this.is(TokenKind::DotDot) { is_c_variadic = true; return Ok(ControlFlow::Break(())); }
let pat = this.parse_pat(IsFnParam::Yes, AllowVis::No)?;
let ty_expr = if require_sig_ty == RequireSigTy::Yes { this.eat(TokenKind::Colon)?; Some(this.parse_ty()?) } else if this.is(TokenKind::Colon) { Some(this.parse_ty()?) } else { None };
Ok(ControlFlow::Continue(FnParam { span: pat.span(), pat, ty_expr })) })?;
Ok((params, is_c_variadic)) }
fn parse_attrs(&mut self) -> DiagnosticResult<Attrs> { let mut attrs = Attrs::new();
while self.is(TokenKind::At) { let (id, span) = self.parse_attr_id()?; let args = self.parse_attr_args(id)?; self.skip_semi(); attrs.push(Attr { id, args, span }); }
Ok(attrs) }
fn parse_attr_id(&mut self) -> DiagnosticResult<(AttrId, Span)> { let start = self.last_span(); let ident = self.eat_ident()?; let span = start.merge(ident.span); let name = ident.str_value().as_str();
let id = AttrId::try_from(name).map_err(|()| { Diagnostic::error(format!("unknown attribute `{name}`")) .with_label(Label::primary(span, "unknown attribute")) })?;
Ok((id, span)) }
fn parse_attr_args(&mut self, id: AttrId) -> DiagnosticResult<AttrArgs> { match id { AttrId::Builtin => { self.eat(TokenKind::OpenParen)?; let name = self.eat_str_lit()?; self.eat(TokenKind::CloseParen)?; Ok(AttrArgs::Builtin(name)) } } }
pub(super) fn parse_let( &mut self, attrs: Attrs, kind: LetKind, allow_vis: AllowVis, require_ty: RequireTy, ) -> DiagnosticResult<Let> { let start = self.last_span(); let pat = self.parse_pat(IsFnParam::No, allow_vis)?;
let ty_expr = if self.is(TokenKind::Colon) { Some(self.parse_ty()?) } else if require_ty == RequireTy::No { None } else { return Err(self.unexpected_token(":")); };
self.eat(TokenKind::Eq)?;
let value = self.parse_expr()?;
Ok(Let { attrs, kind, pat, ty_expr, span: start.merge(value.span()), value: Box::new(value), }) }
fn parse_extern_let(&mut self, attrs: Attrs) -> DiagnosticResult<ExternLet> { let start = self.last_span();
let mutability = self.parse_mutability(); let ident = self.eat_ident()?; let vis = self.parse_vis(); self.eat(TokenKind::Colon)?; let ty_expr = self.parse_ty()?;
let span = start.merge(ty_expr.span()); Ok(ExternLet { attrs, mutability, vis, word: ident.word(), ty_expr, span }) }}
create_bool_enum!(RequireTy);create_bool_enum!(AllowVis);create_bool_enum!(IsFnParam);