use crate::lexer::{SpannedToken, Token};
use crate::types::Value;
const EOF_TOKEN: SpannedToken = SpannedToken {
kind: Token::EOF,
line: 0,
col: 0,
};
#[derive(Debug, Clone)]
pub enum Expr {
Literal(Value),
Ident(String),
Array(Vec<Expr>),
Range(Box<Expr>, Box<Expr>),
BinOp {
left: Box<Expr>,
op: String,
right: Box<Expr>,
},
Assign {
name: String,
value: Box<Expr>,
},
VarDecl {
name: String,
type_hint: Option<String>,
value: Box<Expr>,
is_mut: bool,
},
Call {
keyword: String,
args: Vec<Expr>,
line: usize,
file: String,
},
If {
cond: Box<Expr>,
then_block: Vec<Expr>,
else_block: Option<Vec<Expr>>,
},
Loop {
body: Vec<Expr>,
},
While {
cond: Box<Expr>,
body: Vec<Expr>,
},
For {
var: String,
iter: Box<Expr>,
body: Vec<Expr>,
},
FnDef {
name: String,
params: Vec<String>,
body: Vec<Expr>,
},
Return(Box<Expr>),
Break,
Switch {
value: Box<Expr>,
cases: Vec<(Expr, Vec<Expr>)>,
default: Option<Vec<Expr>>,
},
Lambda {
params: Vec<String>,
body: Vec<Expr>,
},
Try {
body: Vec<Expr>,
catch_body: Vec<Expr>,
},
Import(String),
StructDef {
name: String,
fields: Vec<String>,
},
Interpolated(Vec<InterpolPart>),
}
#[derive(Debug, Clone)]
pub enum InterpolPart {
Text(String),
Expr(Expr),
}
pub struct Parser {
tokens: Vec<SpannedToken>,
pos: usize,
file_name: String,
keywords: Vec<String>,
mut_keyword: Option<String>,
immut_keyword: Option<String>,
fn_keyword: Option<String>,
return_keyword: Option<String>,
if_keyword: Option<String>,
loop_keyword: Option<String>,
for_keyword: Option<String>,
in_keyword: Option<String>,
try_keyword: Option<String>,
catch_keyword: Option<String>,
import_keyword: Option<String>,
break_keyword: Option<String>,
while_keyword: Option<String>,
switch_keyword: Option<String>,
case_keyword: Option<String>,
default_keyword: Option<String>,
struct_keyword: Option<String>,
}
impl Parser {
pub fn new(tokens: Vec<SpannedToken>, file_name: String) -> Self {
Self {
tokens,
pos: 0,
file_name,
keywords: vec![],
mut_keyword: None,
immut_keyword: None,
fn_keyword: None,
return_keyword: None,
if_keyword: None,
loop_keyword: None,
for_keyword: None,
in_keyword: None,
try_keyword: None,
catch_keyword: None,
import_keyword: None,
break_keyword: None,
while_keyword: None,
switch_keyword: None,
case_keyword: None,
default_keyword: None,
struct_keyword: None,
}
}
pub fn with_keywords(mut self, k: Vec<String>) -> Self {
self.keywords = k;
self
}
pub fn with_mut(mut self, k: Option<String>) -> Self {
self.mut_keyword = k;
self
}
pub fn with_immut(mut self, k: Option<String>) -> Self {
self.immut_keyword = k;
self
}
pub fn with_fn(mut self, k: Option<String>) -> Self {
self.fn_keyword = k;
self
}
pub fn with_return(mut self, k: Option<String>) -> Self {
self.return_keyword = k;
self
}
pub fn with_if(mut self, k: Option<String>) -> Self {
self.if_keyword = k;
self
}
pub fn with_loop(mut self, k: Option<String>) -> Self {
self.loop_keyword = k;
self
}
pub fn with_for(mut self, k: Option<String>) -> Self {
self.for_keyword = k;
self
}
pub fn with_in(mut self, k: Option<String>) -> Self {
self.in_keyword = k;
self
}
pub fn with_try(mut self, k: Option<String>) -> Self {
self.try_keyword = k;
self
}
pub fn with_catch(mut self, k: Option<String>) -> Self {
self.catch_keyword = k;
self
}
pub fn with_break(mut self, k: Option<String>) -> Self {
self.break_keyword = k;
self
}
pub fn with_import(mut self, k: Option<String>) -> Self {
self.import_keyword = k;
self
}
pub fn with_while(mut self, k: Option<String>) -> Self {
self.while_keyword = k;
self
}
pub fn with_switch(mut self, k: Option<String>) -> Self {
self.switch_keyword = k;
self
}
pub fn with_case(mut self, k: Option<String>) -> Self {
self.case_keyword = k;
self
}
pub fn with_default(mut self, k: Option<String>) -> Self {
self.default_keyword = k;
self
}
pub fn with_struct(mut self, k: Option<String>) -> Self {
self.struct_keyword = k;
self
}
fn peek(&self) -> &SpannedToken {
self.tokens.get(self.pos).unwrap_or(&EOF_TOKEN)
}
fn peek_kind(&self) -> &Token {
&self.peek().kind
}
fn advance(&mut self) -> SpannedToken {
let t = self
.tokens
.get(self.pos)
.cloned()
.unwrap_or_else(|| EOF_TOKEN.clone());
self.pos += 1;
t
}
fn skip_newlines(&mut self) {
while self.peek_kind() == &Token::Newline {
self.advance();
}
}
fn err_at(&self, token: &SpannedToken, msg: &str) -> String {
if token.line == 0 {
msg.to_string()
} else {
format!("{}:Line {}:{}: {}", self.file_name, token.line, token.col, msg)
}
}
pub fn parse(&mut self) -> Result<Vec<Expr>, String> {
let mut stmts = vec![];
loop {
self.skip_newlines();
if self.peek_kind() == &Token::EOF {
break;
}
stmts.push(self.parse_stmt()?);
}
Ok(stmts)
}
fn parse_block(&mut self) -> Result<Vec<Expr>, String> {
let mut stmts = vec![];
match self.peek_kind() {
Token::LBrace => {
self.advance();
loop {
self.skip_newlines();
if self.peek_kind() == &Token::RBrace || self.peek_kind() == &Token::EOF {
break;
}
stmts.push(self.parse_stmt()?);
}
self.advance();
}
_ => {
stmts.push(self.parse_stmt()?);
}
}
Ok(stmts)
}
fn parse_stmt(&mut self) -> Result<Expr, String> {
if let Some(mk) = self.mut_keyword.clone() {
if self.peek_kind() == &Token::Keyword(mk.clone()) {
self.advance();
return self.parse_var_decl(true);
}
}
if let Some(ik) = self.immut_keyword.clone() {
if self.peek_kind() == &Token::Keyword(ik.clone()) {
self.advance();
return self.parse_var_decl(false);
}
}
if let Some(fk) = self.fn_keyword.clone() {
if self.peek_kind() == &Token::Keyword(fk) {
self.advance();
return self.parse_fn_def();
}
}
if let Some(rk) = self.return_keyword.clone() {
if self.peek_kind() == &Token::Keyword(rk) {
self.advance();
return Ok(Expr::Return(Box::new(self.parse_expr()?)));
}
}
if let Some(ik) = self.if_keyword.clone() {
if self.peek_kind() == &Token::Keyword(ik) {
self.advance();
return self.parse_if();
}
}
if let Some(lk) = self.loop_keyword.clone() {
if self.peek_kind() == &Token::Keyword(lk) {
self.advance();
return Ok(Expr::Loop {
body: self.parse_block()?,
});
}
}
if let Some(fk) = self.for_keyword.clone() {
if self.peek_kind() == &Token::Keyword(fk) {
self.advance();
return self.parse_for();
}
}
if let Some(tk) = self.try_keyword.clone() {
if self.peek_kind() == &Token::Keyword(tk) {
self.advance();
return self.parse_try();
}
}
if let Some(bk) = self.break_keyword.clone() {
if self.peek_kind() == &Token::Keyword(bk) {
self.advance();
return Ok(Expr::Break);
}
}
if let Some(wk) = self.while_keyword.clone() {
if self.peek_kind() == &Token::Keyword(wk) {
self.advance();
return self.parse_while();
}
}
if let Some(sk) = self.switch_keyword.clone() {
if self.peek_kind() == &Token::Keyword(sk) {
self.advance();
return self.parse_switch();
}
}
if let Some(ik) = self.import_keyword.clone() {
if self.peek_kind() == &Token::Keyword(ik) {
self.advance();
let t = self.advance();
return match t.kind {
Token::Str(s) => Ok(Expr::Import(s)),
_ => Err(self.err_at(&t, "Expected string after import")),
};
}
}
if let Some(sk) = self.struct_keyword.clone() {
if self.peek_kind() == &Token::Keyword(sk) {
self.advance();
return self.parse_struct_def();
}
}
if let Token::Keyword(kw) = self.peek_kind().clone() {
let line = self.peek().line;
self.advance();
let mut args = vec![];
loop {
match self.peek_kind() {
Token::Newline | Token::Semicolon | Token::EOF | Token::RBrace => break,
_ => args.push(self.parse_expr()?),
}
if self.peek_kind() == &Token::Comma {
self.advance();
}
}
return Ok(Expr::Call {
keyword: kw,
args,
line,
file: self.file_name.clone(),
});
}
self.parse_expr()
}
fn parse_var_decl(&mut self, is_mut: bool) -> Result<Expr, String> {
let t = self.advance();
let name = match t.kind {
Token::Ident(n) => n,
_ => return Err(self.err_at(&t, "Expected variable name")),
};
let type_hint = if self.peek_kind() == &Token::Colon {
self.advance();
let t = self.advance();
match t.kind {
Token::Ident(t) => Some(t),
_ => return Err(self.err_at(&t, "Expected type")),
}
} else {
None
};
let t = self.advance();
match t.kind {
Token::Eq => {}
_ => return Err(self.err_at(&t, "Expected '='")),
};
Ok(Expr::VarDecl {
name,
type_hint,
value: Box::new(self.parse_expr()?),
is_mut,
})
}
fn parse_fn_def(&mut self) -> Result<Expr, String> {
let name = self.parse_dotted_ident()?;
let mut params = vec![];
if self.peek_kind() == &Token::LParen {
self.advance();
loop {
if self.peek_kind() == &Token::RParen {
break;
}
let t = self.advance();
match t.kind {
Token::Ident(p) => params.push(p),
_ => return Err(self.err_at(&t, "Expected parameter name")),
}
if self.peek_kind() == &Token::Comma {
self.advance();
}
}
self.advance();
}
Ok(Expr::FnDef {
name,
params,
body: self.parse_block()?,
})
}
fn parse_struct_def(&mut self) -> Result<Expr, String> {
let t = self.advance();
let name = match t.kind {
Token::Ident(n) => n,
_ => return Err(self.err_at(&t, "Expected struct name")),
};
let mut fields = Vec::new();
if self.peek_kind() != &Token::LBrace {
return Err(self.err_at(self.peek(), "Expected '{' after struct name"));
}
self.advance();
loop {
self.skip_newlines();
if self.peek_kind() == &Token::RBrace || self.peek_kind() == &Token::EOF {
break;
}
let t = self.advance();
match t.kind {
Token::Ident(f) => fields.push(f),
_ => return Err(self.err_at(&t, "Expected field name")),
}
if self.peek_kind() == &Token::Comma {
self.advance();
}
}
if self.peek_kind() == &Token::RBrace {
self.advance();
}
Ok(Expr::StructDef { name, fields })
}
fn parse_dotted_ident(&mut self) -> Result<String, String> {
let t = self.advance();
let mut name = match t.kind {
Token::Ident(n) => n,
_ => return Err(self.err_at(&t, "Expected identifier")),
};
while self.peek_kind() == &Token::Dot {
self.advance();
let t = self.advance();
match t.kind {
Token::Ident(n) => {
name.push('.');
name.push_str(&n);
}
_ => return Err(self.err_at(&t, "Expected identifier after '.'")),
}
}
Ok(name)
}
fn parse_if(&mut self) -> Result<Expr, String> {
let cond = self.parse_expr()?;
let then_block = self.parse_block()?;
let else_block = if self.peek_kind() == &Token::Keyword("else".to_string()) {
self.advance();
Some(self.parse_block()?)
} else {
None
};
Ok(Expr::If {
cond: Box::new(cond),
then_block,
else_block,
})
}
fn parse_for(&mut self) -> Result<Expr, String> {
let t = self.advance();
let var = match t.kind {
Token::Ident(n) => n,
_ => return Err(self.err_at(&t, "Expected variable name in for")),
};
let in_kw = self.in_keyword.clone().unwrap_or_else(|| "in".to_string());
let t = self.advance();
match t.kind {
Token::Keyword(k) if k == in_kw => {}
Token::Ident(k) if k == in_kw => {}
_ => return Err(self.err_at(&t, &format!("Expected '{}' after for", in_kw))),
};
let iter = self.parse_expr()?;
let body = self.parse_block()?;
Ok(Expr::For {
var,
iter: Box::new(iter),
body,
})
}
fn parse_try(&mut self) -> Result<Expr, String> {
let body = self.parse_block()?;
let catch_kw = self
.catch_keyword
.clone()
.unwrap_or_else(|| "catch".to_string());
if self.peek_kind() == &Token::Keyword(catch_kw) {
self.advance();
}
Ok(Expr::Try {
body,
catch_body: self.parse_block()?,
})
}
fn parse_while(&mut self) -> Result<Expr, String> {
let cond = self.parse_expr()?;
let body = self.parse_block()?;
Ok(Expr::While {
cond: Box::new(cond),
body,
})
}
fn parse_switch(&mut self) -> Result<Expr, String> {
let value = self.parse_expr()?;
let mut cases = vec![];
let mut default = None;
self.skip_newlines();
if self.peek_kind() == &Token::LBrace {
self.advance();
}
let case_kw = self
.case_keyword
.clone()
.unwrap_or_else(|| "case".to_string());
let default_kw = self
.default_keyword
.clone()
.unwrap_or_else(|| "default".to_string());
loop {
self.skip_newlines();
if self.peek_kind() == &Token::RBrace || self.peek_kind() == &Token::EOF {
if self.peek_kind() == &Token::RBrace {
self.advance();
}
break;
}
if self.peek_kind() == &Token::Keyword(case_kw.clone()) {
self.advance();
let case_val = self.parse_expr()?;
let body = self.parse_block()?;
cases.push((case_val, body));
} else if self.peek_kind() == &Token::Keyword(default_kw.clone()) {
self.advance();
default = Some(self.parse_block()?);
} else {
let t = self.peek().clone();
return Err(self.err_at(&t, "Expected 'case' or 'default' in switch"));
}
}
Ok(Expr::Switch {
value: Box::new(value),
cases,
default,
})
}
fn parse_expr(&mut self) -> Result<Expr, String> {
self.parse_comparison()
}
fn parse_comparison(&mut self) -> Result<Expr, String> {
let mut left = self.parse_additive()?;
loop {
let op = match self.peek_kind() {
Token::EqEq => "==",
Token::NotEq => "!=",
Token::Lt => "<",
Token::Gt => ">",
Token::LtEq => "<=",
Token::GtEq => ">=",
_ => break,
}
.to_string();
self.advance();
left = Expr::BinOp {
left: Box::new(left),
op,
right: Box::new(self.parse_additive()?),
};
}
Ok(left)
}
fn parse_additive(&mut self) -> Result<Expr, String> {
let mut left = self.parse_multiplicative()?;
loop {
let op = match self.peek_kind() {
Token::Plus => "+",
Token::Minus => "-",
_ => break,
}
.to_string();
self.advance();
left = Expr::BinOp {
left: Box::new(left),
op,
right: Box::new(self.parse_multiplicative()?),
};
}
Ok(left)
}
fn parse_multiplicative(&mut self) -> Result<Expr, String> {
let mut left = self.parse_primary()?;
loop {
let op = match self.peek_kind() {
Token::Star => "*",
Token::Slash => "/",
Token::Percent => "%",
_ => break,
}
.to_string();
self.advance();
left = Expr::BinOp {
left: Box::new(left),
op,
right: Box::new(self.parse_primary()?),
};
}
Ok(left)
}
fn parse_primary(&mut self) -> Result<Expr, String> {
let t = self.advance();
match t.kind {
Token::Number(n) => {
if self.peek_kind() == &Token::DotDot {
self.advance();
return Ok(Expr::Range(
Box::new(Expr::Literal(Value::Float(n))),
Box::new(self.parse_primary()?),
));
}
Ok(Expr::Literal(Value::Float(n)))
}
Token::Str(s) => {
if s.contains('{') {
Ok(parse_interpolation(&s))
} else {
Ok(Expr::Literal(Value::Str(s)))
}
}
Token::Bool(b) => Ok(Expr::Literal(Value::Bool(b))),
Token::Null => Ok(Expr::Literal(Value::Null)),
Token::Ident(name) => {
let mut full = name;
while self.peek_kind() == &Token::Dot {
self.advance();
let t = self.advance();
match t.kind {
Token::Ident(n) => {
full.push('.');
full.push_str(&n);
}
_ => return Err(self.err_at(&t, "Expected identifier after '.'")),
}
}
if self.peek_kind() == &Token::Eq {
self.advance();
return Ok(Expr::Assign {
name: full,
value: Box::new(self.parse_expr()?),
});
}
if self.peek_kind() == &Token::LParen {
let line = self.peek().line;
self.advance();
let mut args = vec![];
loop {
if self.peek_kind() == &Token::RParen {
break;
}
args.push(self.parse_expr()?);
if self.peek_kind() == &Token::Comma {
self.advance();
}
}
self.advance();
return Ok(Expr::Call {
keyword: full,
args,
line,
file: self.file_name.clone(),
});
}
Ok(Expr::Ident(full))
}
Token::LParen => {
let e = self.parse_expr()?;
self.advance();
Ok(e)
}
Token::LBracket => {
let mut items = vec![];
loop {
if self.peek_kind() == &Token::RBracket {
break;
}
items.push(self.parse_expr()?);
if self.peek_kind() == &Token::Comma {
self.advance();
}
}
self.advance();
Ok(Expr::Array(items))
}
_ => Err(self.err_at(&t, "Unexpected token")),
}
}
}
fn parse_interpolation(s: &str) -> Expr {
let mut parts = vec![];
let mut text = String::new();
let mut chars = s.chars().peekable();
while let Some(c) = chars.next() {
if c == '{' {
if !text.is_empty() {
parts.push(InterpolPart::Text(text.clone()));
text.clear();
}
let mut expr_src = String::new();
for c in chars.by_ref() {
if c == '}' {
break;
}
expr_src.push(c);
}
let expr_src = expr_src.trim().to_string();
if expr_src.chars().all(|c| c.is_alphanumeric() || c == '_') {
parts.push(InterpolPart::Expr(Expr::Ident(expr_src)));
} else {
parts.push(InterpolPart::Text(format!("{{{}}}", expr_src)));
}
} else {
text.push(c);
}
}
if !text.is_empty() {
parts.push(InterpolPart::Text(text));
}
if parts.len() == 1 {
if let InterpolPart::Text(t) = &parts[0] {
return Expr::Literal(Value::Str(t.clone()));
}
}
Expr::Interpolated(parts)
}