# ELPL (English Like Programming Language)
 ## Written and Created by Syed Ishaq (Software and Systems Engineer)

 **First release v6.6.6**

> current version `7.1.3`

[Visit website](https://mujtabaishaq5.github.io/ELPL-Official/ "Visit website to check further resources and more details about ELPL")

```elpl
// initial version
let x be 5
let y be 10

print "Initial values: " x " and " y

if x is less than y then{
  print "x is less than y"
}otherwise{
  print "x is not less than y"
}
repeat 3 times {
  print "Repeating" x
}

while x is less than 10 {
  print "Incrementing x:" x
  let x be x add 1
}

function greet() {
  print "Hello from function!"
}

call greet()

let result be y multiply x
print "x * y = " result

let condition be true
if condition is equal to true then{
  print "Condition is true"
  }otherwise{
  print "Condition is false"
}
let a be not false
print "a (not false) = " a
```


```elpl
Array nums be [1, 2, 3, 4]

let sums be 0
for i be 0 to length(nums) {
    let sums be sums add nums[i]
}

print sums  // prints: 10

print nums[1]  // prints: 2

// this is a single line comment
>>>This is a multi line 
comment<<<

///---in newer version above 6.0.1 Beta----
// single comment
>>> Multi-line<<<

```
> Some more examples

```elpl

for i be 0 to 5 {
  print "Loop at i ="
  print i
  if i is equal to 3 then {
    print "Stopping at i = 3"
    stop
  }
}
print "Loop ended"
```
> output below


`Loop at i =` 
`0` 
`otherwise case` 
`Loop at i =` 
`1` 
`otherwise case` 
`Loop at i = `
`2` 
`otherwise case` 
`Loop at i =` 
`3` 
`Stopping at i = 3` 
`Loop ended` 

```elpl
Array nums be [2,7,11,15]

let target be 9

for i be 0 to 3 {
   for j be 1 to 3{
  if nums[i] add nums[j] is equal to target then{
  print "Indices: "
  print i j
  stop    // for ‘break’
} otherwise {
     print "no found"
        }

     }
    stop
}
```

> Recursion


```elpl
function factorial(n) {
    if n is equal to 0 then {
        return 1
    }
    return n multiply factorial(n subtract 1)
}

call factorial(5)      // prints: 120


//RECURSION USING ARRAYS

Array memo be [0,0,0,0,0,0,0]

function fibonacci(n) {
    if n is less than 2 then {
        return n
    }

    if not (memo[n] is equal to 0) then {
        return memo[n]
    }

    let a be call fibonacci(n subtract 1)
    let b be call fibonacci(n subtract 2)
    let memo[n] be a add b
    return memo[n]
}

print "Fibonacci(6) = " fibonacci(6)    // Fibonacci(6) = 8

```

> Solving twoSum 
```elpl
Array nums be [2,7,11,15]

let target be 9


for i be 0 to 3{
   for j be 1 to 3 {
   if nums[i] add nums[j] is equal to target then {
   print "indices: " i j
    stop // will break the loop
    }  otherwise {
  print "no pair found"
         }

       }
     stop

      } // prints : indices : 0 1

//===============

Array nums be [1,1,1,1]


let sums be 0

for i be 0 to length(nums){
 let sums be sums add nums[i]
}

print sums  // output : 4
//===============
```

> LOGICALS
```elpl
let flag be false

if not flag then {
    print "Flag is false"
} otherwise {
    print "Flag is true"
}

let a be true
let b be false

if a and not b then {
    print "Logical expression works!"
}
```
> solving twoSum using Built-In function length
```elpl
Array nums be [2, 7, 11, 15]
let target be 9
let found be false

for i be 0 to length(nums){
    for j be i add 1 to length(nums){
        let sums be nums[i] add nums[j]
        print "checking pair: " i j " sum: " sums
        if sums is equal to target then {
            print "indices: " i j
            let found be true
            stop
        } otherwise{
        print "pair no found"
        }
    }
   
        stop
    
}
//=================
Array nums be [2, 7, 11, 15]
let target be 9
let found be false
Array result be [-1, -1]

for i be 0 to length(nums) subtract 1 {
    for j be i add 1 to length(nums) subtract 1 {
        let sum be nums[i] add nums[j]
        print "checking pair:" i j "sum:" sum

        if sum is equal to target then {
            let found be true
            let result[0] be i
            let result[1] be j
            stop
        }
    }
    if found is equal to true then {
        stop
    }
}

if found is equal to true then {
    print "indices: " result[0] result[1]
} otherwise {
    print "no pair found"
}
```

> REVERSING AN ARRAYs
```elpl
Array nums be [3, 9, 12,11]
Array reversed be []

for i be 0 to length(nums){
    let reversed[i] be nums[length(nums) subtract 1 subtract i]
}

print reversed


//IN place reversal

Array nums be [2, 7, 11, 15]
let n be length(nums)
let mid be n divide 2

for i be 0 to mid subtract 1 {
    let temp be nums[i]
    let nums[i] be nums[n subtract 1 subtract i]
    let nums[n subtract 1 subtract i] be temp
}

print nums

```
> Recursion sum of Arrays
```elpl
function sumArray(arr, i) {
    if i is equal to length(arr) then {
        return 0
    }
    return arr[i] add call sumArray(arr, i add 1)
}

Array nums be [1, 2, 3, 4, 5]
call sumArray(nums, 0)



//More recursive function

function power(x, n) {
    if n is equal to 0 then {
        return 1
    }
    return x multiply call power(x, n subtract 1)
}

call power(2, 4) / should print 16

```
> threeSum Solution
```elpl
Array nums be [-1, 0, 1, 2, -1, -4]


for i be 0 to length(nums) subtract 3 {
  for j be i add 1 to length(nums) subtract 2 {
    for k be j add 1 to length(nums){
      let sums be nums[i] add nums[j] add nums[k]
     print "checking triple: " i j k " sum: " sums
     if sums is equal to 0 then {
       print "FOUND triple at indices: " i j k " sum: " sums

  stop
}

       otherwise {
        print "not a valid triple"
      }
    }
stop
   
  }
stop
 
}

//threeSum solution simpler

Array nums be [-1, 0, 1, 2, -1, -4]


for i be 0 to length(nums) subtract 2 {
  for j be i add 1 to length(nums) subtract 1 {
    for k be j add 1 to length(nums) {
      let sums be nums[i] add nums[j] add nums[k]
     print "checking triple: " i j k " sum: " sums
     if sums is equal to 0 then {
       print "FOUND triple at indices: " i j k " sum: " sums
  stop
  }

       otherwise {
        print "not a valid triple"
      }
    }
 stop
    
  }
stop
  
}
```
> fourSum solution
```elpl
Array nums be [1, 0, -1, 0, -2, 2]
let target be 0


for i be 0 to length(nums) subtract 3 {
  for j be i add 1 to length(nums) subtract 2 {
    for k be j add 1 to length(nums){
      for l be k add 1 to length(nums) {
        let sums be nums[i] add nums[j] add nums[k] add nums[l]
        print "checking quadruple: " i j k l " sum: " sums
        if sums is equal to target then {
          print "FOUND quadruple at indices: " i j k l " sum: " sums
          
          stop
        } otherwise {
          print "not a valid quadruple"
        }
        
      }
      stop
    }
    stop
  }
  stop
}
```

> fiveSum solution
```elpl
Array nums be [-2, -1, 0, 1, 2, 3]
let target be 3


for i be 0 to length(nums) subtract 5 {
 for j be i add 1 to length(nums) subtract 4 {
  for k be j add 1 to length(nums) subtract 3 {
   for l be k add 1 to length(nums) subtract 2 {
    for m be l add 1 to length(nums){
     let sums be nums[i] add nums[j] add nums[k] add nums[l] add nums[m]
     print "checking quintuple: " i j k l m " sum: " sums
     if sums is equal to target then {
      print "FOUND quintuple at indices: " i j k l m " sum: " sums
    
      stop
     } otherwise {
     print "not found"
     } 
    }
    stop
   }
   
  }
  stop
 }
 stop
}
```
> Recursion
```elpl
function fib(n){
if n is less than or equal to 1 then {
return n
} otherwise {
 let a be fib(n subtract 1)
 let b be fib(n subtract 2)
 return a add b
}



}

for i be 0 to 30{
print call fib(i)
}     
```
### Output

`0`

`1`

`1`

`2`

`3`

`5`

`8`

`13`

`21`

`34`

`55`

`89`

`144`

`233`

`377`

`610`

`987`

`1597`

`2584`

`4181`

`6765`

`10946`

`17711`

`28657`

`46368`

`75025`

`121393`

`196418`

`317811`

`514229`

`832040`

> Backtracking and recursion
```elpl
function subsetSum(nums, index, target) {
    print"subsetSum called with index = " index ", target = " target

    if target is equal to 0 then {
        print"Target reached 0 — returning true"
        return true
    }

    if index is equal to length(nums) then {
        print"Reached end of array — returning false"
        return false
    }

    if nums[index] is less than or equal to target then {
        print"Trying including nums[" index "] = " nums[index]
        if call subsetSum(nums, index add 1, target subtract nums[index]) then {
            print"Path including nums[" index "] worked — returning true"
            return true
        }
    }

    print"Trying excluding nums[" index "] = " nums[index]
    let result be call subsetSum(nums, index add 1, target)
    print"Result after excluding nums[" index "]: " result
    return result
}

Array nums be [3, 4, 5, 2]
let target be 9
let result be call subsetSum(nums, 0, target)
print"Final result: " result


// Recursion fibonacci
function fib(n) {
    if n is equal to 0 then {
        return 0
    }
    if n is equal to 1 then {
        return 1
    }
    let a be fib(n subtract 1) 
    let b be fib(n subtract 2)
    return a add b
}

let result be fib(6)
print "Fib(6): " result

```
> Palindrome 
```elpl
function isPalindrome(s, left, right) {
    if left is greater than or equal to right then {
        return true
    }

    if s[left] not equal to s[right] then {
        return false
    }

    return isPalindrome(s, left add 1, right subtract 1)
}

/ Test case
Array word be ["r", "a", "c", "e", "c", "a", "r"]
let result be isPalindrome(word, 0, length(word) subtract 1)
print "Is Palindrome: " result


```
> 2D Arrays 
```elpl
Array nums be [[0,2,3],[2,3,4]]

let total be 0

for i be 0 to length(nums){
  for j be 0 to length(nums[i]){
     total pels nums[i][j] 
  }
}

print total  // output: 14
```
> Maps
```elpl
Map[key,value] mymap be {1: "a", 2: "b", 3: "c", 5: "v"}

foreach k,v : mymap{
   print "key: "k "value: " v
} 

```
## Taking input   

> **Note:** input() has been deprecated and replaced with scan()     
     
```elpl
let name be scan(“Enter your name: ”)

print “Hello, ”name    // Hello, <your entry>


//More on Maps

Map[key,value] m be {1:"a", 2:"b"}


m.put(3, "c")
print m.size() 
print m[3]        //  3 c   
                     


Map[k,v] m be {1: "a", 2: "b"}
foreach k,v : m {             >>>new loop foreach works with arrays and maps both<<<
   print k v
}

```
## Interoperability with java
`This style of interoperability has been deprecated only valid in v6.7.3`

```elpl

let n be 10
float f be 3.5
let msg be "Hello"

@java {
    vars.put("z", (int) vars.get("n") + 5);
    vars.put("pi", 3.14159);
    vars.put("shout", ((String) vars.get("msg")).toUpperCase());
}

print n      // 10
print f      // 3.5
print msg    // Hello
print z      // 15 (int)
print pi     // 3.14159 (double, formatted)
print shout  // HELLO


let x be 5
float y be 2.5
let name be "Syed Ishaq"

@java {
    double z = VarUtils.getNumber(vars, "x");
    double p = Math.pow(VarUtils.getNumber(vars, "y"), 3);
    String s = "Hello " + VarUtils.getString(vars, "name");

    vars.put("z", z);
    vars.put("p", p);
    vars.put("greeting", s);
}

print z
print p
print greeting



// ====> v6.7.3 <=====

Map[k,v] mymap be {1: "a", 2: "b"}

mymap.put(3, "c")       // add a new key-value
print mymap.size()       // 3

if mymap.has(2) then {
  print "key 2 exists"
}

mymap.delete(1)          // remove key 1
print mymap.has(1)       // false

mymap.clear()            // remove all entries
print mymap.size()       // 0


```
### two Sum in Maps
```elpl

function twoSum(nums, target) {
Map[k,v] map be {} // initialize empty map
for i be 0 to length(nums){
let complement be target subtract nums[i]
// check if complement exists in map
if map.has(complement) then {
return [map[complement], i]
}
// store current number with its index in map
map[nums[i]] be i
}
return [] // return empty array if no solution
}
// Example usage
Array nums be [2, 7, 11, 15]
let target be 9
let result be call twoSum(nums, target)
print "Indices:" result

//-------------with Interop

Map[key,value] numsMap be {2: 0, 7: 1, 11: 2, 15: 3}
let target be 9
@java {
  // Implement twoSum using the Map from ELPL
  for (Map.Entry<Object,Object> entry : numsMap.entrySet()) {
    int num = (int) entry.getKey();
     int index = (int) entry.getValue();
     int complement = target - num;
    if (numsMap.containsKey(complement) && (int)       numsMap.get(complement) != index) {
    System.out.println("__ELPL_VAR__b=" + index + ", " +    numsMap.get(complement));
  break;
     }
   }
}
print "Found Indices:"b
```
### Exception handling
```elpl
try {
print "Before throw"
throw "Something went wrong"
print "After throw"
} catch e {
print "Caught: "e
}

//Another example

try {
print "Outer try"
try {
throw "Inner error"
} catch inner {
print "Caught inner: " inner
throw "Escalate"
}
} catch outer {
print "Caught outer: " outer
}

function riskyDivide(a, b) {
    if b is equal to 0 then{
    throw "Division by zero"
   }
  return a divide b
  }
try  {
   call riskyDivide(10, 0)
  } catch ex {
  print "Error caught: " ex
}

```
> Lists
```elpl
// Simple numeric list
List nums be [10, 20, 30]

// Heterogeneous types
List mixed be ["apple", true, 99]

// Nested lists
List matrix be [[1, 2], [3, 4], [5, 6]]



// Expressions inside
List calc be [2 add 2, 5 multiply 3, length([1,2,3])]

print matrix
print calc
print nums

// =====> Another example <=====

List nums be [10, 20, 30]
nums.insert(1, 15)       // inserts 15 at index 1
nums.append(50)      // adds 40 at end
nums.remove(2)        // removes 3rd element
print nums             

```
> **v6.7.9**
```elpl
use elpl.sys.io // Introducing standard library for I/O
//example use
let dataFile be "myData.cpp"
io.write(dataFile, "#include <iostream> int main(){ return 0;}")
let content be io.read(dataFile)
print content

// =====> Another example

use elpl.sys.io
let file be "Test.java"
try {
io.write(file, "public class Test { // check java}")
io.append(file, "public static void main(String[] mine){}")
io.delete(file)
let content be io.readLines(file)
print content
} catch error {
print "Error: "error
}
```
## OBJECT ORIENTED PROGRAMMING
```elpl
class myclass {
    let name be " "

    myclass(newName) {
        this.name be newName
    }

    function greet() {
        print "Hello," this.name
    }
}
let p be new myclass("Ishaq")
print p.greet()
```
### v6.8.3

 > 4x4 sudoko solver in ELPL
     
```elpl
  function get(board, row, col){
  return board[row multiply 4 add col]
  }
 function set(board, row, col, value){
 let board[row multiply 4 add col] be value
 }
  function isSafe(board, row, col, num){
 // row check
 for c be 0 to 4 subtract 1{
 if get(board, row, c) is equal to num then {
 return false
 }
 }
 // col check
 for r be 0 to 4 subtract 1{
 if get(board, r, col) is equal to num then {
 return false
  }
}
  // 2x2 subgrid
  let startRow be row subtract (row mod 2)
  let startCol be col subtract (col mod 2)
   for r be 0 to 2 subtract 1{
  for c be 0 to 2 subtract 1{
  if get(board, startRow add r, startCol add c) is equal to num then {
   return false
   }
  }
 }
  return true
 }
    function solve(board){
   for row be 0 to 4 subtract 1{
   for col be 0 to 4 subtract 1 {
   if get(board, row, col) is equal to 0 then {
   // try numbers 1 to 4
   for num be 1 to 5 subtract 1{
   if isSafe(board, row, col, num) then {
   set(board, row, col, num)
   if solve(board) then {
   return true
  }
  set(board, row, col, 0)
  }
 }
   return false
  }

   }
  }
  return true
}
         function Print(board){
        for r be 0 to 4 subtract 1{
          for c be 0 to 4 subtract 1{
             print get(board, r, c) " "
    }
     print " "
    }
  }
  Array board be [
   1,0,0,4,
   0,0,0,0,
   0,0,0,0,
   3,0,0,2
  ]
   if solve(board) then {
   Print(board)
   } otherwise {
   print "No solution found."
}
```
> ***8x8 sudoko solver(6.8.4)***
```elpl
     Array board be [
    [1,0,0,0, 0,0,0,2],
    [0,0,0,0, 3,0,0,0],
    [0,0,0,4, 0,0,0,0],
    [0,5,0,0, 0,6,0,0],
    [0,0,7,0, 0,0,4,0],
    [0,0,0,0, 5,0,0,0],
    [0,0,0,0, 0,8,0,0],
    [3,0,0,0, 0,0,0,1]
    ]
    function isSafe(board, row, col, num){
   // row check
   for c be 0 to 8 subtract 1 {
   if board[row][c] is equal to num then{
   return false
   }
  }
  // col check
   for r be 0 to 8 subtract 1 {
   if board[r][col] is equal to num then{
   return false
   }
 }
   // subgrid check (2x4)
   let startRow be row subtract (row mod 2)
   let startCol be col subtract (col mod 4)
      for r be 0 to 2 subtract 1 {
          for c be 0 to 4 subtract 1 {
             if board[startRow add r][startCol add c] is equal to num then{
                          return false
            }
       }
   }
        return true
  }
            function solve(board){
        for row be 0 to 8 subtract 1 {
             for col be 0 to 8 subtract 1 {
                if board[row][col] is equal to 0 then {
                             for num be 1 to 8 {
        if isSafe(board, row, col, num) then{
              let board[row][col] be num
                 if solve(board) then{
         return true
     }
         let board[row][col] be 0
       }
       } 
        return false
      }
     }
   }
    return true
}
     function Print(board){
    for r be 0 to 8 subtract 1 {
       for c be 0 to 8 subtract 1 {
        print " " board[r][c]
     }
       printnl " "
     }
  }
      if solve(board) then {
          Print(board)
   } 
       otherwise {
      print "No solution found."
 }
```
> ### 6.8.5
```elpl
let day be 0
switch(day){
case 1 => print "Monday"
case 2 => print "Tuesday"
case 3 => print "Wednesday"
default => print "Other day"
}
```
> 6.8.7

### MULTI THREADING
```elpl
   let counter be 0
      Thread t1 {
   for i be 1 to 3 {
       counter pels 1
      printnl "T1 incremented: " counter
    nl
    sleep => 100
  } 
 }
  Thread t2 {
  for i be 1 to 3 {
   counter pels 1
   printnl "T2 incremented: " counter
      nl
    sleep => 150
    }
 }
    printnl "Counting started"
   nl
  join t1
  join t2
    printnl "Counting finished"
   nl
printnl "Final counter: " counter
```
### v6.9.3 Beta 
***Note: Direct assignments are depreciated now***
```elpl
let name be "Ahmed"
   printnl "Hello, " name
     function greet() {
     printnl "Hello, " name
  }
     greet()
class Person {
      function Person(name, age) {
              this.name be name // direct assignment to the field
             this.age be age
     }
          function greet() {
          return "Hello, " this.name " is " this.age
      }
   }
     let p be new Person("Alice", 30)
               print p.greet()
```
> ### v6.9.4
```elpl
class Person {
     function Person(){
        this.name be "unknown"
     }
         function Person(name){
              this.name be name
          }
             function greet(){
                return "Hello, "this.name
          }
      } 
          let p1 be new Person()
             print p1.name
           let p2 be new Person("Alice")
       print p2.greet()

// ===> New example <======
class Animal { 

      function Animal(type,name,age){
          this.type be type 
          this.name be name 
          this.age be age 
       } 
            function animalData(){
              return "My pet is a: " this.type" , his name is: "this.name", he's "this.age" years old." 
        } 
   } 
    let p be new Animal("Cat", "Snow", 5) 

   print p.animalData()

```
> ### Otherwise-if statements

```elpl
let score be 85

if score is greater than or equal to 90 then {
    print "A"
}
otherwise if score is greater than or equal to 80 then {
    print "B"
}
otherwise if score is greater than or equal to 70 then {
    print "C"
}
otherwise if score is greater than or equal to 60 then {
    print "D"
}
otherwise {
    print "F"
}
```

### v6.9.5 NESTED CLASSES
```elpl
class University {

    class Student {

        public let name

        function Student(name) {

            this.name be name

        }

        function greet() {

            return "Hi, I'm " this.name

        }

    }

}

let s be new University.Student("Alice")

print s.greet()

```
>  ### Inheritance
`super, super()`
```elpl
class Animal {
   function speak() {
      return "Animal"
    }
 }

class Dog extends Animal {
     function speak() {
        return "Dog"
   }
 }
   let d be new Dog() 
     print d.speak()

// Another example

class Animal {

    function speak() {
        return "Animal"
    }

}

class Dog extends Animal {

    function speak() {
        return super.speak() // new
    }

}

let d be new Dog()

print d.speak() // output: Animal

// ====> Another example <====

class Animal {

    function speak() {
        return "Animal"
    }

}

class Dog extends Animal {

    function speak() {
        return super.speak() " -> Dog"
    }

}

let d be new Dog()

print d.speak()  //Output: Animal -> Dog

// =====> Another example

class Animal {

    function Animal() {
        this.name be "Buddy"
    }

    function info() {
        return this.name
    }

}

class Dog extends Animal {

    function info() {
        return super.info()
    }

}

let d be new Dog()

print d.info() // Output: Buddy
 
 // =====> Another example

class Animal {
    function animalSound() {
    printnl "The animal makes a sound"
     }
}
class Dog extends Animal  {
      function animalSound(){
      super.animalSound() //. Use of 'super'
      print "The dog says: bow bow"
    }
  }
let myDog be new Dog()
print myDog.animalSound() >>> Output: The animal makes a sound
                                     The dog says: bow bow <<<
// =====> Another example

class Animal {
    function Animal() {
     this.name be "Unknown"
    }
    function info() {
    return "Hi," this.name
   }
  }
class Dog extends Animal {
    }
let d be new Dog()
d.name be "Buddy"
print d.info() // output: Buddy

//=====> Another example

class Animal  {
    function Animal(){
    printnl "Animal is created"
   }
  }
class Dog extends Animal {
    function Dog() {
     super() // super constructor  <============    
     print "Dog is created"
   }
  }
let dog be new Dog()

//======> Another

class Animal {
    function Animal(name) {
      this.name be name
    }
  }
class Dog extends Animal {
      function Dog(name, breed) {
          super(name)
        this.breed be breed
     }
  }
    let dog be new Dog("Buddy", "Labrador")
      printnl dog.name
      print dog.breed
```
> ### Encapsulation

```elpl
class Person {

    private function secret() {
        print "hidden"
    }

    function reveal() {
        this.secret()
    }

}

let p be new Person()

p.reveal()     

p.secret() // this will fail    

//===== Another example

class Person {
      private let age
    public function setAge(newAge){
     if newAge is greater than or equal to 0 then {
          this.age be newAge
      } otherwise {
         printnl "Age cannot be negative"
     }
   }
      protected function getAge(){
         return this.age
      }
   }
     let person be new Person()
       person.setAge(26)
     printnl "Person's age is:"person.getAge()
     nl
     person.setAge(10)
printnl "Person's age is:"person.getAge()
```
> `override`
```elpl
//========>Another example

class Animal {

    function speak(){

        return "animal"

    }

}


class Dog extends Animal {

    @override // override annotation to check for function overrides
    function speak(){

        return "dog"

    }

}


let a be new Dog()

print a.speak()

//==== Another example

class Person {
     protected function getAge() {
      return 25
    }
 }
class Employee extends Person {
     public function printAge() {
     print this.getAge()
   }
 }
let e be new Employee()
print e.printAge()

```
> `static`
```elpl

class Math {
    // also field static ‘private static let a’
     public static function Add(a,b){
         return a add b
       }
  }
print Math.Add(5,10)
```
> `abstract`
```elpl
abstract class Shape {

    abstract function area()

    abstract function perimeter()

}

class Rectangle extends Shape {

    function area() {
        return 50
    }

    function perimeter() {
        return 30
    }

}

let r be new Rectangle()

printnl r.area()
print r.perimeter()

// ====Another example

abstract class Animal {

    function eat() {
        return "Eating"
    }

    abstract function speak()

}

class Dog extends Animal {

    function speak() {
        return "Woof"
    }

}

let d be new Dog()

printnl d.eat()
print d.speak()
```
> `interface`
```elpl
// Another example

interface Flyable {

    function fly()

}


interface Runnable {

    function run()

}


class Bird implements Flyable, Runnable {


    public function fly(){

        return "flying"

    }


    public function run(){

        return "running"

    }

}

// Another example

interface Animal {

    function speak()

}


interface DogLike extends Animal {

    function bark()

}


class Dog implements DogLike {


    function bark(){

        print "bark"

    }


}
```
> ### v6.9.6
```elpl
interface Animal {

    function speak()

}

class Dog implements Animal {

    function speak() {
        return "dog"
    }

}

class Car {

}

Animal a be new Dog()   // new declaration , old will work too

Animal b be new Car()   // will fail

// ====> Another example

interface Animal {
    function speak()
}

class Dog implements Animal {

    function speak() {
        return "dog"
    }

}


class Puppy extends Dog {

}


let a be new Puppy()

Animal b be new Puppy()

Dog c be new Puppy()
```
> ### v6.9.7

```elpl
class Math {

    public static let PI be 3.14

    public static function square(x) {
        return x multiply x
    }

}

printnl Math.PI
print Math.square(5)
```
> `enums`

```elpl

enum Color {
      RED,
     GREEN
   }
     Color c be Color.GREEN

    switch(c) {
       case RED =>
         print "red"
       case GREEN =>
        print "green"
       default =>
        print "default case" 
   }

//======> Another example

enum Color(label, code) {
   RED("red", 1),
   GREEN("green", 2),
   BLUE("blue", 3)
}
printnl Color.RED.name()
printnl Color.RED.ordinal()
printnl Color.RED.label
print Color.RED.code
```
> ### `Generics` v7.0.0
`note generics are currently in beta`
```elpl
Array<int> a be [
    [1,2],
    [3,4]
]

a[1][0] be 10

```
### Comprehensive test
```elpl
//v7.0.0 (Comprehensive test)

// ==========================================
// 1. Interfaces & Interface Inheritance
// ==========================================

interface Flyable {
    function fly()
}

interface Runnable {
    function run()
}

interface AnimalInterface {
    function speak()
}

interface DogLike extends AnimalInterface {
    function bark()
}

// ==========================================
// 2. Abstract Classes
// ==========================================

abstract class Shape {
    abstract function area()
    abstract function perimeter()
}

abstract class BaseAnimal {
    function eat() {
        return "Eating..."
    }

    abstract function speak()
}

// ==========================================
// 3. Concrete Classes & Inheritance
// ==========================================

class Rectangle extends Shape {
    private let width
    private let height

    function Rectangle(w, h) {
        this.width be w
        this.height be h
    }

    function area() {
        return this.width multiply this.height
    }

    function perimeter() {
        return 2 multiply (this.width add this.height)
    }
}

class Person {
    protected let age

    function Person(initialAge) {
        this.age be initialAge
    }

    public function getAge() {
        return this.age
    }

    public function setAge(newAge) {
        if newAge is greater than or equal to 0 then {
            this.age be newAge
        } otherwise {
            printnl "Age cannot be negative!"
        }
    }
}

class Employee extends Person {
    private let salary

    function Employee(initialAge, initialSalary) {
        super(initialAge)
        this.salary be initialSalary
    }

    public function printAge() {
        print "Employee Age: "
        printnl this.getAge()
    }
}

class Dog extends BaseAnimal implements DogLike {
    
    @override
    function speak() {
        return "Woof!"
    }

    function bark() {
        printnl "Bark! Bark!"
    }
}

class Bird implements Flyable, Runnable {
    
    public function fly() {
        return "flying high in the sky"
    }

    public function run() {
        return "running fast on the ground"
    }
}

// ==========================================
// 4. Static Utility Class
// ==========================================

class MathUtils {
    public static let PI be 3.14

    public static function Add(a, b) {
        return a add b
    }

    public static function Multiply(a, b) {
        return a multiply b
    }
}

// ==========================================
// 5. Execution Flow
// ==========================================

printnl "=== 1. Testing Person & Employee ==="
Person person be new Person(26)
print "Person's age is: "
printnl person.getAge()

Employee emp be new Employee(30, 75000)
emp.printAge()
nl

printnl "=== 2. Testing Static Utility Methods ==="
print "MathUtils.Add(5, 10) = "
printnl MathUtils.Add(5, 10)

print "MathUtils.Multiply(4, 6) = "
printnl MathUtils.Multiply(4, 6)
nl

printnl "=== 3. Testing Abstract Classes & Shapes ==="
Rectangle rect be new Rectangle(5, 10)
print "Rectangle Area: "
printnl rect.area()
print "Rectangle Perimeter: "
printnl rect.perimeter()
nl

printnl "=== 4. Testing Abstract Base Animal & Dog ==="
baseAnimal myDog be new Dog()
print "Dog Action: "
printnl myDog.eat()
print "Dog Sound: "
printnl myDog.speak()
myDog.bark()
nl

printnl "=== 5. Testing Multiple Interfaces (Bird) ==="
Flyable myBird be new Bird()
print "Bird Flying: "
printnl myBird.fly()
print "Bird Running: "
printnl myBird.run()
```
### v7.0.3
`return type changed with generics, normal dynamic but with generics like this`
```elpl
Array<int> myarr be [0,1,2,3] // generic array can only contain integers

List<string> list be [“hello”, “world”]

Map<string,string> mapName be {“check”,”mate”}

//normal declarations remain dynamic, but generics changes the declarations.

//Also, now functions with explicit parameter types. 

function mymap(Map<int,string> mapName) 
```
> ### v7.0.6
`Java interop bug fixes & improvments`
```elpl
let name be "John"
let age be 20

@java{
    age += 5;
    name = name.toUpperCase();
}

print age
print name
```

## Ultimate OOP test



> 1. Private method - same class



```elpl
class BankAccount {

    private function secretMessage() {
        return "Private method works!"
    }

    public function test() {
        return this.secretMessage()
    }
}

BankAccount account be new BankAccount()

printnl account.test()
```

```bash
output: Private method works!
```

> 2. Private method - outside class


```elpl
class BankAccount {

    private function secretMessage() {
        return "You should not see this"
    }
}

BankAccount account be new BankAccount()

printnl account.secretMessage()
```

```bash
output: cannot access private method 'secretMessage'
```


> 3. Private method - subclass


```elpl
class Parent {

    private function secret() {
        return "Parent secret"
    }
}

class Child extends Parent {

    public function test() {
        return this.secret()
    }
}

Child child be new Child()

printnl child.test()
```

```bash
output: ERROR
```

> 4. Protected method - subclass


```elpl
class Parent {

    protected function greet() {
        return "Hello from Parent"
    }
}

class Child extends Parent {

    public function test() {
        return this.greet()
    }
}

Child child be new Child()

printnl child.test()
```

```bash
output: Hello from parent
```


> 5. Protected method - unrelated class


```elpl
class Parent {

    protected function secret() {
        return "Protected"
    }
}

class Other {

    public function test(Parent p) {
        return p.secret()
    }
}

Parent parent be new Parent()
Other other be new Other()

printnl other.test(parent)
```

```bash
output: ERROR
```

> 6. Public method through inheritance


```elpl
class Animal {

    public function speak() {
        return "Animal sound"
    }
}

class Dog extends Animal {
}

Dog dog be new Dog()

printnl dog.speak()
```

```bash
output: Animal sound
```

> 7. Override and polymorphism


```elpl
class Animal {

    public function speak() {
        return "Animal"
    }
}

class Dog extends Animal {

    @override
    public function speak() {
        return "Woof"
    }
}

Animal animal be new Dog()

printnl animal.speak()
```

```bash
output: Woof
```


> 8. Deep inheritance and protected


```elpl

class A {

    protected let value

    function A() {
        this.value be 100
    }

    protected function getValue() {
        return this.value
    }
}

class B extends A {

    function B() {
        super()
    }
}

class C extends B {

    public function test() {
        return this.getValue()
    }
}

C c be new C()

printnl c.test()
```

```bash
output: 100
```


> 9. Deep inheritance and private


```elpl
class A {

    private function secret() {
        return "SECRET"
    }
}

class B extends A {
}

class C extends B {

    public function test() {
        return this.secret()
    }
}

C c be new C()

printnl c.test()
```

```bash
output: ERROR
```

> 10. Private field - same class


```elpl
class Person {

    private let name

    function Person(n) {
        this.name be n
    }

    public function getName() {
        return this.name
    }
}

Person p be new Person("John")

printnl p.getName()
```

```bash
output: John
```


> 11. private field - subclass


```elpl
class Person {

    private let name

    function Person() {
        this.name be "John"
    }
}

class Employee extends Person {

    public function test() {
        return this.name
    }
}

Employee e be new Employee()

printnl e.test()
```

```bash
output: ERROR
```


> 12. Protected field - subclass


```elpl
class Person {

    protected let age

    function Person(a) {
        this.age be a
    }
}

class Employee extends Person {

    public function getAge() {
        return this.age
    }
}

Employee e be new Employee(30)

printnl e.getAge()
```

```bash
output: 30
```


> 13. Public field - outside


```elpl
class Person {

    public let name

    function Person(n) {
        this.name be n
    }
}

Person p be new Person("John")

printnl p.name
```


```bash
output: John
```


> 14. Constructor inheritance


```elpl
class Animal {

    protected let name

    function Animal(n) {
        this.name be n
    }
}

class Dog extends Animal {

    function Dog(n) {
        super(n)
    }

    public function getName() {
        return this.name
    }
}

Dog d be new Dog("Buddy")

printnl d.getName()
```


```bash
output: Buddy
```


> 15. Constructor context restoration


```elpl
class Parent {

    protected let parentValue

    function Parent(value) {
        this.parentValue be value
    }
}

class Child extends Parent {

    private let childValue

    function Child(parentValue, childValue) {
        super(parentValue)
        this.childValue be childValue
    }

    public function test() {
        print "Parent = "
        printnl this.parentValue

        print "Child = "
        printnl this.childValue
    }
}

Child c be new Child(10, 20)

c.test()
```

```bash
output: Parent = 30
output: Child = 20
```


> 16. Interface polymorphism


```elpl
interface Speaker {
    function speak()
}

class Dog implements Speaker {

    function speak() {
        return "Woof"
    }
}

class Cat implements Speaker {

    function speak() {
        return "Meow"
    }
}

Speaker a be new Dog()
Speaker b be new Cat()

printnl a.speak()
printnl b.speak()
```

```bash
output: Woof
output: Meow
```


> 17. Multiple Interfaces


```elpl
interface Flyable {
    function fly()
}

interface Runnable {
    function run()
}

class Bird implements Flyable, Runnable {

    function fly() {
        return "Flying"
    }

    function run() {
        return "Running"
    }
}

Flyable bird be new Bird()

printnl bird.fly()
```

```elpl
Runnable runner be new Bird()

printnl runner.run()
```

```bash
output: Flying \n Running
```


> 18. Interface implementation failure


```elpl
interface Printable {
    function printDocument()
}

class Document implements Printable {

}
```

```bash
output: ERROR
```


> 19. Abstract class cannot be instantiated


```elpl
abstract class Animal {

    abstract function speak()
}

Animal a be new Animal()
```


```bash
output: ERROR
```


> 20. Abstract subclass must implement abstract method


```elpl
abstract class Animal {

    abstract function speak()
}

class Dog extends Animal {

}
```


```bash
output: ERROR
```


> 21. Abstract subclass can remain abstract


```elpl
abstract class Animal {

    abstract function speak()
}

abstract class Dog extends Animal {

}
```


```bash
output: No error
```


> 22. Final field reassignment


```elpl 
class Config {

    public final let version be 1

    function change() {
        this.version be 2
    }
}

Config c be new Config()

c.change()
```

```bash
output: ERROR
```


> 23. Final field initialisation once


```elpl
class Config {

    public final let version

    function Config(v) {
        this.version be v
    }

    public function getVersion() {
        return this.version
    }
}

Config c be new Config(10)

printnl c.getVersion()
```

```bash
output: 10
```


> 24. Composition + private storage


```elpl
class Engine {

    public function start() {
        return "Engine started"
    }
}

class Car {

    private let engine

    function Car(e) {
        this.engine be e
    }

    public function startCar() {
        return this.engine.start()
    }
}

Engine engine be new Engine()
Car car be new Car(engine)

printnl car.startCar()
```

```bash
output: Engine started
```


> 25. Composition + polymorphism


```elpl
interface Logger {
    function log(message)
}

class ConsoleLogger implements Logger {

    function log(message) {
        print "CONSOLE: "
        printnl message
    }
}

class FileLogger implements Logger {

    function log(message) {
        print "FILE: "
        printnl message
    }
}

class Application {

    private let logger

    function Application(l) {
        this.logger be l
    }

    public function run() {
        this.logger.log("Application started")
    }
}

Logger logger be new ConsoleLogger()

Application app be new Application(logger)

app.run()
```

```bash
output: CONSOLE: Application started
```

***Then change***


```elpl
Logger logger be new FileLogger()
```

```bash
FILE: Application started
```

## More on OOP


### Test 1


```elpl
// ==========================================
// 1. Interfaces & Polymorphism
// ==========================================

interface PaymentProcessor {
    function processPayment(amount)
}

class CreditCardProcessor implements PaymentProcessor {
    function processPayment(amount) {
        print "Charged $"
        print amount" securely via Credit Card Gateway."
    }
}

class CryptoProcessor implements PaymentProcessor {
    function processPayment(amount) {
        print "Transferred $"
        print amount" equivalent via Crypto Smart Contract."
    }
}

// ==========================================
// 2. Abstract Classes & Encapsulation
// ==========================================

abstract class SmartDevice {
    public let deviceId
    protected let powerDraw
    public let isOn

    // Hardcoded default constructor initialization to bypass reference parsing bugs
    function initDevice(id, power) {
        this.deviceId be id
        this.powerDraw be power
        this.isOn be false
    }

    public function togglePower() {
        if this.isOn then {
            this.isOn be false
            print "Device "
            print this.deviceId
            printnl " is now OFF."
        } otherwise {
            this.isOn be true
            print "Device "
            print this.deviceId
            printnl " is now ON."
        }
    }

    public function getPowerStatus() {
        return this.isOn
    }

    abstract function operate()
}

// ==========================================
// 3. Inheritance & Implementation
// ==========================================

class SmartThermostat extends SmartDevice {
    private let targetTemp

    function SmartThermostat(id, power, temp) {
        // Explicitly using internal initialization safely
        this.initDevice(id, power)
        this.targetTemp be temp
    }

    function operate() {
        if this.getPowerStatus() then {
            print "Thermostat "
            print this.deviceId
            print " regulating temperature to "
            print this.targetTemp" degrees."
        } otherwise {
            print "Thermostat "
            print this.deviceId " is off. Turn it on first."
        }
    }
}

// ==========================================
// 4. Composition (Using Setter Injection)
// ==========================================

class SmartHomeHub {
    private let hubName
    private let paymentEngine
    private let activeDevice

    // Primitive values work perfectly inside constructors in your language
    function SmartHomeHub(name) {
        this.hubName be name
    }

    // Setter methods completely bypass constructor object-linking bugs
    public function setPaymentEngine(processor) {
        this.paymentEngine be processor
    }

    public function setDevice(device) {
        this.activeDevice be device
    }

    public function runRoutine() {
        this.activeDevice.togglePower()
        printnl this.activeDevice.operate()
    }

    public function payBill(amount) {
        printnl "--- Processing Utility Bill ---"
        printnl this.paymentEngine.processPayment(amount)
    }
}

// ==========================================
// 5. Execution Flow (Matching Your Working Demo)
// ==========================================

printnl "=== 1. Setting up Smart Thermostat ==="
// Instantiating with clean primitives works perfectly
SmartThermostat nest be new SmartThermostat("TH-01", 15, 22)

printnl "=== 2. Setting up Payment Processors ==="
CryptoProcessor crypto be new CryptoProcessor()
CreditCardProcessor card be new CreditCardProcessor()

printnl "=== 3. Initializing Composition Hub ==="
SmartHomeHub myHome be new SmartHomeHub("Villa Hub")

// Using setter injection to safely link objects outside constructors
myHome.setDevice(nest)
myHome.setPaymentEngine(crypto)

printnl "=== 4. Executing System Logic ==="
myHome.runRoutine()
myHome.payBill(45)

printnl ""
printnl "=== 5. Demonstrating Polymorphism (Swapping Processors) ==="
myHome.setPaymentEngine(card)
myHome.payBill(120)
```

### Test 2


```elpl
// ==========================================
// 1. Interfaces & Polymorphism
// ==========================================

interface PaymentProcessor {
    function processPayment(amount)
}

class CreditCardProcessor implements PaymentProcessor {
    public function processPayment(amount) {
        print "Charged $"
        print amount
        printnl " securely via Credit Card Gateway."
    }
}

class CryptoProcessor implements PaymentProcessor {
    public function processPayment(amount) {
        print "Transferred $"
        print amount
        printnl " equivalent via Crypto Smart Contract."
    }
}

// ==========================================
// 2. Abstract Classes & Encapsulation
// ==========================================

abstract class SmartDevice {
    public let deviceId
    protected let powerDraw
    public let isOn

    function SmartDevice(id, power) {
        this.deviceId be id
        this.powerDraw be power
        this.isOn be false
    }

    public function togglePower() {
        if this.isOn then {
            this.isOn be false
            print "Device "
            print this.deviceId
            printnl " is now OFF."
        } otherwise {
            this.isOn be true
            print "Device "
            print this.deviceId
            printnl " is now ON."
        }
    }

    public function getPowerStatus() {
        return this.isOn
    }

    abstract function operate()
}

// ==========================================
// 3. Inheritance & Implementation
// ==========================================

class SmartThermostat extends SmartDevice {
    private let targetTemp

    function SmartThermostat(id, power, temp) {
        super(id, power)
        this.targetTemp be temp
    }

    @override
    function operate() {
        if this.getPowerStatus() then {
            print "Thermostat "
            print this.deviceId
            print " regulating temperature to "
            print this.targetTemp
            printnl " degrees."
        } otherwise {
            print "Thermostat "
            print this.deviceId
            printnl " is off. Turn it on first."
        }
    }
}

// ==========================================
// 4. Composition (Has-A Relationships)
// ==========================================

class SmartHomeHub {
    private let hubName
    private let device1
    private let paymentEngine

    function SmartHomeHub(name, processor) {
        this.hubName be name
        this.paymentEngine be processor
    }

    public function setDevice(device) {
        this.device1 be device
        print "Added "
        print device.deviceId
        print " to "
        printnl this.hubName
    }

    public function runRoutine() {
        printnl ""
        print "--- Running Routine on "
        print this.hubName
        printnl " ---"
        
        this.device1.togglePower()
        this.device1.operate()
    }

    public function payElectricityBill(amount) {
        printnl ""
        printnl "--- Processing Utility Bill ---"
        this.paymentEngine.processPayment(amount)
    }
}

// ==========================================
// 5. Explicit Entry-Point Execution Block
// ==========================================

class Main {
    public static function Start() {
        printnl "=== Initializing Polymorphic Payments ==="
        CryptoProcessor cryptoEngine be new CryptoProcessor()

        printnl "=== Initializing Composition Hub ==="
        SmartHomeHub myHome be new SmartHomeHub("Villa Hub", cryptoEngine)

        printnl "=== Instantiating Inherited Objects ==="
        SmartThermostat nestThermostat be new SmartThermostat("TH-01", 15, 21)

        printnl "=== Building System Relationships ==="
        myHome.setDevice(nestThermostat)

        printnl "=== Simulating Ecosystem Logic ==="
        myHome.runRoutine()
        myHome.payElectricityBill(45)
    }
}

// Run the script directly through the static runner
Main.Start()
```
> Sets

### v7.3.4

```elpl
Queue tasks be {}

tasks.affix("First")
tasks.affix("Second")
tasks.affix("Third")

printnl tasks.peek()
printnl tasks.poll()
printnl tasks.poll()
printnl tasks.peek()
print tasks.size()
```
> Queue

```elpl
Set numbers be {}

numbers.include(10)
numbers.include(20)
numbers.include(10)
numbers.include(30)

printnl numbers
printnl numbers.contains(20)
printnl numbers.contains(50)
printnl numbers.size()

numbers.remove(20)

print numbers
```

> LocalDate library


```elpl
use elpl.sys.LocalDate

let today be LocalDate.now()

print "Today: "
print today

print "Year: "
print today.year()

print "Month: "
print today.month()

print "Day: "
print today.day()

let tomorrow be today.plusDays(1)

print "Tomorrow: "
print tomorrow
```
### Another example

```elpl
let birthday be LocalDate.of(2000, 5, 15)

print birthday
print birthday.isLeapYear()
print birthday.dayOfWeek()
```

> BFS Algorithm

```elpl
printnl "========================================"
printnl "          ELPL BFS TEST"
printnl "========================================"


// ------------------------------------------------------------
// Graph
//
//        A
//       / \
//      B   C
//     / \   \
//    D   E   F
// ------------------------------------------------------------

Map[key,value] graph be {
    "A": ["B", "C"],
    "B": ["D", "E"],
    "C": ["F"],
    "D": [],
    "E": [],
    "F": []
}


// ------------------------------------------------------------
// BFS
// ------------------------------------------------------------

function bfs(graph, start) {

    Queue queue be {}

    Set visited be {}

    queue.affix(start)
    visited.include(start)

    printnl "BFS traversal:"

    while not queue.isEmpty() {

        let current be queue.remove()

        print current

        foreach neighbor : graph[current] {

            if not visited.contains(neighbor) then {

                visited.include(neighbor)
                queue.affix(neighbor)
            }
        }
    }
}


// ------------------------------------------------------------
// Run BFS
// ------------------------------------------------------------

bfs(graph, "A")

printnl ""
printnl "========================================"
printnl "          BFS TEST COMPLETE"
printnl "========================================"
```

> Localdate comprehensive example

```elpl
// ============================================================
// ELPL LocalDate Comprehensive Test
// ============================================================
use elpl.sys.LocalDate

printnl "========================================"
printnl "       ELPL LocalDate Test Suite"
printnl "========================================"


// ------------------------------------------------------------
// 1. Create dates
// ------------------------------------------------------------

printnl ""
printnl "--- Creating Dates ---"

let date1 be LocalDate.of(2026, 8, 10)
let date2 be LocalDate.of(2026, 12, 25)
let leapDate be LocalDate.of(2024, 2, 29)

print "Date 1: "
printnl date1

print "Date 2: "
printnl date2

print "Leap Date: "
printnl leapDate


// ------------------------------------------------------------
// 2. Current date
// ------------------------------------------------------------

printnl ""
printnl "--- Current Date ---"

let today be LocalDate.now()

print "Today: "
printnl today


// ------------------------------------------------------------
// 3. Date components
// ------------------------------------------------------------

printnl ""
printnl "--- Date Components ---"

print "Year: "
printnl date1.year()

print "Month: "
printnl date1.month()

print "Day: "
printnl date1.day()

print "Day of Week: "
printnl date1.dayOfWeek()

print "Day of Year: "
printnl date1.dayOfYear()

print "Leap year (2024): "
printnl leapDate.isLeapYear()

print "Leap year (2026): "
printnl date1.isLeapYear()


// ------------------------------------------------------------
// 4. Month/year lengths
// ------------------------------------------------------------

printnl ""
printnl "--- Month / Year Length ---"

print "February 2024 days: "
printnl leapDate.lengthOfMonth()

print "February 2024 year length: "
printnl leapDate.lengthOfYear()

print "August 2026 days: "
printnl date1.lengthOfMonth()

print "2026 year length: "
printnl date1.lengthOfYear()


// ------------------------------------------------------------
// 5. Adding days
// ------------------------------------------------------------

printnl ""
printnl "--- Plus / Minus Days ---"

let plusDays be date1.plusDays(10)
let minusDays be date1.minusDays(10)

print "Original: "
printnl date1

print "Plus 10 days: "
printnl plusDays

print "Minus 10 days: "
printnl minusDays


// ------------------------------------------------------------
// 6. Adding / removing weeks
// ------------------------------------------------------------

printnl ""
printnl "--- Plus / Minus Weeks ---"

print "Plus 2 weeks: "
printnl date1.plusWeeks(2)

print "Minus 2 weeks: "
printnl date1.minusWeeks(2)


// ------------------------------------------------------------
// 7. Adding / removing months
// ------------------------------------------------------------

printnl ""
printnl "--- Plus / Minus Months ---"

print "Original: "
printnl date1

print "Plus 2 months: "
printnl date1.plusMonths(2)

print "Minus 2 months: "
printnl date1.minusMonths(2)


// ------------------------------------------------------------
// 8. Date transformation
// ------------------------------------------------------------

printnl ""
printnl "--- Date Transformation ---"

print "Change year to 2030: "
printnl date1.withYear(2030)

print "Change month to December: "
printnl date1.withMonth(12)

print "Change day to 25: "
printnl date1.withDay(25)


// ------------------------------------------------------------
// 9. Date comparisons
// ------------------------------------------------------------

printnl ""
printnl "--- Date Comparisons ---"

print "date1 before date2: "
printnl date1.isBefore(date2)

print "date1 after date2: "
printnl date1.isAfter(date2)

print "date1 equal date2: "
printnl date1.isEqual(date2)

print "date1 equal itself: "
printnl date1.isEqual(date1)


// ------------------------------------------------------------
// 10. Days between dates
// ------------------------------------------------------------

printnl ""
printnl "--- Date Difference ---"

let daysToChristmas be date1.daysUntil(date2)

print "Days from date1 to date2: "
printnl daysToChristmas

let daysBack be date2.daysUntil(date1)

print "Days from date2 back to date1: "
printnl daysBack


// ------------------------------------------------------------
// 11. Date arithmetic consistency
// ------------------------------------------------------------

printnl ""
printnl "--- Arithmetic Consistency ---"

let future be date1.plusDays(30)
let back be future.minusDays(30)

print "Original: "
printnl date1

print "After +30 days: "
printnl future

print "After +30 then -30: "
printnl back

print "Returned to original: "
printnl date1.isEqual(back)


// ------------------------------------------------------------
// 12. Month-end handling
// ------------------------------------------------------------

printnl ""
printnl "--- Month-End Handling ---"

let januaryEnd be LocalDate.of(2026, 1, 31)

print "January 31: "
printnl januaryEnd

print "January 31 + 1 month: "
printnl januaryEnd.plusMonths(1)

print "January 31 + 2 months: "
printnl januaryEnd.plusMonths(2)


// ------------------------------------------------------------
// 13. Leap-year behavior
// ------------------------------------------------------------

printnl ""
printnl "--- Leap Year Behavior ---"

let leapYearDate be LocalDate.of(2024, 2, 29)

print "Leap date: "
printnl leapYearDate

print "Is leap year: "
printnl leapYearDate.isLeapYear()

print "One year later: "
printnl leapYearDate.plusMonths(12)


// ------------------------------------------------------------
// 14. String conversion
// ------------------------------------------------------------

printnl ""
printnl "--- String Conversion ---"

print "date1.toString(): "
printnl date1.toString()


// ------------------------------------------------------------
// 15. Real-world example
// ------------------------------------------------------------

printnl ""
printnl "--- Project Deadline Example ---"

let projectStart be LocalDate.of(2026, 8, 1)
let projectDeadline be LocalDate.of(2026, 9, 30)

print "Project starts: "
printnl projectStart

print "Project deadline: "
printnl projectDeadline

print "Days available: "
printnl projectStart.daysUntil(projectDeadline)

if today.isBefore(projectDeadline) then {
    printnl "Project deadline has not passed."
} otherwise {
    printnl "Project deadline has passed."
}


// ------------------------------------------------------------
// Finished
// ------------------------------------------------------------

printnl ""
printnl "========================================"
printnl "       LocalDate Tests Completed"
printnl "========================================"