Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion src/functions/private/ConvertFrom-LuaTable.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@

# Maximum allowed nesting depth.
[Parameter()]
[int] $MaxDepth = 1024
[int] $MaxDepth = 1024,

# Skip strict Lua grammar validation. Warnings are emitted instead of terminating errors.
[Parameter()]
[switch] $SkipValidation
)

begin {}
Expand All @@ -33,6 +37,7 @@
$script:luaAsPSCustomObject = $AsPSCustomObject.IsPresent
$script:luaMaxDepth = $MaxDepth
$script:luaCurrentDepth = 0
$script:luaSkipValidation = $SkipValidation.IsPresent

Skip-LuaWhitespace

Expand Down Expand Up @@ -81,6 +86,14 @@
}

if ($assignmentDetected) {
# Lua 5.4 reserved words per §3.1
$reservedWords = @(
'and', 'break', 'do', 'else', 'elseif', 'end',
'false', 'for', 'function', 'goto', 'if', 'in',
'local', 'nil', 'not', 'or', 'repeat', 'return',
'then', 'true', 'until', 'while'
)

# Parse one or more assignment statements into an ordered dictionary
$assignments = [ordered]@{}
while ($script:luaPos -lt $script:luaString.Length) {
Expand All @@ -100,6 +113,15 @@
}
$varName = $script:luaString.Substring($identStart, $script:luaPos - $identStart)

# Lua grammar: variable names cannot be reserved words (§3.1)
if ($varName -in $reservedWords) {
if ($script:luaSkipValidation) {
Write-Warning "Reserved word '$varName' used as a variable name at position $identStart."
} else {
throw "Reserved word '$varName' cannot be used as a variable name at position $identStart."
}
}

Skip-LuaWhitespace

# Expect '='
Expand Down
2 changes: 1 addition & 1 deletion src/functions/private/ConvertTo-LuaTable.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
# Enum handling
if ($InputObject -is [enum]) {
if ($EnumsAsStrings) {
$escaped = $InputObject.ToString() -replace '\\', '\\\\' -replace '"', '\"'
$escaped = $InputObject.ToString() -replace '\\', '\\' -replace '"', '\"'
return "`"$escaped`""
}
$underlyingType = [System.Enum]::GetUnderlyingType($InputObject.GetType())
Expand Down
18 changes: 18 additions & 0 deletions src/functions/private/Read-LuaTable.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
begin {}

process {
# Lua 5.4 reserved words per §3.1
$reservedWords = @(
'and', 'break', 'do', 'else', 'elseif', 'end',
'false', 'for', 'function', 'goto', 'if', 'in',
'local', 'nil', 'not', 'or', 'repeat', 'return',
'then', 'true', 'until', 'while'
)

$script:luaCurrentDepth++
if ($script:luaCurrentDepth -gt $script:luaMaxDepth) {
throw "Maximum nesting depth ($($script:luaMaxDepth)) exceeded."
Expand Down Expand Up @@ -78,6 +86,16 @@

if ($script:luaPos -lt $script:luaString.Length -and
$script:luaString[$script:luaPos] -eq '=') {
# Lua grammar: Name cannot be a reserved word (§3.1)
if ($ident -in $reservedWords) {
if ($script:luaSkipValidation) {
Write-Warning "Reserved word '$ident' used as a bare identifier key at position $identStart."
} else {
$msg = "Reserved word '$ident' cannot be used as a bare identifier key" +
" in a Lua table. Use bracket notation: [`"$ident`"] = value."
throw $msg
}
}
# Key = value pair
$script:luaPos++ # skip =
Skip-LuaWhitespace
Expand Down
14 changes: 12 additions & 2 deletions src/functions/public/Lua/ConvertFrom-Lua.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,23 @@

# Output arrays as a single object instead of enumerating elements through the pipeline.
[Parameter()]
[switch] $NoEnumerate
[switch] $NoEnumerate,

# Skip strict Lua grammar validation (e.g., reserved words as bare keys). Warnings are emitted instead of errors.
[Parameter()]
[switch] $SkipValidation
)

begin {}

process {
$result = ConvertFrom-LuaTable -InputString $InputObject -AsPSCustomObject:(-not $AsHashtable) -MaxDepth $Depth
$convertParams = @{
InputString = $InputObject
AsPSCustomObject = -not $AsHashtable
MaxDepth = $Depth
SkipValidation = $SkipValidation.IsPresent
}
$result = ConvertFrom-LuaTable @convertParams
if ($NoEnumerate -and $result -is [System.Array]) {
Write-Output -InputObject $result -NoEnumerate
} else {
Expand Down
51 changes: 51 additions & 0 deletions tests/Lua.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,57 @@ B = { val = 2 }
It 'Throws on assignment with missing value' {
{ ConvertFrom-Lua -InputObject 'A = ' } | Should -Throw '*Unexpected end of input*'
}

It 'Throws on reserved word as bare table key' {
{ ConvertFrom-Lua -InputObject '{ end = 1 }' } | Should -Throw '*Reserved word*'
}

It 'Throws on reserved word as bare table key (while)' {
{ ConvertFrom-Lua -InputObject '{ while = "loop" }' } | Should -Throw '*Reserved word*'
}

It 'Allows reserved words in bracket notation' {
$result = ConvertFrom-Lua -InputObject '{ ["end"] = 1, ["while"] = 2 }' -AsHashtable
$result['end'] | Should -Be 1
$result['while'] | Should -Be 2
}

It 'Throws on reserved word as assignment variable name' {
{ ConvertFrom-Lua -InputObject 'end = 1' } | Should -Throw '*Reserved word*'
}

It 'Throws on reserved word as assignment variable name (while as assignment)' {
{ ConvertFrom-Lua -InputObject 'while = 42' } | Should -Throw '*Reserved word*'
}

It 'SkipValidation allows reserved word as bare table key with warning' {
$result = ConvertFrom-Lua -InputObject '{ end = 1 }' -AsHashtable -SkipValidation 3>&1
$warnings = $result | Where-Object { $_ -is [System.Management.Automation.WarningRecord] }
$output = $result | Where-Object { $_ -isnot [System.Management.Automation.WarningRecord] }
$warnings.Message | Should -BeLike '*Reserved word*end*'
$output['end'] | Should -Be 1
}

It 'SkipValidation allows reserved word as assignment variable name with warning' {
$result = ConvertFrom-Lua -InputObject 'end = 1' -AsHashtable -SkipValidation 3>&1
$warnings = $result | Where-Object { $_ -is [System.Management.Automation.WarningRecord] }
$output = $result | Where-Object { $_ -isnot [System.Management.Automation.WarningRecord] }
$warnings.Message | Should -BeLike '*Reserved word*end*'
$output['end'] | Should -Be 1
}

It 'SkipValidation emits a warning for each reserved word occurrence' {
$result = ConvertFrom-Lua -InputObject '{ end = 1, while = 2, for = 3 }' -AsHashtable -SkipValidation 3>&1
$warnings = @($result | Where-Object { $_ -is [System.Management.Automation.WarningRecord] })
$output = $result | Where-Object { $_ -isnot [System.Management.Automation.WarningRecord] }
$warnings.Count | Should -Be 3
$warnings[0].Message | Should -BeLike '*end*'
$warnings[1].Message | Should -BeLike '*while*'
$warnings[2].Message | Should -BeLike '*for*'
$output['end'] | Should -Be 1
$output['while'] | Should -Be 2
$output['for'] | Should -Be 3
}
}

Context 'Pipeline input' {
Expand Down
Loading