From 0fca17defbdf63a9e8a54371ef2892e659fb983c Mon Sep 17 00:00:00 2001 From: Sofia Date: Mon, 16 Mar 2026 16:53:52 +0200 Subject: [PATCH] Add unary operators --- src/ast.rs | 101 +++++++++++++++++++++++++++++++++---------------- src/compile.rs | 14 ++++++- 2 files changed, 81 insertions(+), 34 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 3a253f6..ed2b322 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -284,6 +284,7 @@ pub enum AccessModifier { #[derive(Debug, Clone)] pub enum Expression { ValueRef(String), + UnOp(UnaryOperator, Box>), BinOp(BinaryOperator, Box>, Box>), FunctionDefinition(Vec>, Block), FunctionCall(Box>, Node), @@ -318,6 +319,24 @@ impl Parse for ExpressionList { #[derive(Debug, Clone)] pub struct PrimaryExpression(Node); +#[derive(Debug, Clone, Copy)] +pub enum UnaryOperator { + Negation, +} + +impl Parse for UnaryOperator { + fn parse(mut stream: TokenStream) -> Result { + if let Some(token) = stream.next() { + match token { + Token::Symbol('-') => Ok(UnaryOperator::Negation), + _ => Err(stream.expected_err("unop")), + } + } else { + Err(stream.expected_err("unop")) + } + } +} + #[derive(Debug, Clone, Copy)] pub enum BinaryOperator { And, @@ -347,10 +366,49 @@ impl BinaryOperator { } } +impl Parse for BinaryOperator { + fn parse(mut stream: TokenStream) -> Result { + if let Some(token) = stream.next() { + match (token, stream.peek()) { + (Token::Word(word), _) => match word.as_str() { + "and" => Ok(BinaryOperator::And), + "or" => Ok(BinaryOperator::Or), + _ => Err(stream.expected_err("binop")), + }, + (Token::Symbol('<'), Some(Token::Symbol('='))) => { + stream.next(); + Ok(BinaryOperator::LessThanOrEqual) + } + (Token::Symbol('>'), Some(Token::Symbol('='))) => { + stream.next(); + Ok(BinaryOperator::GreaterThanOrEqual) + } + (Token::Symbol('='), Some(Token::Symbol('='))) => { + stream.next(); + Ok(BinaryOperator::Equal) + } + (Token::Symbol('<'), _) => Ok(BinaryOperator::LessThan), + (Token::Symbol('>'), _) => Ok(BinaryOperator::GreaterThan), + (Token::Symbol('+'), _) => Ok(BinaryOperator::Add), + (Token::Symbol('-'), _) => Ok(BinaryOperator::Sub), + _ => Err(stream.expected_err("binop")), + } + } else { + Err(stream.expected_err("binop")) + } + } +} + impl Parse for PrimaryExpression { fn parse(mut stream: TokenStream) -> Result { let pre = Metadata::pre(&mut stream, "expression")?; + let mut unary_operators = Vec::new(); + + while let Ok(unop) = stream.parse::() { + unary_operators.push(unop); + } + let peeked = stream.peek(); let mut expression = if peeked == Some(Token::Keyword(Keyword::Function)) { let function = stream.parse::>()?; @@ -377,6 +435,16 @@ impl Parse for PrimaryExpression { ); } + for unop in unary_operators.into_iter().rev() { + expression = Expression::UnOp( + unop, + Box::new(Node { + kind: expression, + meta: Metadata::produce(&mut stream, pre.clone()), + }), + ); + } + Ok(PrimaryExpression(Node { kind: expression, meta: Metadata::produce(&mut stream, pre), @@ -421,39 +489,6 @@ fn parse_binop_rhs( Ok(lhs.0) } -impl Parse for BinaryOperator { - fn parse(mut stream: TokenStream) -> Result { - if let Some(token) = stream.next() { - match (token, stream.peek()) { - (Token::Word(word), _) => match word.as_str() { - "and" => Ok(BinaryOperator::And), - "or" => Ok(BinaryOperator::Or), - _ => Err(stream.expected_err("binop")), - }, - (Token::Symbol('<'), Some(Token::Symbol('='))) => { - stream.next(); - Ok(BinaryOperator::LessThanOrEqual) - } - (Token::Symbol('>'), Some(Token::Symbol('='))) => { - stream.next(); - Ok(BinaryOperator::GreaterThanOrEqual) - } - (Token::Symbol('='), Some(Token::Symbol('='))) => { - stream.next(); - Ok(BinaryOperator::Equal) - } - (Token::Symbol('<'), _) => Ok(BinaryOperator::LessThan), - (Token::Symbol('>'), _) => Ok(BinaryOperator::GreaterThan), - (Token::Symbol('+'), _) => Ok(BinaryOperator::Add), - (Token::Symbol('-'), _) => Ok(BinaryOperator::Sub), - _ => Err(stream.expected_err("binop")), - } - } else { - Err(stream.expected_err("binop")) - } - } -} - #[derive(Debug, Clone, Copy)] pub enum Literal { Number(LuaNumber), diff --git a/src/compile.rs b/src/compile.rs index f50a66f..8e7697e 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,7 +1,7 @@ use std::collections::{HashMap, HashSet}; use crate::{ - ast::{AccessModifier, BinaryOperator, Block, Expression, Literal, Statement}, + ast::{AccessModifier, BinaryOperator, Block, Expression, Literal, Statement, UnaryOperator}, vm::{Constant, Instruction, VMNumber}, }; @@ -258,6 +258,7 @@ impl Expression { constants.extend(rhs.kind.find_constants(scope)); constants } + Expression::UnOp(_, expr) => expr.kind.find_constants(scope), Expression::FunctionDefinition(_, block) => block.find_constants(scope), Expression::FunctionCall(expr, params) => { let mut constants = HashSet::new(); @@ -371,6 +372,17 @@ impl Expression { }; (instructions, vec![reg]) } + Expression::UnOp(op, expr) => { + let mut instructions = Vec::new(); + let (instr, registers) = expr.kind.compile(state, scope, Some(1)); + instructions.extend(instr); + for reg in ®isters { + match op { + UnaryOperator::Negation => instructions.push(Instruction::Unm(*reg, *reg)), + } + } + (instructions, registers) + } Expression::FunctionDefinition(params, block) => { let mut inner_scope = Scope::default(); for param in params {