Compare commits
5 Commits
4fcad8c6a4
...
732d80dd9a
Author | SHA1 | Date |
---|---|---|
mars | 732d80dd9a | |
mars | 6217b83cd8 | |
mars | 0a795f1450 | |
mars | 1d7007ab9a | |
mars | 24e5ac2aef |
|
@ -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,
|
||||
|
||||
|
|
122
src/parse.rs
122
src/parse.rs
|
@ -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]
|
||||
|
|
Loading…
Reference in New Issue