Jedi 1.0 is basically a calculator language. It is able to execute arithmetic and logical expressions. Programmers can store the values of expressions in identifiers which can be used in subsequent expressions.
Here are some examples of FunCalls:
-> add(2, 3, 4)
9
-> mul(add(3, 4), sub(9, 3))
42
-> less(4, 3)
false
-> add(2, 3, 4.1)
9.1
-> 2 + 3 + 4
9
-> (3 + 4) * 2 + 1
15
-> 3 < 4.1
true
Here's a class diagram for FunCall:
Notes:
· A function call consists of an operator (which is an identifier) followed by operands-- a comma-separated list of zero or more expressions.
· Here's the EBNF rule
funcall ::= identifier ~ operands
operands ::= "(" ~ (expression ~ ("," ~ expression)*)? ~
")"
· The operands may themselves be function calls or any other type of expression.
· The parser converts an infix expressions like 3 + 4 into the FunCall add(3, 4).
· FunCall.execute begins by eagerly executing all of its operands. This produces a list of values called arguments.
· Jedi 1.0 does not have user-defined functions (i.e., lambdas). All functions are implemented in the alu.
· FunCall.execute calls alu.execute(operator, arguments).
Here's a test app for FunCalls:
Here's a sample Jedi 1.0 session:
-> 3 < 4 && 2 == 1 && x
false
-> 2 == 1 || 3 < 4 || x
true
-> if (3 < 4) 3 + 4 else x
7
-> x
Undefined identifier: x
-> if (false) x
Unspecified
Notes:
· Conjunction (&&) and disjunction (||) use a form of lazy execution called short-circuit execution—execute operands from left-to-right until the answer is known, then stop executing operands. In both examples the expression x was never executed. We know this because executing x produces an undefined identifier error.
· Similarly conditionals (if/else) use a form of lazy execution called conditional execution—execute the condition. If it's true, execute the consequent and ignore the alternative. If it's false, execute the alternative (if it's not null, if it is, return Notification.UNSPECIFIED) and ignore the consequent.
· Jedi conditionals produce values and therefore are similar to Scala conditionals and the conditional expression in C:
(3 < 4)? 3 + 4: x
· Without some form of laziness it would be impossible to write code such as:
if (x != null && x.isInstanceOf[Double] && 0 <= x) y = math.sqrt(x)
· Here are the (simplified) EBNF rules for these expressions:
conditional ::= "if" ~ "(" ~ expression ~
")" ~ expression ~ ("else" ~ expression)?
conjunction ::= expression ~ ("&&" ~ expression)*
disjunction ::= expression ~ ("||" ~ expression)*
· Here's a class diagram for these special forms:
Jedi 1.0 allows programmers to bind identifiers to the values of expressions:
-> def pi = 3.14
ok
-> def e = 2.7
ok
-> def pie = pi * e
ok
-> pie
8.478000000000002
Notes:
· Here's the EBNF rule for declarations:
declaration ::= "def" ~ identifier ~ "=" ~ expression
· Here's the class diagram:
· Declaration.execute(env) adds a new row to env, then returns OK.
Much of the Jedi context is implemented here:
Notes:
· Much of Jedi's dynamic type checking happens in the ALU.
The Jedi1 Parsers are discussed here: Jedi 1.0 Parsers.
The flow of control through the Jedi interpreter.
Jedi can run in repl mode or batch mode. This is determined in the console's main method:
def main(args:
Array[String]): Unit = {
if
(args.length == 0)
repl
else
try {
executeFile(args(0))
} catch {
case e: Exception => {
println(e)
}
}
}
If a command line argument is specified, then the console assumes it's the name of a file containing Jedi expressions (one per line). It passes the file name to its executeFile method, which executes the expressions one at a time. (This is very similar to the way IntelliJ implements worksheets.)
For example, here's a file of Jedi expressions that can be used to test your code: jedi1tests. (Here are my outputs.)
How do you pass this file name to main?
1. Right click on the top-level project node in your project view (Jedi?) and select add/file. Name it jedi1tests. You will be asked what type of file it is. Select "text".
2. Copy-paste the contents of my jedi1tests into your jedi1tests.
3. Select "Edit Configurations" under the Run menu:
4. Select the console application. In the program arguments field type "jedi1tests" then click Apply, then OK.
5. To return to repl mode repeat this process and simply erase the field.
In the Run Configurations dialog, set the program arguments to this file:
When the console runs, it should execute the expressions in this file instead of calling repl.