EON


Introduction Notation Accessors Commands Grammar
This program returns the classic "Hello World" message to whatever process called the EON program. Whatever value is assigned to the out keyword when the program ends execution will be output by the program. out has a default value of {} until reassigned. Each complete EON program must be enclosed within eon{} delimiters to indicate it's bounds.
eon{
  out: "Hello World!"
  // returns "Hello World!"
}

The key-value pairs in a card are accessible from within the card's index and body (here, a list of commands).
eon{
  message: "Hello World!"
  name: "Hello Bob!"
  /(- 
    out: message
    out:+ name)
  /* 
    prints: 
    Hello World!Hello Bob! */ }

Except for the last line, commands in a command list must always terminated by a new line character.

Commands in a command list can be spread onto multiple lines by placing a // before the next new line character.


The fn keyword converts the expression list on it's right into an executable process. Processes are named expression lists that are executed when accessed.
eon{
  printAll: fn {
    my_var: "World"
    /(-
      out: "Hello"
      out:+ my_var
      out:+ "!" )}
  (-out: printAll)
  /* prints: 
  HelloWorld! */ }

The cfn keyword is a type of process like fn, but after each execution the process's input and output are cached so that future calls to the process can skip execution for duplicate inputs. This increases program speed when a process is known to be deterministic like in mathematical functions.
eon{
  add5: cfn (-
    out: sum [in 5])
  /(-out: add5 5)
  /* prints: 
  10 */ }

The pfn keyword is a type of process like fn, but the function executes on each of its inputs concurrently and waits until all are done before progressing. Consequently, the inputs to the function must be in a list [] otherwise void will automatically be returned. However the src input may be singular to enable other passing in other parameters. Outputs are returned in a list in the same order as the inputs. This can reduce overall execution time compared to loops when hardware supports concurrency or parallelism.
eon{
  add5: pfn (-
    out: sum [in 5])
  /(-out: add5 [5 6 7 8])
  /* outputs: 
  10 11 12 13 */ >

It is idiomatic to use camelCase to name processes and snake_case to name cards.

Capitalized keys are Public and all other keys are private (similar to Golang)


Creating a process with :? passes the input in to the process by a pointing reference instead of by copying it, which is the default behavior.
eon{
  printHello:? fn(-
    out: "Hello "
    out:+ in )}

EON does not have null values in the way that most other programming languages do. Instead other constructs are used depending on the particular context and type. Empty, but initialized, values return {}, [], [:], (), "", or 0. Attempting to access an undefined value returns a void card. When the void expression is typically executed it immediately exits the current expression list ().

The best way to understand how the void keyword works is to think of it as a function whose output triggers a context dependent behavior. It takes the card input into it, if any, and makes it the body of a returned void{} card. Within an executing expression list, any expression that evaluates to a card of type void, sets out to the void card's body and ends execution of the expression list. With no input it returns an empty but typed card void{}. This behavior enables void to fill the roles that break, null, throw, and false keywords in other languages serve, as well as enabling custom error handling and treatment of errors as data.


Tags can be added to an existing card's index by assigning them an empty card {} and removed by assigning them void.
eon{
  card: { tag1 }
  /(-
    card.tag2: {}
    card.tag1: void)
  // now the card is { tag2 }
  }

You can check if a card has a specified tag, which may result in a void card if it does not.
eon{
  (-{tag1 tag2}.tag_3)
  // if yes, then execution continues
  // if no, then a void card results
  }

You can check if a card is a primitive or array.
eon{
  (- "string"/[:])
  // if yes, then execution continues
  // if no, then a void card results
  }

You can check if a card is a list.
eon{
  (-{tag1 tag2}/[])
  // if yes, then execution continues
  // if no, then a void card results
  }

The try keyword executes the commands in the list to its right in order until the void keyword is called or execution of the card finishes. If the expression list is unordered (executed in parallel) then all expressions in the list are always executed.
eon{
  try(-
    printAll
    out: "Success!")}

The try keyword can emulate the behavior of if-elseif-else patterns by instead passing a list of expression lists to attempt. Each successive expression list is only executed if the prior's execution was interrupted by a void.
eon{
  try[
    (-
      void
      out: "Success!")
    (-
      out: "Error!")]}

The esc keyword immediately ends execution in the current loop (similarly to 'break' in other languages).
eon{
  try[
    (-
      loop(-
        esc
        out: "Fail!"))
    (-out: "Loop Completed!")]}

The loop keyword repeatedly executes the commands in the list to its right until the esc keyword is called or the next keyword triggers another iteration.
eon{
  loop(-
    printAll
    esc)}

The next keyword triggers another iteration of the loop without waiting until the current iteration of the loop has completed.
eon{
  loop(-
    out: "This is an infinite loop"
    next
    esc)}

The void and esc keywords can be returned to be executed by the encapsulating command-list in order to conditionally exit a command-list (scope) or loop.
eon{
  loop
    try[
      (-
        forceExitLoop // outputs void to exit the if
        out: "Fail!")
      (-
        out: fn (void)
        out: "Success!" // this is still executed 
        // because the output is not retrieved until after 
        // the or finishes executing or a void/esc has been used
        )]}

To loop through a list's cards use the loop interface. In each iteration the current key and its value will be referenced by the reserved names key and val.
eon{
  list: [ "hello" "world" ]
  /(-list.loop(-
      out:+ key 
      out:+ val))
    // prints "1hello2world"
    }

Nested loops are possible by specifying which card the key or val is referencing.
eon{
  list1: [ "A" "B" ]
  list2: [ "I" "II"]
  /(-
    list1.loop(-
      list2.loop(-
        out:+ list1.key
        out:+ list1.val 
        out:+ list2.val
        out:+ " "))
    // prints "1AI 1AII 2BI 2BII"
    }

Attempting to access an undefined name returns a void card.
eon{
  try[
    (-
      undefined
      out: "Success!")
    (-
      out: "Error!")]}

The $ operator concatenates the bodies of a list of cards of the same type and merges their indexes. The values of duplicate keys are combined into a list [].
eon{
  (-
    $["Hello " "World"]
    // combines into "Hello World"
    $[ 
      { tag1 key1: "Hello"}
      { tag2 key1: "World"}]
    // combines into: 
    // { tag1 tag2 
    //   key1: ["Hello" "World"]
    // }
    )]

The ini keyword is a reserved index that is only executed after its parent card is initialized or when a copy of the parent is initialized. Changing a card's type does not trigger ini.
eon{
  my_card: {
    var: "Hello"
    ini: fn(-
      var: $[var "!"])
    message: fn(-
      out: var)}
  out: my_card.message
  // prints Hello!
  }

The del keyword is a reserved index that is only executed immediately before its parent card is deleted or when a copy of the parent is deleted if defined in a type. Changing a card's type does not trigger del.
eon{
  my_card: {
    var: "Bye"
    del: (-
      var: $[var "!"])
    message: fn(-
      out: var)}
  out: my_card.message
  // prints Bye!
  }

The free keyword is used to delete data and references subsequently freeing up a key or index for reuse. Using this keyword triggers execution of any code defined in an card's del index followed by recursively calling free on each internal key and index. Finally the card's internal reference counter is checked and if 0 the memory containing the card is released, otherwise a void is returned.
eon{
  my_card: {
    var: "Bye"
    del: (-
      var: $[var "!"])
    message: fn(-
      out: var)}
  out: free my_card
  // prints Bye!
  }

The in keyword is actually a reserved name to the card passed into a process.
eon{
  printName: fn(-
    out: $["Hi! My name is " in])
  myName: "Jane"
  out: printName myName
  // prints Hi! My name is Jane
  }

The out keyword is actually a reserved name to the card a process returns. It can be used to not only set the process's output, but to reference it within the process, and modify it prior to the end of the process.
eon{
  echo: fn(-
    out: in
    out: $[out "!"])
  out: echo "Hello"
  // returns "Hello!"
  }

The type keyword creates a type interface (essentially a library of values and functions only accessible by the given type of card). This enables defining and consolidating class-like behaviors and values for cards based on their type. The src keyword accesses the card to the left of the process being called.
eon{
  (-
    type str{ 
      echo: fn(-out: src)
      ping: fn(-out: $[src in])}
    "Hello World".echo
    "Hello World".ping "... and John.")}

The has keyword returns void if the left card does not have all the same type, key-value pairs, and body that are in the right card.
eon{
  bowl: [ "milk" "cereal" ]
  cup: [ "cereal" "milk" ]
  isBreakfast: fn(-
    try[
      (-
        in.has [ "milk" "cereal" ]
        out: "yes")
      (-out: "no"))]
  // prints yes
  }

The os keyword provides an interface with the host operating system's API similar to a terminal or CLI. The functions and interface options available depend on the operating system, but there will always be a version function that returns the os name and version.
eon{
  /(-
    os.version // returns something like "BSD 13.0"
    os.cd "../project/"
    os.git.commit < a m /"commit message">)
    // in Powershell this is equivalent to:
    // cd ../project/
    // git commit -am "commit message" 
  }

Key-value pairs can be made volatile (like in C) using the vol keyword so that they are ignored by a compiler's optimizer.
eon{ 
  key1: "data" 
  key2: "volatile data"
  /(-vol key2)}

Concurrency and promises can be accomplished using the conc keyword. This executes its input concurrently to the main process. Its returned output, if earmarked for a variable/list, becomes a promise that will await fulfillment the next time it is accessed (like async/await in other languages). If not earmarked, it will be automatically terminated (if still running) when its calling scope is exited.
Only volatile variables can serve as shared memory between concurrent processes and the main process. Earmarking a concurrent process's output to a variable/list that has been made volatile removes the blocking action of the promise.
eon{ 
  name: "placeholder" 
  start: "My name is "
  sentence1: ""
  sentance2: ""
  /(-
    name: conc getName // outputs "John" 
    sentence1: $[ start name "." ]
    name: vol "placeholder" 
    sentence2: $[ start name "." ]
    /* 
    if getName takes 1 sec to finish
    then sentence1 becomes 
    "My name is John."
    and sentence2 becomes 
    "My name is placeholder."
    */ 
    )}

The use keyword is used to set the namespace that will be prepended to each subsequent identifier until changed again.
eon{
  (-
    use "os."
    cd "../project/"
    // prepends "os." to cd
    use "" // "exits" namespace
    )}

The lib keyword indicates that the code in the given file belongs to the named library. This is similar to Golang's package keyword.
eon{
  lib myLibrary}

The import keyword opens the designated .eon library and returns it as a card.
eon{
  myLib: import "./libraries/myLibrary.eon"
  // imported code is now available using myLib 
  // as library name. ie: myLib.printName("Bob")
  }

The insert keyword opens the designated .eon file and directly inserts it into the current scope and executes it as-is.
eon{
  insert "./helloWorld.eon"
  // prints Hello World!
  }


Introduction Notation Accessors Commands Grammar