Preprocessor unexpected indexOutOfBounds

0 votes
asked Dec 19, 2023 in Bug by AI_Mancer (140 points)
Environment:

PlantUML Version: 1.2023.13
IDE: IntelliJ IDEA 2023.2.5
Operating System: Kubuntu 23.10
Java Version: openjdk 17.0.9 2023-10-17 (OpenJDK Runtime Environment build 17.0.9+9-Ubuntu-123.10; OpenJDK 64-Bit Server VM build 17.0.9+9-Ubuntu-123.10, mixed mode, sharing)
Description: Encountered a fatal parsing error in PlantUML when accessing the second element of a split string array. The function $getAttributeName is designed to split a string like "Address_id;1-1" at the semicolon, resulting in an array ["Address_id", "1-1"]. Accessing the first element with $splitAttributes[0] returns "Address_id" as expected. However, attempting to access the second element with $splitAttributes[1] results in a "Fatal parsing error" in PlantUML.

Steps to Reproduce:

Use the $getAttributeName function to split a string at the semicolon.
Access the first element of the resulting array, which works as expected.
Attempt to access the second element of the array.
Expected Result: Accessing the second element should return "1-1" without errors.

Actual Result: PlantUML throws a "Fatal parsing error". Additionally, when running through the console, an "index out of bounds" error is observed, despite the log showing the correct attribute.

Additional Information:

A simplified version of the code excluding the full context works as expected, suggesting a potential issue with state management or memory references in PlantUML.
Renaming the $split variable to avoid potential conflicts (e.g., splitAttributes) does not resolve the issue.
The issue might be related to PlantUML's internal handling of arrays or string operations.
Attachments:

Terminal output showcasing the error.
Complete code where the error occurs.
Simplified version of the code where the error does not occur.
Notes: Open to suggestions or insights that might indicate a different cause for this issue. The behavior suggests a potential bug in PlantUML's handling of array element access or string manipulation.

I do not get how to upload the file, hence I paste it here, sorry :/ :

FullCode (notworking)

```plantuml
@startuml
skinparam linetype ortho
!define pk(x) <b><color:#b8861b><&key></color> x</b>
!define fk(x) <color:#aaaaaa><&key></color> x
!define column(x) <color:#efefef><&media-record></color> x
!function $Rtr($notation)
  !if ($notation == "n")
    !return "}|"
  !elseif ($notation == "cn")
    !return "}o"
  !elseif ($notation == "c")
    !return "|o"
  !elseif ($notation == "1")
    !return "||"
  !endif
!endfunction

!function $Ltr($notation)
  !if ($notation == "n" || $notation == "m")
    !return "|{"
  !elseif ($notation == "cn")
    !return "o{"
  !elseif ($notation == "c")
    !return "o|"
  !elseif ($notation == "1")
    !return "||"
  !endif
!endfunction

!procedure $createRelationalEntity($table1, $table2, $table3)
  ($table1, $table2) -- $table3
!endprocedure

!procedure $rel($table1, $table2, $relationType)
  !if ($relationType == "n-m")
    !$newEntity = $table1 +"_"+ $table2
    $table1 "n"$Rtr("n")--$Ltr("m")"m" $table2
    $createRelationalEntity($table1, $table2, $newEntity): n-m
  !elseif ($relationType == "1-m")
    $table1 "1"$Rtr("1")--$Ltr("m")"m" $table2
  !elseif ($relationType == "n-1")
    $table1 "n"$Rtr("n")--$Ltr("1")"1" $table2
  !elseif ($relationType == "1-1")
    $table1 "1"$Rtr("1")--$Ltr("1")"1" $table2
  !endif
!endprocedure

!procedure $addForeignKey($entityName, $foreignKeyString)
  !$firstRelParam = getFirstRelParam($entityName, $foreignKeyString)
  !$secondRelParam = getSecondRelParam($foreignKeyString)
  !$cardinality = getCardinality($foreignKeyString)
  $rel($firstRelParam, $secondRelParam, $cardinality)
!endprocedure

!function $getTableName($foreignKey)
  !$attributeName = $getAttributeName($foreignKey)
  !$tableName = %splitstr($attributeName, "_")
  !$tableName = $tableName[0]
  !return $tableName
!endfunction

!function $getCardinality($foreignKey)
  !$splitCardinality = %splitstr($foreignKey, ";")
  !log $splitCardinality
  !$cardinality = $splitCardinality[0]
  !return $cardinality
!endfunction

!function $getAttributeName($foreignKey)
  !$splitAttributes = %splitstr($foreignKey, ";")
  !log getAttributeName: fk: $foreignKey Split: $splitAttributes, Split[0], $splitAttributes[0], Split[1]: $splitAttributes[1]
  !$attributeName = $splitAttributes[0]
  !return $attributeName
!endfunction

!function $getFirstRelParam($tableName, $foreignKey)
  !$attributeName = $getAttributeName($foreignKey)
  !return $tableName + "::" + $attributeName
!endfunction

!function $getSecondRelParam($foreignKey)
  !$tableName = $getTableName($foreignKey)
  !return $tableName + "::id"
!endfunction

!procedure $table($name, $fields="attribute1, attribute2, attribute3", $foreignKeys="table1_id;[1-1], table2_id;[1-m], table3_id;[n-m]")
  !$list = %splitstr($fields, ",")
  entity $name {
    pk(id)
    !$fkList = %splitstr($foreignKeys, ",")
          !foreach $fk in $fkList
    $getTableName($fk)
    !endfor
    --
    !foreach $field in $list
        $field
    !endfor
  }
  !$fkList = %splitstr($foreignKeys, ",")
      !foreach $fk in $fkList
          !$firstRelParam = $getFirstRelParam($entityName, $foreignKeyString)
          !$secondRelParam = $getSecondRelParam($foreignKeyString)
          !$cardinality = $getCardinality($foreignKeyString)
          $rel($firstRelParam, $secondRelParam, $cardinality)

      !endfor
!endprocedure

$table("Customers", "name, firstName, dateOfBirth", "Address_id;1-1")

$rel("Customers", "Order", "n-m")
'$rel("Customers", "Seller", "1-m")
'$rel("Order", "Item", "n-1")
$table("Address", "street, houseNumber, zipCode_id", "zipCode_id;[1-1]")
$getSecondRelParam("Address_id;1-1") -- test

@enduml
```

Shortend Code(working):

```plantuml

@startuml
!function $getAttributeName($foreignKey)
  !$split = %splitstr($foreignKey, ";")
  !log getAttributeName: fk: $foreignKey Split: $split, Split[0], $split[0], Split[1]: $split[1]
  !$attributeName = $split[0]
  !return $attributeName
!endfunction

$getAttributeName("Address_id;1-1") -- test

@enduml

```

Log of Fullcode(Could not paste more because of char limit):
```
[Log] getAttributeName: fk: Address_id;1-1 Split: ["Address_id","1-1"], Split[0], Address_id, Split[1]: 1-1

java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1

at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)

```

1 Answer

0 votes
answered Dec 23, 2023 by kirchsth (4,800 points)

Hi AI_Mancer

it is not an error in preprocessor.

You have basically 1 main error in your source (and 2 which could follow):
1) in $table() procedure, you have

      !foreach $fk in $fkList
          !$firstRelParam = $getFirstRelParam($entityName, $foreignKeyString)

    I assume it is copied from $addForeignKey(), and during this step you forgot to set $entityName and $foreignKeyString. With following lines it is working

      !foreach $fk in $fkList
          !$entityName = $name
          !$foreignKeyString = $fk
          !$firstRelParam = $getFirstRelParam($entityName, $foreignKeyString)

2) in the $addForeignKey() procedure you call getFirstRelParam(),.. without `$` like `$getFirstRelParam()`
3) I would avoid !define calls (I think they are outdated, in your case !functions would be the better choice)

BR Helmut


 

commented Dec 28, 2023 by AI_Mancer (140 points)
Thanks a lot. Yeah, the usual copy error one does ^^.

Probably I was blind to my own code at some point ;).
...