Add unary operators

This commit is contained in:
Sofia 2026-03-16 16:53:52 +02:00
parent f3870e2e1a
commit 0fca17defb
2 changed files with 81 additions and 34 deletions

View File

@ -284,6 +284,7 @@ pub enum AccessModifier {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Expression { pub enum Expression {
ValueRef(String), ValueRef(String),
UnOp(UnaryOperator, Box<Node<Expression>>),
BinOp(BinaryOperator, Box<Node<Expression>>, Box<Node<Expression>>), BinOp(BinaryOperator, Box<Node<Expression>>, Box<Node<Expression>>),
FunctionDefinition(Vec<Node<String>>, Block), FunctionDefinition(Vec<Node<String>>, Block),
FunctionCall(Box<Node<Expression>>, Node<ExpressionList>), FunctionCall(Box<Node<Expression>>, Node<ExpressionList>),
@ -318,6 +319,24 @@ impl Parse for ExpressionList {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PrimaryExpression(Node<Expression>); pub struct PrimaryExpression(Node<Expression>);
#[derive(Debug, Clone, Copy)]
pub enum UnaryOperator {
Negation,
}
impl Parse for UnaryOperator {
fn parse(mut stream: TokenStream) -> Result<Self, TokenStreamError> {
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)] #[derive(Debug, Clone, Copy)]
pub enum BinaryOperator { pub enum BinaryOperator {
And, And,
@ -347,10 +366,49 @@ impl BinaryOperator {
} }
} }
impl Parse for BinaryOperator {
fn parse(mut stream: TokenStream) -> Result<Self, TokenStreamError> {
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 { impl Parse for PrimaryExpression {
fn parse(mut stream: TokenStream) -> Result<Self, TokenStreamError> { fn parse(mut stream: TokenStream) -> Result<Self, TokenStreamError> {
let pre = Metadata::pre(&mut stream, "expression")?; let pre = Metadata::pre(&mut stream, "expression")?;
let mut unary_operators = Vec::new();
while let Ok(unop) = stream.parse::<UnaryOperator>() {
unary_operators.push(unop);
}
let peeked = stream.peek(); let peeked = stream.peek();
let mut expression = if peeked == Some(Token::Keyword(Keyword::Function)) { let mut expression = if peeked == Some(Token::Keyword(Keyword::Function)) {
let function = stream.parse::<Node<Function>>()?; let function = stream.parse::<Node<Function>>()?;
@ -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 { Ok(PrimaryExpression(Node {
kind: expression, kind: expression,
meta: Metadata::produce(&mut stream, pre), meta: Metadata::produce(&mut stream, pre),
@ -421,39 +489,6 @@ fn parse_binop_rhs(
Ok(lhs.0) Ok(lhs.0)
} }
impl Parse for BinaryOperator {
fn parse(mut stream: TokenStream) -> Result<Self, TokenStreamError> {
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)] #[derive(Debug, Clone, Copy)]
pub enum Literal { pub enum Literal {
Number(LuaNumber), Number(LuaNumber),

View File

@ -1,7 +1,7 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use crate::{ use crate::{
ast::{AccessModifier, BinaryOperator, Block, Expression, Literal, Statement}, ast::{AccessModifier, BinaryOperator, Block, Expression, Literal, Statement, UnaryOperator},
vm::{Constant, Instruction, VMNumber}, vm::{Constant, Instruction, VMNumber},
}; };
@ -258,6 +258,7 @@ impl Expression {
constants.extend(rhs.kind.find_constants(scope)); constants.extend(rhs.kind.find_constants(scope));
constants constants
} }
Expression::UnOp(_, expr) => expr.kind.find_constants(scope),
Expression::FunctionDefinition(_, block) => block.find_constants(scope), Expression::FunctionDefinition(_, block) => block.find_constants(scope),
Expression::FunctionCall(expr, params) => { Expression::FunctionCall(expr, params) => {
let mut constants = HashSet::new(); let mut constants = HashSet::new();
@ -371,6 +372,17 @@ impl Expression {
}; };
(instructions, vec![reg]) (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 &registers {
match op {
UnaryOperator::Negation => instructions.push(Instruction::Unm(*reg, *reg)),
}
}
(instructions, registers)
}
Expression::FunctionDefinition(params, block) => { Expression::FunctionDefinition(params, block) => {
let mut inner_scope = Scope::default(); let mut inner_scope = Scope::default();
for param in params { for param in params {