Unified the C# mod and the Rust compiler into a monorepo
This commit is contained in:
1266
rust_compiler/libs/parser/src/lib.rs
Normal file
1266
rust_compiler/libs/parser/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
226
rust_compiler/libs/parser/src/sys_call.rs
Normal file
226
rust_compiler/libs/parser/src/sys_call.rs
Normal file
@@ -0,0 +1,226 @@
|
||||
use crate::tree_node::{Expression, Literal};
|
||||
|
||||
use super::LiteralOrVariable;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Math {
|
||||
/// Returns the angle in radians whose cosine is the specified number.
|
||||
/// ## In Game
|
||||
/// `acos r? a(r?|num)`
|
||||
Acos(LiteralOrVariable),
|
||||
/// Returns the angle in radians whose sine is the specified number.
|
||||
/// ## In Game
|
||||
/// `asin r? a(r?|num)`
|
||||
Asin(LiteralOrVariable),
|
||||
/// Returns the angle in radians whose tangent is the specified number.
|
||||
/// ## In Game
|
||||
/// `atan r? a(r?|num)`
|
||||
Atan(LiteralOrVariable),
|
||||
/// Returns the angle in radians whose tangent is the quotient of the specified numbers.
|
||||
/// ## In Game
|
||||
/// `atan2 r? a(r?|num) b(r?|num)`
|
||||
Atan2(LiteralOrVariable, LiteralOrVariable),
|
||||
/// Gets the absolute value of a number.
|
||||
/// ## In Game
|
||||
/// `abs r? a(r?|num)`
|
||||
Abs(LiteralOrVariable),
|
||||
/// Rounds a number up to the nearest whole number.
|
||||
/// ## In Game
|
||||
/// `ceil r? a(r?|num)`
|
||||
Ceil(LiteralOrVariable),
|
||||
/// Returns the cosine of the specified angle in radians.
|
||||
/// ## In Game
|
||||
/// cos r? a(r?|num)
|
||||
Cos(LiteralOrVariable),
|
||||
/// Rounds a number down to the nearest whole number.
|
||||
/// ## In Game
|
||||
/// `floor r? a(r?|num)`
|
||||
Floor(LiteralOrVariable),
|
||||
/// Computes the natural logarithm of a number.
|
||||
/// ## In Game
|
||||
/// `log r? a(r?|num)`
|
||||
Log(LiteralOrVariable),
|
||||
/// Computes the maximum of two numbers.
|
||||
/// ## In Game
|
||||
/// `max r? a(r?|num) b(r?|num)`
|
||||
Max(LiteralOrVariable, LiteralOrVariable),
|
||||
/// Computes the minimum of two numbers.
|
||||
/// ## In Game
|
||||
/// `min r? a(r?|num) b(r?|num)`
|
||||
Min(LiteralOrVariable, LiteralOrVariable),
|
||||
/// Gets a random number between 0 and 1.
|
||||
/// ## In Game
|
||||
/// `rand r?`
|
||||
Rand,
|
||||
/// Returns the sine of the specified angle in radians.
|
||||
/// ## In Game
|
||||
/// `sin r? a(r?|num)`
|
||||
Sin(LiteralOrVariable),
|
||||
/// Computes the square root of a number.
|
||||
/// ## In Game
|
||||
/// `sqrt r? a(r?|num)`
|
||||
Sqrt(LiteralOrVariable),
|
||||
/// Returns the tangent of the specified angle in radians.
|
||||
/// ## In Game
|
||||
/// `tan r? a(r?|num)`
|
||||
Tan(LiteralOrVariable),
|
||||
/// Truncates a number by removing the decimal portion.
|
||||
/// ## In Game
|
||||
/// `trunc r? a(r?|num)`
|
||||
Trunc(LiteralOrVariable),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Math {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Math::Acos(a) => write!(f, "acos({})", a),
|
||||
Math::Asin(a) => write!(f, "asin({})", a),
|
||||
Math::Atan(a) => write!(f, "atan({})", a),
|
||||
Math::Atan2(a, b) => write!(f, "atan2({}, {})", a, b),
|
||||
Math::Abs(a) => write!(f, "abs({})", a),
|
||||
Math::Ceil(a) => write!(f, "ceil({})", a),
|
||||
Math::Cos(a) => write!(f, "cos({})", a),
|
||||
Math::Floor(a) => write!(f, "floor({})", a),
|
||||
Math::Log(a) => write!(f, "log({})", a),
|
||||
Math::Max(a, b) => write!(f, "max({}, {})", a, b),
|
||||
Math::Min(a, b) => write!(f, "min({}, {})", a, b),
|
||||
Math::Rand => write!(f, "rand()"),
|
||||
Math::Sin(a) => write!(f, "sin({})", a),
|
||||
Math::Sqrt(a) => write!(f, "sqrt({})", a),
|
||||
Math::Tan(a) => write!(f, "tan({})", a),
|
||||
Math::Trunc(a) => write!(f, "trunc({})", a),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum System {
|
||||
/// Pauses execution for exactly 1 tick and then resumes.
|
||||
/// ## In Game
|
||||
/// yield
|
||||
Yield,
|
||||
/// Represents a function that can be called to sleep for a certain amount of time.
|
||||
/// ## In Game
|
||||
/// `sleep a(r?|num)`
|
||||
Sleep(Box<Expression>),
|
||||
/// Gets the in-game hash for a specific prefab name.
|
||||
/// ## In Game
|
||||
/// `HASH("prefabName")`
|
||||
Hash(Literal),
|
||||
/// Represents a function which loads a device variable into a register.
|
||||
/// ## In Game
|
||||
/// `l r? d? var`
|
||||
/// ## Examples
|
||||
/// `l r0 d0 Setting`
|
||||
/// `l r1 d5 Pressure`
|
||||
LoadFromDevice(LiteralOrVariable, Literal),
|
||||
/// Function which gets a LogicType from all connected network devices that match
|
||||
/// the provided device hash and name, aggregating them via a batchMode
|
||||
/// ## In Game
|
||||
/// lbn r? deviceHash nameHash logicType batchMode
|
||||
/// ## Examples
|
||||
/// lbn r0 HASH("StructureWallLight") HASH("wallLight") On Minimum
|
||||
LoadBatchNamed(LiteralOrVariable, Box<Expression>, Literal, Literal),
|
||||
/// Loads a LogicType from all connected network devices, aggregating them via a
|
||||
/// batchMode
|
||||
/// ## In Game
|
||||
/// lb r? deviceHash loggicType batchMode
|
||||
/// ## Examples
|
||||
/// lb r0 HASH("StructureWallLight") On Minimum
|
||||
LoadBatch(LiteralOrVariable, Literal, Literal),
|
||||
/// Represents a function which stores a setting into a specific device.
|
||||
/// ## In Game
|
||||
/// `s d? logicType r?`
|
||||
/// ## Example
|
||||
/// `s d0 Setting r0`
|
||||
SetOnDevice(LiteralOrVariable, Literal, Box<Expression>),
|
||||
/// Represents a function which stores a setting to all devices that match
|
||||
/// the given deviceHash
|
||||
/// ## In Game
|
||||
/// `sb deviceHash logictype r?`
|
||||
/// ## Example
|
||||
/// `sb HASH("Doors") Lock 1`
|
||||
SetOnDeviceBatched(LiteralOrVariable, Literal, Box<Expression>),
|
||||
/// Represents a function which stores a setting to all devices that match
|
||||
/// both the given deviceHash AND the given nameHash
|
||||
/// ## In Game
|
||||
/// `sbn deviceHash nameHash logicType r?`
|
||||
/// ## Example
|
||||
/// `sbn HASH("Doors") HASH("Exterior") Lock 1`
|
||||
SetOnDeviceBatchedNamed(
|
||||
LiteralOrVariable,
|
||||
LiteralOrVariable,
|
||||
Literal,
|
||||
Box<Expression>,
|
||||
),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for System {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
System::Yield => write!(f, "yield()"),
|
||||
System::Sleep(a) => write!(f, "sleep({})", a),
|
||||
System::Hash(a) => write!(f, "hash({})", a),
|
||||
System::LoadFromDevice(a, b) => write!(f, "loadFromDevice({}, {})", a, b),
|
||||
System::LoadBatch(a, b, c) => write!(f, "loadBatch({}, {}, {})", a, b, c),
|
||||
System::LoadBatchNamed(a, b, c, d) => {
|
||||
write!(f, "loadBatchNamed({}, {}, {}, {})", a, b, c, d)
|
||||
}
|
||||
System::SetOnDevice(a, b, c) => write!(f, "setOnDevice({}, {}, {})", a, b, c),
|
||||
System::SetOnDeviceBatched(a, b, c) => {
|
||||
write!(f, "setOnDeviceBatched({}, {}, {})", a, b, c)
|
||||
}
|
||||
System::SetOnDeviceBatchedNamed(a, b, c, d) => {
|
||||
write!(f, "setOnDeviceBatchedNamed({}, {}, {}, {})", a, b, c, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
/// This represents built in functions that cannot be overwritten, but can be invoked by the user as functions.
|
||||
pub enum SysCall {
|
||||
System(System),
|
||||
/// Represents any mathmatical function that can be called.
|
||||
Math(Math),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SysCall {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
SysCall::System(s) => write!(f, "{}", s),
|
||||
SysCall::Math(m) => write!(f, "{}", m),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SysCall {
|
||||
pub fn is_syscall(identifier: &str) -> bool {
|
||||
matches!(
|
||||
identifier,
|
||||
"yield"
|
||||
| "sleep"
|
||||
| "hash"
|
||||
| "loadFromDevice"
|
||||
| "setOnDevice"
|
||||
| "setOnDeviceBatched"
|
||||
| "setOnDeviceBatchedNamed"
|
||||
| "acos"
|
||||
| "asin"
|
||||
| "atan"
|
||||
| "atan2"
|
||||
| "abs"
|
||||
| "ceil"
|
||||
| "cos"
|
||||
| "floor"
|
||||
| "log"
|
||||
| "max"
|
||||
| "min"
|
||||
| "rand"
|
||||
| "sin"
|
||||
| "sqrt"
|
||||
| "tan"
|
||||
| "trunc"
|
||||
)
|
||||
}
|
||||
}
|
||||
21
rust_compiler/libs/parser/src/test/blocks.rs
Normal file
21
rust_compiler/libs/parser/src/test/blocks.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use tokenizer::Tokenizer;
|
||||
|
||||
use crate::Parser;
|
||||
|
||||
#[test]
|
||||
fn test_block() -> anyhow::Result<()> {
|
||||
let mut parser = crate::parser!(
|
||||
r#"
|
||||
{
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
}
|
||||
"#
|
||||
);
|
||||
|
||||
let expression = parser.parse()?.unwrap();
|
||||
|
||||
assert_eq!("{ (let x = 5); (let y = 10); }", expression.to_string());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
115
rust_compiler/libs/parser/src/test/mod.rs
Normal file
115
rust_compiler/libs/parser/src/test/mod.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
#[macro_export]
|
||||
macro_rules! parser {
|
||||
($input:expr) => {
|
||||
Parser::new(Tokenizer::from($input.to_owned()))
|
||||
};
|
||||
}
|
||||
|
||||
mod blocks;
|
||||
use super::Parser;
|
||||
use super::Tokenizer;
|
||||
use anyhow::Result;
|
||||
|
||||
#[test]
|
||||
fn test_unsupported_keywords() -> Result<()> {
|
||||
let mut parser = parser!("enum x;");
|
||||
assert!(parser.parse().is_err());
|
||||
|
||||
let mut parser = parser!("if x {}");
|
||||
assert!(parser.parse().is_err());
|
||||
|
||||
let mut parser = parser!("else {}");
|
||||
assert!(parser.parse().is_err());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_declarations() -> Result<()> {
|
||||
let input = r#"
|
||||
let x = 5;
|
||||
// The below line should fail
|
||||
let y = 234
|
||||
"#;
|
||||
let tokenizer = Tokenizer::from(input.to_owned());
|
||||
let mut parser = Parser::new(tokenizer);
|
||||
|
||||
let expression = parser.parse()?.unwrap();
|
||||
|
||||
assert_eq!("(let x = 5)", expression.to_string());
|
||||
|
||||
assert!(parser.parse().is_err());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_function_expression() -> Result<()> {
|
||||
let input = r#"
|
||||
// This is a function. The parser is starting to get more complex
|
||||
fn add(x, y) {
|
||||
let z = x;
|
||||
}
|
||||
"#;
|
||||
|
||||
let tokenizer = Tokenizer::from(input.to_owned());
|
||||
let mut parser = Parser::new(tokenizer);
|
||||
|
||||
let expression = parser.parse()?.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
"(fn add(x, y) { { (let z = x); } })",
|
||||
expression.to_string()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_function_invocation() -> Result<()> {
|
||||
let input = r#"
|
||||
add();
|
||||
"#;
|
||||
|
||||
let tokenizer = Tokenizer::from(input.to_owned());
|
||||
let mut parser = Parser::new(tokenizer);
|
||||
|
||||
let expression = parser.parse()?.unwrap();
|
||||
|
||||
assert_eq!("add()", expression.to_string());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_priority_expression() -> Result<()> {
|
||||
let input = r#"
|
||||
let x = (4);
|
||||
"#;
|
||||
|
||||
let tokenizer = Tokenizer::from(input.to_owned());
|
||||
let mut parser = Parser::new(tokenizer);
|
||||
|
||||
let expression = parser.parse()?.unwrap();
|
||||
|
||||
assert_eq!("(let x = (4))", expression.to_string());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_binary_expression() -> Result<()> {
|
||||
let expr = parser!("4 ** 2 + 5 ** 2").parse()?.unwrap();
|
||||
assert_eq!("((4 ** 2) + (5 ** 2))", expr.to_string());
|
||||
|
||||
let expr = parser!("2 ** 3 ** 4").parse()?.unwrap();
|
||||
assert_eq!("(2 ** (3 ** 4))", expr.to_string());
|
||||
|
||||
let expr = parser!("45 * 2 - 15 / 5 + 5 ** 2").parse()?.unwrap();
|
||||
assert_eq!("(((45 * 2) - (15 / 5)) + (5 ** 2))", expr.to_string());
|
||||
|
||||
let expr = parser!("(5 - 2) * 10").parse()?.unwrap();
|
||||
assert_eq!("(((5 - 2)) * 10)", expr.to_string());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
258
rust_compiler/libs/parser/src/tree_node.rs
Normal file
258
rust_compiler/libs/parser/src/tree_node.rs
Normal file
@@ -0,0 +1,258 @@
|
||||
use super::sys_call::SysCall;
|
||||
use tokenizer::token::Number;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub enum Literal {
|
||||
Number(Number),
|
||||
String(String),
|
||||
Boolean(bool),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Literal {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Literal::Number(n) => write!(f, "{}", n),
|
||||
Literal::String(s) => write!(f, "\"{}\"", s),
|
||||
Literal::Boolean(b) => write!(f, "{}", if *b { 1 } else { 0 }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum BinaryExpression {
|
||||
Add(Box<Expression>, Box<Expression>),
|
||||
Multiply(Box<Expression>, Box<Expression>),
|
||||
Divide(Box<Expression>, Box<Expression>),
|
||||
Subtract(Box<Expression>, Box<Expression>),
|
||||
Exponent(Box<Expression>, Box<Expression>),
|
||||
Modulo(Box<Expression>, Box<Expression>),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for BinaryExpression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
BinaryExpression::Add(l, r) => write!(f, "({} + {})", l, r),
|
||||
BinaryExpression::Multiply(l, r) => write!(f, "({} * {})", l, r),
|
||||
BinaryExpression::Divide(l, r) => write!(f, "({} / {})", l, r),
|
||||
BinaryExpression::Subtract(l, r) => write!(f, "({} - {})", l, r),
|
||||
BinaryExpression::Exponent(l, r) => write!(f, "({} ** {})", l, r),
|
||||
BinaryExpression::Modulo(l, r) => write!(f, "({} % {})", l, r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum LogicalExpression {
|
||||
And(Box<Expression>, Box<Expression>),
|
||||
Or(Box<Expression>, Box<Expression>),
|
||||
Not(Box<Expression>),
|
||||
Equal(Box<Expression>, Box<Expression>),
|
||||
NotEqual(Box<Expression>, Box<Expression>),
|
||||
GreaterThan(Box<Expression>, Box<Expression>),
|
||||
GreaterThanOrEqual(Box<Expression>, Box<Expression>),
|
||||
LessThan(Box<Expression>, Box<Expression>),
|
||||
LessThanOrEqual(Box<Expression>, Box<Expression>),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for LogicalExpression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
LogicalExpression::And(l, r) => write!(f, "({} && {})", l, r),
|
||||
LogicalExpression::Or(l, r) => write!(f, "({} || {})", l, r),
|
||||
LogicalExpression::Not(e) => write!(f, "(!{})", e),
|
||||
LogicalExpression::Equal(l, r) => write!(f, "({} == {})", l, r),
|
||||
LogicalExpression::NotEqual(l, r) => write!(f, "({} != {})", l, r),
|
||||
LogicalExpression::GreaterThan(l, r) => write!(f, "({} > {})", l, r),
|
||||
LogicalExpression::GreaterThanOrEqual(l, r) => write!(f, "({} >= {})", l, r),
|
||||
LogicalExpression::LessThan(l, r) => write!(f, "({} < {})", l, r),
|
||||
LogicalExpression::LessThanOrEqual(l, r) => write!(f, "({} <= {})", l, r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct AssignmentExpression {
|
||||
pub identifier: String,
|
||||
pub expression: Box<Expression>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AssignmentExpression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "({} = {})", self.identifier, self.expression)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct FunctionExpression {
|
||||
pub name: String,
|
||||
pub arguments: Vec<String>,
|
||||
pub body: BlockExpression,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for FunctionExpression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"(fn {}({}) {{ {} }})",
|
||||
self.name,
|
||||
self.arguments.to_vec().join(", "),
|
||||
self.body
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct BlockExpression(pub Vec<Expression>);
|
||||
|
||||
impl std::fmt::Display for BlockExpression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{{ {}; }}",
|
||||
self.0
|
||||
.iter()
|
||||
.map(|e| e.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("; ")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct InvocationExpression {
|
||||
pub name: String,
|
||||
pub arguments: Vec<Expression>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for InvocationExpression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}({})",
|
||||
self.name,
|
||||
self.arguments
|
||||
.iter()
|
||||
.map(|e| e.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum LiteralOrVariable {
|
||||
Literal(Literal),
|
||||
Variable(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for LiteralOrVariable {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
LiteralOrVariable::Literal(l) => write!(f, "{}", l),
|
||||
LiteralOrVariable::Variable(v) => write!(f, "{}", v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct DeviceDeclarationExpression {
|
||||
/// any variable-like name
|
||||
pub name: String,
|
||||
/// The device port, ex. (db, d0, d1, d2, d3, d4, d5)
|
||||
pub device: String,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DeviceDeclarationExpression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "(device {} = {})", self.name, self.device)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct IfExpression {
|
||||
pub condition: Box<Expression>,
|
||||
pub body: BlockExpression,
|
||||
pub else_branch: Option<Box<Expression>>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for IfExpression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "(if ({}) {}", self.condition, self.body)?;
|
||||
if let Some(else_branch) = &self.else_branch {
|
||||
write!(f, " else {}", else_branch)?;
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct LoopExpression {
|
||||
pub body: BlockExpression,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for LoopExpression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "(loop {})", self.body)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct WhileExpression {
|
||||
pub condition: Box<Expression>,
|
||||
pub body: BlockExpression,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for WhileExpression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "(while {} {})", self.condition, self.body)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Expression {
|
||||
Assignment(AssignmentExpression),
|
||||
Binary(BinaryExpression),
|
||||
Block(BlockExpression),
|
||||
Break,
|
||||
Continue,
|
||||
Declaration(String, Box<Expression>),
|
||||
DeviceDeclaration(DeviceDeclarationExpression),
|
||||
Function(FunctionExpression),
|
||||
If(IfExpression),
|
||||
Invocation(InvocationExpression),
|
||||
Literal(Literal),
|
||||
Logical(LogicalExpression),
|
||||
Loop(LoopExpression),
|
||||
Negation(Box<Expression>),
|
||||
Priority(Box<Expression>),
|
||||
Return(Box<Expression>),
|
||||
Syscall(SysCall),
|
||||
Variable(String),
|
||||
While(WhileExpression),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Expression {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Expression::Assignment(e) => write!(f, "{}", e),
|
||||
Expression::Binary(e) => write!(f, "{}", e),
|
||||
Expression::Block(e) => write!(f, "{}", e),
|
||||
Expression::Break => write!(f, "break"),
|
||||
Expression::Continue => write!(f, "continue"),
|
||||
Expression::Declaration(id, e) => write!(f, "(let {} = {})", id, e),
|
||||
Expression::DeviceDeclaration(e) => write!(f, "{}", e),
|
||||
Expression::Function(e) => write!(f, "{}", e),
|
||||
Expression::If(e) => write!(f, "{}", e),
|
||||
Expression::Invocation(e) => write!(f, "{}", e),
|
||||
Expression::Literal(l) => write!(f, "{}", l),
|
||||
Expression::Logical(e) => write!(f, "{}", e),
|
||||
Expression::Loop(e) => write!(f, "{}", e),
|
||||
Expression::Negation(e) => write!(f, "(-{})", e),
|
||||
Expression::Priority(e) => write!(f, "({})", e),
|
||||
Expression::Return(e) => write!(f, "(return {})", e),
|
||||
Expression::Syscall(e) => write!(f, "{}", e),
|
||||
Expression::Variable(id) => write!(f, "{}", id),
|
||||
Expression::While(e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user