Skip to content

Commit

Permalink
Support CfxLua
Browse files Browse the repository at this point in the history
  • Loading branch information
mdxwzl committed Feb 9, 2025
1 parent aeb4d4b commit b66a9aa
Show file tree
Hide file tree
Showing 154 changed files with 16,907 additions and 179 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"rust-analyzer.cargo.features": ["luau", "lua52", "lua53", "lua54", "luau"]
"rust-analyzer.cargo.features": ["luau", "lua52", "lua53", "lua54", "luau", "cfxlua"]
}
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added
- Implemented CFX Lua as a feature flag - `cfxlua`
- Compound Operators: `+=, -=, *=, /=, <<=, >>=, &=, |=, and ^=`
- Safe Navigation e.g. `t?.x?.y == nil`
- In Unpacking e.g. `local a, b, c = t` is equivalent to `local a, b, c = t.a, t.b, t.c`
- Set Constructors e.g. `t = { .x, .y }` is equivalent to `t = { x = true, y = true }`
- C-Style Comments (single & multiline) e.g. `/* comment */`
- Compile Time Jenkins' Hashes e.g. ``` `Hello, World!` -> 1395890823```

## [1.2.0] - 2025-01-09

### Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</h1>
</div>

A lossless Lua 5.1 / 5.2 / 5.3 / 5.4 / [Luau](https://luau-lang.org/) parser written in Rust.
A lossless Lua 5.1 / 5.2 / 5.3 / 5.4 / [Luau](https://luau-lang.org/) / [CfxLua](https://docs.fivem.net/docs/scripting-manual/runtimes/lua/) parser written in Rust.


## Lossless?
Expand Down
5 changes: 3 additions & 2 deletions full-moon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ license = "MPL-2.0"
readme = "README.md"
repository = "https://github.com/Kampfkarren/full-moon"
categories = ["parsing"]
keywords = ["lua", "parser", "lua51", "lua52", "luau"]
keywords = ["lua", "parser", "lua51", "lua52", "luau", "cfxlua"]
edition = "2021"

[package.metadata.docs.rs]
# Build Locally: RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --features luau,lua52,lua53,lua54,luajit --no-deps --open
features = ["luau", "lua52", "lua53", "lua54", "luajit"]
features = ["luau", "lua52", "lua53", "lua54", "luajit", "cfxlua"]
rustdoc-args = ["--cfg", "docsrs"]

[features]
Expand All @@ -23,6 +23,7 @@ lua52 = []
lua53 = ["lua52"]
lua54 = ["lua53"]
luajit = []
cfxlua = ["lua54"]
no-source-tests = []

[dependencies]
Expand Down
141 changes: 141 additions & 0 deletions full-moon/src/ast/compound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use derive_more::Display;
use serde::{Deserialize, Serialize};
use full_moon_derive::{Node, Visit};
use crate::ast::{Expression, Var};
use crate::tokenizer::{Symbol, TokenReference};

#[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
#[allow(missing_docs)]
#[display("{_0}")]
/// Compound operators, such as X += Y or X -= Y
pub enum CompoundOp {
PlusEqual(TokenReference),
MinusEqual(TokenReference),
StarEqual(TokenReference),
SlashEqual(TokenReference),
CaretEqual(TokenReference),

// luau sepcific
DoubleSlashEqual(TokenReference),
PercentEqual(TokenReference),
TwoDotsEqual(TokenReference),

// cfxlua sepcific
LeftShift(TokenReference),
RightShift(TokenReference),
BitwiseAndAssignment(TokenReference),
BitwiseOrAssignment(TokenReference),
}

impl CompoundOp {
/// The token associated with the operator
pub fn token(&self) -> &TokenReference {
match self {
Self::PlusEqual(token)
| Self::MinusEqual(token)
| Self::StarEqual(token)
| Self::SlashEqual(token)
| Self::DoubleSlashEqual(token)
| Self::PercentEqual(token)
| Self::CaretEqual(token)
| Self::TwoDotsEqual(token)
| Self::LeftShift(token)
| Self::RightShift(token)
| Self::BitwiseAndAssignment(token)
| Self::BitwiseOrAssignment(token) => token,
}
}

pub(crate) fn from_token(token: TokenReference) -> Self {
if token.is_symbol(Symbol::PlusEqual) {
return Self::PlusEqual(token)
} else if token.is_symbol(Symbol::MinusEqual) {
return Self::MinusEqual(token)
} else if token.is_symbol(Symbol::StarEqual) {
return Self::StarEqual(token)
} else if token.is_symbol(Symbol::SlashEqual) {
return Self::SlashEqual(token)
} else if token.is_symbol(Symbol::CaretEqual) {
return Self::CaretEqual(token)
}

#[cfg(feature = "luau")]
if token.is_symbol(Symbol::DoubleSlashEqual) {
return Self::DoubleSlashEqual(token)
} else if token.is_symbol(Symbol::PercentEqual) {
return Self::PercentEqual(token)
} else if token.is_symbol(Symbol::TwoDotsEqual) {
return Self::TwoDotsEqual(token)
}

#[cfg(feature = "cfxlua")]
if token.is_symbol(Symbol::LeftShift) {
return Self::LeftShift(token)
} else if token.is_symbol(Symbol::RightShift) {
return Self::RightShift(token)
} else if token.is_symbol(Symbol::BitwiseAndAssignment) {
return Self::BitwiseAndAssignment(token)
} else if token.is_symbol(Symbol::BitwiseOrAssignment) {
return Self::BitwiseOrAssignment(token)
}

unreachable!("converting an unknown token into a compound operator")
}
}


/// A Compound Assignment statement, such as `x += 1` or `x -= 1`
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{lhs}{compound_operator}{rhs}")]
pub struct CompoundAssignment {
pub(crate) lhs: Var,
pub(crate) compound_operator: CompoundOp,
pub(crate) rhs: Expression,
}

impl CompoundAssignment {
/// Creates a new CompoundAssignment from the left and right hand side
pub fn new(lhs: Var, compound_operator: CompoundOp, rhs: Expression) -> Self {
Self {
lhs,
compound_operator,
rhs,
}
}

/// The variable assigned to, the `x` part of `x += 1`
pub fn lhs(&self) -> &Var {
&self.lhs
}

/// The operator used, the `+=` part of `x += 1`
pub fn compound_operator(&self) -> &CompoundOp {
&self.compound_operator
}

/// The value being assigned, the `1` part of `x += 1`
pub fn rhs(&self) -> &Expression {
&self.rhs
}

/// Returns a new CompoundAssignment with the given variable being assigned to
pub fn with_lhs(self, lhs: Var) -> Self {
Self { lhs, ..self }
}

/// Returns a new CompoundAssignment with the given operator used
pub fn with_compound_operator(self, compound_operator: CompoundOp) -> Self {
Self {
compound_operator,
..self
}
}

/// Returns a new CompoundAssignment with the given value being assigned
pub fn with_rhs(self, rhs: Expression) -> Self {
Self { rhs, ..self }
}
}
2 changes: 1 addition & 1 deletion full-moon/src/ast/lua54.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ impl Attribute {
pub fn with_brackets(self, brackets: ContainedSpan) -> Self {
Self { brackets, ..self }
}
}
}
111 changes: 3 additions & 108 deletions full-moon/src/ast/luau.rs
Original file line number Diff line number Diff line change
Expand Up @@ -893,114 +893,9 @@ impl ExportedTypeFunction {
}
}

#[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[non_exhaustive]
#[allow(missing_docs)]
#[display("{_0}")]
/// Compound operators, such as X += Y or X -= Y
pub enum CompoundOp {
PlusEqual(TokenReference),
MinusEqual(TokenReference),
StarEqual(TokenReference),
SlashEqual(TokenReference),
DoubleSlashEqual(TokenReference),
PercentEqual(TokenReference),
CaretEqual(TokenReference),
TwoDotsEqual(TokenReference),
}

impl CompoundOp {
/// The token associated with the operator
pub fn token(&self) -> &TokenReference {
match self {
Self::PlusEqual(token)
| Self::MinusEqual(token)
| Self::StarEqual(token)
| Self::SlashEqual(token)
| Self::DoubleSlashEqual(token)
| Self::PercentEqual(token)
| Self::CaretEqual(token)
| Self::TwoDotsEqual(token) => token,
}
}

pub(crate) fn from_token(token: TokenReference) -> Self {
if token.is_symbol(Symbol::PlusEqual) {
Self::PlusEqual(token)
} else if token.is_symbol(Symbol::MinusEqual) {
Self::MinusEqual(token)
} else if token.is_symbol(Symbol::StarEqual) {
Self::StarEqual(token)
} else if token.is_symbol(Symbol::SlashEqual) {
Self::SlashEqual(token)
} else if token.is_symbol(Symbol::DoubleSlashEqual) {
Self::DoubleSlashEqual(token)
} else if token.is_symbol(Symbol::PercentEqual) {
Self::PercentEqual(token)
} else if token.is_symbol(Symbol::CaretEqual) {
Self::CaretEqual(token)
} else if token.is_symbol(Symbol::TwoDotsEqual) {
Self::TwoDotsEqual(token)
} else {
unreachable!("converting an unknown token into a compound operator")
}
}
}

/// A Compound Assignment statement, such as `x += 1` or `x -= 1`
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[display("{lhs}{compound_operator}{rhs}")]
pub struct CompoundAssignment {
pub(crate) lhs: Var,
pub(crate) compound_operator: CompoundOp,
pub(crate) rhs: Expression,
}

impl CompoundAssignment {
/// Creates a new CompoundAssignment from the left and right hand side
pub fn new(lhs: Var, compound_operator: CompoundOp, rhs: Expression) -> Self {
Self {
lhs,
compound_operator,
rhs,
}
}

/// The variable assigned to, the `x` part of `x += 1`
pub fn lhs(&self) -> &Var {
&self.lhs
}

/// The operator used, the `+=` part of `x += 1`
pub fn compound_operator(&self) -> &CompoundOp {
&self.compound_operator
}

/// The value being assigned, the `1` part of `x += 1`
pub fn rhs(&self) -> &Expression {
&self.rhs
}

/// Returns a new CompoundAssignment with the given variable being assigned to
pub fn with_lhs(self, lhs: Var) -> Self {
Self { lhs, ..self }
}

/// Returns a new CompoundAssignment with the given operator used
pub fn with_compound_operator(self, compound_operator: CompoundOp) -> Self {
Self {
compound_operator,
..self
}
}

/// Returns a new CompoundAssignment with the given value being assigned
pub fn with_rhs(self, rhs: Expression) -> Self {
Self { rhs, ..self }
}
}
/*
CompoundOp and CompoundAssignment have been moved to `compound.rs´, since CfxLua makes use of them as well.
*/

/// An if statement
#[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
Expand Down
Loading

0 comments on commit b66a9aa

Please sign in to comment.