use crate::ast::*;
use crate::lexeme::Lexeme;
use crate::span::Spanned;
use super::Parser;
impl Parser {
pub(super) fn parse_program(&mut self) -> File {
self.expect(&Lexeme::Program);
let name = self.expect_ident();
let uses = self.parse_uses();
let declarations = self.parse_declarations();
let items = self.parse_items();
File {
kind: FileKind::Program,
name,
uses,
declarations,
items,
}
}
pub(super) fn parse_module(&mut self) -> File {
self.expect(&Lexeme::Module);
let name = self.expect_ident();
// Module name can be dotted: `module std.hash`
let mut name_str = name.node.clone();
while self.eat(&Lexeme::Dot) {
let part = self.expect_ident();
name_str.push('.');
name_str.push_str(&part.node);
}
let name = Spanned::new(name_str, name.span);
let uses = self.parse_uses();
let items = self.parse_items();
File {
kind: FileKind::Module,
name,
uses,
declarations: Vec::new(),
items,
}
}
fn parse_declarations(&mut self) -> Vec<Declaration> {
let mut decls = Vec::new();
loop {
if self.at(&Lexeme::Pub) && self.is_declaration_ahead() {
self.advance(); // consume pub
let kind_name = self.expect_ident();
self.expect(&Lexeme::Colon);
let ty = self.parse_type();
match kind_name.node.as_str() {
"input" => decls.push(Declaration::PubInput(ty)),
"output" => decls.push(Declaration::PubOutput(ty)),
_ => {}
}
} else if self.at(&Lexeme::Sec) && self.is_sec_declaration_ahead() {
self.advance(); // consume sec
let kind_name = self.expect_ident();
self.expect(&Lexeme::Colon);
if kind_name.node == "input" {
let ty = self.parse_type();
decls.push(Declaration::SecInput(ty));
} else if kind_name.node == "ram" {
// sec ram: { addr: Type, addr: Type, ... }
self.expect(&Lexeme::LBrace);
let mut entries = Vec::new();
while !self.at(&Lexeme::RBrace) && !self.at(&Lexeme::Eof) {
// Parse address (integer literal)
let addr_tok = self.advance();
let addr = if let Lexeme::Integer(n) = &addr_tok.node {
*n
} else {
0 // error recovery
};
self.expect(&Lexeme::Colon);
let ty = self.parse_type();
entries.push((addr, ty));
// Optional comma
if self.at(&Lexeme::Comma) {
self.advance();
}
}
self.expect(&Lexeme::RBrace);
decls.push(Declaration::SecRam(entries));
}
} else {
break;
}
}
decls
}
/// Check if `pub` is followed by `input` or `output` (declaration, not item).
fn is_declaration_ahead(&self) -> bool {
if self.pos + 1 >= self.tokens.len() {
return false;
}
match &self.tokens[self.pos + 1].node {
Lexeme::Ident(name) => name == "input" || name == "output",
_ => false,
}
}
/// Check if `sec` is followed by `input` or `ram`.
fn is_sec_declaration_ahead(&self) -> bool {
if self.pos + 1 >= self.tokens.len() {
return false;
}
match &self.tokens[self.pos + 1].node {
Lexeme::Ident(name) => name == "input" || name == "ram",
_ => false,
}
}
fn parse_uses(&mut self) -> Vec<Spanned<ModulePath>> {
let mut uses = Vec::new();
while self.at(&Lexeme::Use) {
let start = self.current_span();
self.advance();
let path = self.parse_module_path();
let span = start.merge(self.prev_span());
uses.push(Spanned::new(path, span));
}
uses
}
pub(super) fn parse_items(&mut self) -> Vec<Spanned<Item>> {
let mut items = Vec::new();
while !self.at(&Lexeme::Eof) {
let start = self.current_span();
// Parse attributes: #[cfg(flag)], #[intrinsic(name)], #[test],
// #[requires(pred)], #[ensures(pred)]
let mut cfg_attr: Option<Spanned<String>> = None;
let mut intrinsic_attr: Option<Spanned<String>> = None;
let mut is_test = false;
let mut is_pure = false;
let mut requires_attrs: Vec<Spanned<String>> = Vec::new();
let mut ensures_attrs: Vec<Spanned<String>> = Vec::new();
while self.at(&Lexeme::Hash) {
let attr = self.parse_attribute();
if attr.node.starts_with("cfg(") {
// Extract flag name from "cfg(flag)"
let flag = attr.node[4..attr.node.len() - 1].to_string();
cfg_attr = Some(Spanned::new(flag, attr.span));
} else if attr.node.starts_with("intrinsic(") {
intrinsic_attr = Some(attr);
} else if attr.node.starts_with("requires(") {
let pred = attr.node[9..attr.node.len() - 1].to_string();
requires_attrs.push(Spanned::new(pred, attr.span));
} else if attr.node.starts_with("ensures(") {
let pred = attr.node[8..attr.node.len() - 1].to_string();
ensures_attrs.push(Spanned::new(pred, attr.span));
} else if attr.node == "test" {
is_test = true;
} else if attr.node == "pure" {
is_pure = true;
} else {
self.error_at_current(
"unknown attribute; expected cfg, intrinsic, test, pure, requires, or ensures",
);
}
}
let is_pub = self.eat(&Lexeme::Pub);
if self.at(&Lexeme::Const) {
self.reject_fn_only_attrs(
&intrinsic_attr,
is_test,
is_pure,
&requires_attrs,
&ensures_attrs,
);
let item = self.parse_const(is_pub, cfg_attr);
let span = start.merge(self.prev_span());
items.push(Spanned::new(Item::Const(item), span));
} else if self.at(&Lexeme::Struct) {
self.reject_fn_only_attrs(
&intrinsic_attr,
is_test,
is_pure,
&requires_attrs,
&ensures_attrs,
);
let item = self.parse_struct(is_pub, cfg_attr);
let span = start.merge(self.prev_span());
items.push(Spanned::new(Item::Struct(item), span));
} else if self.at(&Lexeme::Event) {
self.reject_fn_only_attrs(
&intrinsic_attr,
is_test,
is_pure,
&requires_attrs,
&ensures_attrs,
);
let item = self.parse_event(cfg_attr);
let span = start.merge(self.prev_span());
items.push(Spanned::new(Item::Event(item), span));
} else if self.at(&Lexeme::Fn) || self.at(&Lexeme::Hash) {
let item = self.parse_fn_with_attr(
is_pub,
cfg_attr,
intrinsic_attr,
is_test,
is_pure,
requires_attrs,
ensures_attrs,
);
let span = start.merge(self.prev_span());
items.push(Spanned::new(Item::Fn(item), span));
} else {
self.error_with_help(
"expected item (fn, struct, event, or const)",
"top-level items must be function, struct, event, or const definitions",
);
self.advance(); // skip to recover
}
}
items
}
fn reject_fn_only_attrs(
&mut self,
intrinsic: &Option<Spanned<String>>,
is_test: bool,
is_pure: bool,
requires: &[Spanned<String>],
ensures: &[Spanned<String>],
) {
if intrinsic.is_some() {
self.error_at_current("#[intrinsic] is only allowed on functions");
}
if is_test {
self.error_at_current("#[test] is only allowed on functions");
}
if is_pure {
self.error_at_current("#[pure] is only allowed on functions");
}
if !requires.is_empty() || !ensures.is_empty() {
self.error_at_current("#[requires] and #[ensures] are only allowed on functions");
}
}
fn parse_const(&mut self, is_pub: bool, cfg: Option<Spanned<String>>) -> ConstDef {
self.expect(&Lexeme::Const);
let name = self.expect_ident();
self.expect(&Lexeme::Colon);
let ty = self.parse_type();
self.expect(&Lexeme::Eq);
let value = self.parse_expr();
ConstDef {
is_pub,
cfg,
name,
ty,
value,
}
}
fn parse_struct(&mut self, is_pub: bool, cfg: Option<Spanned<String>>) -> StructDef {
self.expect(&Lexeme::Struct);
let name = self.expect_ident();
self.expect(&Lexeme::LBrace);
let mut fields = Vec::new();
while !self.at(&Lexeme::RBrace) && !self.at(&Lexeme::Eof) {
let field_pub = self.eat(&Lexeme::Pub);
let field_name = self.expect_ident();
self.expect(&Lexeme::Colon);
let field_ty = self.parse_type();
fields.push(StructField {
is_pub: field_pub,
name: field_name,
ty: field_ty,
});
if !self.eat(&Lexeme::Comma) {
break;
}
}
self.expect(&Lexeme::RBrace);
StructDef {
is_pub,
cfg,
name,
fields,
}
}
fn parse_fn_with_attr(
&mut self,
is_pub: bool,
cfg: Option<Spanned<String>>,
intrinsic: Option<Spanned<String>>,
is_test: bool,
is_pure: bool,
requires: Vec<Spanned<String>>,
ensures: Vec<Spanned<String>>,
) -> FnDef {
self.expect(&Lexeme::Fn);
let name = self.expect_ident();
// Parse optional size-generic parameters: fn name<N, M>(...)
let type_params = self.parse_type_params();
self.expect(&Lexeme::LParen);
let params = self.parse_params();
self.expect(&Lexeme::RParen);
let return_ty = if self.eat(&Lexeme::Arrow) {
Some(self.parse_type())
} else {
None
};
let body = if self.at(&Lexeme::LBrace) {
Some(self.parse_block())
} else {
None
};
FnDef {
is_pub,
cfg,
intrinsic,
is_test,
is_pure,
requires,
ensures,
name,
type_params,
params,
return_ty,
body,
}
}
/// Parse `<N, M>` size-generic parameter list (if present).
fn parse_type_params(&mut self) -> Vec<Spanned<String>> {
if !self.eat(&Lexeme::Lt) {
return Vec::new();
}
let mut params = Vec::new();
while !self.at(&Lexeme::Gt) && !self.at(&Lexeme::Eof) {
params.push(self.expect_ident());
if !self.eat(&Lexeme::Comma) {
break;
}
}
self.expect(&Lexeme::Gt);
params
}
fn parse_attribute(&mut self) -> Spanned<String> {
let start = self.current_span();
self.expect(&Lexeme::Hash);
self.expect(&Lexeme::LBracket);
let name = self.expect_ident();
if self.at(&Lexeme::LParen) {
self.expect(&Lexeme::LParen);
// Collect everything between ( and ) as raw text, handling nesting.
let mut depth = 1u32;
let mut parts = Vec::new();
while depth > 0 && !self.at(&Lexeme::Eof) {
if self.at(&Lexeme::LParen) {
depth += 1;
parts.push("(".to_string());
self.advance();
} else if self.at(&Lexeme::RParen) {
depth -= 1;
if depth > 0 {
parts.push(")".to_string());
self.advance();
}
} else {
parts.push(self.current_lexeme_text());
self.advance();
}
}
self.expect(&Lexeme::RParen);
self.expect(&Lexeme::RBracket);
let value = parts.join(" ");
let span = start.merge(self.prev_span());
Spanned::new(format!("{}({})", name.node, value.trim()), span)
} else {
self.expect(&Lexeme::RBracket);
let span = start.merge(self.prev_span());
Spanned::new(name.node, span)
}
}
/// Get the text representation of the current token for attribute parsing.
fn current_lexeme_text(&self) -> String {
match self.peek() {
Lexeme::Ident(s) => s.clone(),
Lexeme::Integer(n) => n.to_string(),
Lexeme::Plus => "+".to_string(),
Lexeme::Star => "*".to_string(),
Lexeme::Eq => "=".to_string(),
Lexeme::EqEq => "==".to_string(),
Lexeme::Lt => "<".to_string(),
Lexeme::Gt => ">".to_string(),
Lexeme::Amp => "&".to_string(),
Lexeme::Caret => "^".to_string(),
Lexeme::Dot => ".".to_string(),
Lexeme::Comma => ",".to_string(),
Lexeme::Colon => ":".to_string(),
Lexeme::Arrow => "->".to_string(),
Lexeme::LBracket => "[".to_string(),
Lexeme::RBracket => "]".to_string(),
Lexeme::Hash => "#".to_string(),
other => format!("{:?}", other),
}
}
fn parse_params(&mut self) -> Vec<Param> {
let mut params = Vec::new();
while !self.at(&Lexeme::RParen) && !self.at(&Lexeme::Eof) {
let name = self.expect_ident();
self.expect(&Lexeme::Colon);
let ty = self.parse_type();
params.push(Param { name, ty });
if !self.eat(&Lexeme::Comma) {
break;
}
}
params
}
pub(super) fn parse_event(&mut self, cfg: Option<Spanned<String>>) -> EventDef {
self.expect(&Lexeme::Event);
let name = self.expect_ident();
self.expect(&Lexeme::LBrace);
let mut fields = Vec::new();
while !self.at(&Lexeme::RBrace) && !self.at(&Lexeme::Eof) {
let field_name = self.expect_ident();
self.expect(&Lexeme::Colon);
let field_ty = self.parse_type();
fields.push(EventField {
name: field_name,
ty: field_ty,
});
if !self.eat(&Lexeme::Comma) {
break;
}
}
self.expect(&Lexeme::RBrace);
EventDef { cfg, name, fields }
}
}
trident/src/syntax/parser/items.rs
ฯ 0.0%
use crate*;
use crateLexeme;
use crateSpanned;
use Parser;