Compare commits

...

5 Commits

Author SHA1 Message Date
mars 732d80dd9a Lex and parse bool literals 2022-03-01 13:08:18 -07:00
mars 6217b83cd8 If expressions 2022-03-01 13:06:38 -07:00
mars 0a795f1450 Parse function calls 2022-03-01 12:53:20 -07:00
mars 1d7007ab9a Expression parantheses nesting 2022-03-01 12:26:13 -07:00
mars 24e5ac2aef Parse boolean and bitwise ops 2022-03-01 11:19:04 -07:00
2 changed files with 98 additions and 28 deletions

View File

@ -54,6 +54,10 @@ pub enum Token {
#[token("==")] OpEq,
#[token("!=")] OpNeq,
// boolean literals
#[token("true")] True,
#[token("false")] False,
#[regex(r"[a-zA-Z_][a-zA-Z0-9_]*")]
Identifier,

View File

@ -53,7 +53,7 @@ pub enum Definition<'a> {
associated_struct: Option<(&'a str, bool)>,
name: &'a str,
signature: FnSig<'a>,
body: FnBody<'a>,
body: BranchBody<'a>,
},
Interface {
name: &'a str,
@ -97,7 +97,7 @@ impl<'a> Definition<'a> {
lexer.panic_message("Expected open brace");
}
let body = FnBody::build(lexer);
let body = BranchBody::build(lexer);
Self::Function {
name,
@ -193,12 +193,12 @@ pub struct FnArg<'a> {
}
#[derive(Debug)]
pub struct FnBody<'a> {
pub struct BranchBody<'a> {
pub statements: Vec<Statement<'a>>,
pub tail_expr: Option<Expr<'a>>,
pub tail_expr: Option<Box<Expr<'a>>>,
}
impl<'a> FnBody<'a> {
impl<'a> BranchBody<'a> {
pub fn build(lexer: &mut Lexer<'a>) -> Self {
let mut statements = Vec::new();
@ -215,7 +215,8 @@ impl<'a> FnBody<'a> {
_ => lexer.panic_message("Unexpected token"),
}
}
Token::Identifier => match Expr::build_start(tok, lexer) {
Token::BraceClose => break,
_ => match Expr::build_start(tok, lexer) {
(None, Token::Semicolon | Token::BraceClose) => {}
(Some(expr), Token::Semicolon) => statements.push(Statement::Expr(expr)),
(Some(expr), Token::BraceClose) => {
@ -224,14 +225,12 @@ impl<'a> FnBody<'a> {
}
_ => lexer.panic_message("Unexpected token"),
},
Token::BraceClose => break,
_ => lexer.panic_message("Expected let or expression"),
}
}
Self {
statements,
tail_expr,
tail_expr: tail_expr.map(|x| Box::new(x)),
}
}
}
@ -244,7 +243,8 @@ pub enum Expr<'a> {
Literal(Literal<'a>),
Local(&'a str),
Member(&'a str),
FuncCall(&'a str, Vec<Expr<'a>>),
Group(Box<Expr<'a>>),
FnCall(&'a str, Vec<Expr<'a>>),
If {
test_expr: Box<Expr<'a>>,
then_body: BranchBody<'a>,
@ -254,20 +254,64 @@ pub enum Expr<'a> {
impl<'a> Expr<'a> {
pub fn build_start(tok: Token, lexer: &mut Lexer<'a>) -> (Option<Self>, Token) {
let mut next = None;
let lhs = match tok {
Token::Identifier => Self::Local(lexer.slice()),
Token::Identifier => {
let local = lexer.slice();
let tok = lexer.next().unwrap();
next = Some(tok);
match tok {
Token::ParanOpen => {
next = None;
Self::FnCall(local, Self::eat_args(lexer))
}
_ => Self::Local(local),
}
}
Token::Dot => Self::Member(lexer.eat_expect_id()),
Token::ParanOpen => {
let (inner, next) = Self::build(lexer);
if next != Token::ParanClose {
lexer.panic_message("Expected closing parantheses");
}
Self::Group(Box::new(inner.unwrap()))
}
Token::If => {
let test_expr = match Self::build(lexer) {
(Some(test_expr), Token::BraceOpen) => Box::new(test_expr),
(None, Token::BraceOpen) => lexer.panic_message("Expected test expression"),
_ => lexer.panic_message("Expected opening brace"),
};
let then_body = BranchBody::build(lexer);
lexer.eat_expect(Token::Else);
lexer.eat_expect(Token::BraceOpen);
let else_body = BranchBody::build(lexer);
Self::If {
test_expr,
then_body,
else_body,
}
}
Token::BinaryInteger => Self::Literal(Literal::BinaryInteger(lexer.slice())),
Token::OctalInteger => Self::Literal(Literal::OctalInteger(lexer.slice())),
Token::HexInteger => Self::Literal(Literal::HexInteger(lexer.slice())),
Token::DecimalInteger => Self::Literal(Literal::DecimalInteger(lexer.slice())),
Token::True => Self::Literal(Literal::Boolean(true)),
Token::False => Self::Literal(Literal::Boolean(false)),
Token::Semicolon | Token::BraceClose | Token::ParanClose => return (None, tok),
_ => lexer.panic_message("Unexpected token"),
};
let (rhs, next) = Self::eat_op(lexer);
if let Some((op, rhs)) = rhs {
(Some(Self::BinaryOp(op, Box::new((lhs, rhs)))), next)
let next = next.unwrap_or_else(|| lexer.next().unwrap());
if let Some(op) = BinaryOp::from_token(next) {
match Self::build(lexer) {
(Some(rhs), tail) => (Some(Self::BinaryOp(op, Box::new((lhs, rhs)))), tail),
_ => lexer.panic_message("Expected right-hand expression"),
}
} else {
(Some(lhs), next)
}
@ -277,16 +321,22 @@ impl<'a> Expr<'a> {
Self::build_start(lexer.next().unwrap(), lexer)
}
fn eat_op(lexer: &mut Lexer<'a>) -> (Option<(BinaryOp, Self)>, Token) {
let tok = lexer.next().unwrap();
if let Some(op) = BinaryOp::from_token(tok) {
pub fn eat_args(lexer: &mut Lexer<'a>) -> Vec<Self> {
let mut args = Vec::new();
loop {
match Self::build(lexer) {
(Some(rhs), tail) => (Some((op, rhs)), tail),
_ => lexer.panic_message("Expected right-hand expression"),
(Some(arg), Token::Comma) => args.push(arg),
(Some(arg), Token::ParanClose) => {
args.push(arg);
break;
}
(None, Token::ParanClose) => break,
_ => lexer.panic_message("Unexpected token"),
}
} else {
(None, tok)
}
args
}
}
@ -297,6 +347,11 @@ pub enum BinaryOp {
Mul,
Div,
Assign,
BoolOr,
BoolAnd,
BitOr,
BitAnd,
BitXor,
Less,
LessEq,
Greater,
@ -315,6 +370,11 @@ impl BinaryOp {
OpMul => Some(Mul),
OpDiv => Some(Div),
OpAssign => Some(Assign),
OpBoolOr => Some(BoolOr),
OpBoolAnd => Some(BoolAnd),
OpBitOr => Some(BitOr),
OpBitAnd => Some(BitAnd),
OpBitXor => Some(BitXor),
OpLess => Some(Less),
OpLessEq => Some(LessEq),
OpGreater => Some(Greater),
@ -332,6 +392,7 @@ pub enum Literal<'a> {
OctalInteger(&'a str),
HexInteger(&'a str),
DecimalInteger(&'a str),
Boolean(bool),
}
#[derive(Debug)]
@ -372,12 +433,6 @@ impl<'a> Statement<'a> {
}
}
#[derive(Debug)]
pub struct BranchBody<'a> {
pub statements: Vec<Statement<'a>>,
pub tail_expression: Box<Expr<'a>>,
}
#[cfg(test)]
mod tests {
use super::*;
@ -417,6 +472,7 @@ mod tests {
use super::*;
fn parse_expr(source: &str) {
println!("Source: {}", source);
let mut lex = Lexer::new(source);
let expr = Expr::build(&mut lex);
println!("{:#?}", expr);
@ -433,14 +489,24 @@ mod tests {
parse_expr("local1 + local2 - local3;");
}
#[test]
fn nesting() {
parse_expr("(1 + 2) * (3 / (4 + 5));")
}
#[test]
fn members() {
parse_expr(".member1 * .member2;");
}
#[test]
fn if_expr() {
parse_expr("if true { 1 } else { 0 };");
}
#[test]
fn func_call() {
parse_expr("func_call();");
parse_expr("func_call(1 + 2, 3, 4 * 5);");
}
#[test]