:: Enseignements :: ESIPE :: E5INFO :: 2026-2027 :: Virtual Runtime Environment (and stuff around ...) ::
![[LOGO]](http://monge.univ-eiffel.fr/ens/resources/mlv.png) | Lab 1 - AST walker |
The aim of this first lab is to write an AST interpreter for the language smalljs
which is a small subset of the language JavaScript.
The AST (abstract syntax tree) is a tree representing a script that can be used
to interpret the script by walking the tree and executing for each kind of expression
a specific code.
Note that smalljs does not support the keyword let,
a local variable is declared using the keyword var.
In order to help you to write the AST interpreter, here is a git project containing
a starter code (a lexer, a parser and classes defining the AST)
write_your_dynamic_language_runtime
The git project contains
-
a folder grammar that contains the file (smalljs.ebnf) describing the grammar of smalljs.
The generated lexer and parser classes for this grammar are in the folder grammar/gen-src
-
a folder samples that contains examples of JavaScript scripts supported by smalljs.
-
a folder src/main/java that contains the following packages
-
A package fr.umlv.smalljs.ast which defines the abstract syntax tree
in the class Expr.java.
-
A package fr.umlv.smalljs.rt with for the moment 2 interesting classes,
JSObject that represents a JavaScript object and Failure that represents
an execution error
-
A package fr.umlv.smalljs.main that contains the main class (Main)
able to execute all the interpreters
-
The packages fr.umlv.smalljs.astinterp, fr.umlv.smalljs.stackinterp and
fr.umlv.smalljs.jvminterp that respectively represent the AST interpreter,
the Stack based interpreter and the JVM based interpreter.
The command
mvn package compiles and creates a JAR executable
smalljs.jar
in the folder
target that can be used to test different scripts.
The code of the project requires a recent version of Java (Java 27).
For example, to execute
hello.js with your interpreter use
java -jar target/smalljs.jar ast samples/hello.js
Exercice 1 - AST interpreter
The aim of this exercise is to just complete the file ASTInterpreter.java and you
should not have to write or modify any other files.
The file ASTInterpreterTests contains the unit tests. There is one question
for each test class: the question QN is checked by the nested class QN.
The question Q1 is a warm-up question without test.
All the tests are initially disabled (with @Disabled), remove the annotation
on the nested class corresponding to a question when you start working on it.
-
Before starting, explain to yourself how "switch on types" in the method visit of
ASTInterpreter.java works?
How to "return" a value from a case?
How to call it, how to do a recursive call?
What is the role of the method visitVariable and when is it called?
-
We want to implement the AST interpreter when there is a constant String (a literal).
Which class corresponds to this node in the AST (you can take a look to the file smalljs.md for a summary)?
How to implement it?
Is it enough to make the tests marked Q2 pass?
Which other node should be implemented too?
What should the evaluation of a block return?
-
Verify that the test marked Q3 (an int literal) passes.
Do you have to change something in your implementation? Why?
-
We now want to print something.
Which AST node must be implemented?
For now, we will suppose that the only function is the print function.
How to find the function "print" which is registered in the global environment?
Which method of the class JSObject allows to call a function and what is its first argument?
How to evaluate the arguments of the call?
Take a look at the last assertion of the test, how is undefined represented in the AST?
Add the code to support the function print and verify that the tests marked Q4 pass.
-
In the previous question, the name print was hard-coded.
Now, a function can be used as a value, for example print(print).
Which AST node represents the use of a name as a value?
Which method of the environment env allows to look for a value associated to a name?
What is displayed when a function is printed (take a look to JSObject.toString)?
Implement the corresponding interpreter part and verify that the test marked Q5 passes.
-
We now want to support other functions than just print,
for example the arithmetic operators.
Where are all the builtin functions defined?
How does the parser represent 3 + 2?
How to modify the code to support all builtin functions?
What does the "qualifier" component represent?
Is visiting the node of a function call enough to implement a function call?
What does the interpreter have to do with the qualifier before calling the function?
What happens if the qualifier is not a function (take a look to the helper method asJSObject)?
Which class represents a function at runtime?
What is the method to call a function and which value should be used as receiver?
Modify the code and verify that the tests marked Q6 pass.
-
What is the return value of the function print in JavaScript?
What should be the value of the evaluation of a call?
In which order are the calls executed in print(print(3))?
Make sure your interpreter behaves accordingly and verify that the test marked Q7 passes.
-
We now want to be able to declare or assign a local variable.
Which class corresponds to a local variable declaration or assignment in the AST?
What is the difference between a declaration (var x = 3) and an assignment (x = 3)?
Which method of the environment allows to store a value associated to a name?
What should happen if a script reads a variable that does not exist?
Modify the code you wrote for Q5 accordingly.
What should happen if a script assigns a variable that was never declared
(see the test printAssignmentNoVariable)?
PS: Remember that visitVariable has already been executed when the assignment is visited.
Implement the interpreter part and verify that the tests marked Q8 pass.
-
What is the behavior of JavaScript if someone tries to access a variable declared with var
before the declaration of this variable?
Why does the method visitVariable already give the same semantics to your interpreter?
What is the value of the variable between the beginning of the script and its declaration?
Note that, in JavaScript, a variable declared twice with var is not an error,
so your interpreter should not reject that.
Verify that the test marked Q9 passes.
-
We want to support the declaration of user defined functions.
What is the name of the class of the AST node that corresponds to a function declaration?
How to create a new function (JSObject) at runtime?
What is the role of the JSObject.Invoker?
Why must a new environment be created to represent the environment inside the function?
What will happen if we re-use the current environment?
What should be the parent of this new environment?
What is the value of the hidden parameter "this"?
Under which name should it be stored in the new environment?
Which method should be used to execute the body of the function, visit or execute? Why?
What does the component toplevel mean? When should the function be registered in the global environment?
How to implement the return knowing there is a class ReturnError?
Where should this error be caught?
What is the value of a function without return or with a return without value?
Note: a failure should be thrown if the number of parameters and the number of arguments
are not the same. Why does the interpreter have to check that itself
(take a look to the method invoke of JSObject)?
Note2: if a function doesn't have a name, the name of the JSObject is "lambda" for debugging
but that name is not inserted in the environment
Implement the corresponding interpreter part and verify that the tests marked Q10 pass.
-
Add the support of the if.
What do the builtin comparison functions (==, <, ...) return?
How should the interpreter interpret the value of the condition?
In the tests printVariableWeirdScope and callAUserDefinedFunctionWithAnIfAndAVariable,
a variable is declared inside a branch of the if.
Why does the code still work when the branch is not executed?
Is a new environment needed for the branches?
Verify that the tests marked Q11 pass.
-
Verify that your code supports recursive functions by running the tests marked Q12.
In the test callSeveralOperations, a function is passed as argument of another function
and called through a parameter. Where does the interpreter find the function f?
In the test callAndRewrite, why does the second call of f() return another value
even if f has not been redefined?
What is the maximum value of n for which the function fact gives a correct result? Why?
What happens for a very deep recursion?
-
We now want to add the support of the creation of object instances using the JavaScript JSON like notation.
Which class corresponds to the AST node?
How to create a JSObject at runtime? Which prototype should be used?
How to store the value of each field?
Implement the corresponding interpreter part and verify that the test marked Q13 passes.
-
The value of a field is an expression, not necessarily a literal.
What should be done for the test createAnObjectFromAVariableValue?
In which order should the fields be evaluated?
Fix your implementation if necessary and verify that the tests marked Q14 pass.
-
We want to implement the read of an instance field.
Which class corresponds to the AST node?
What if the value is not an instance of a class but a primitive type?
(take a look to the helper method asJSObject)
What should be done if the field doesn't exist for that instance (see the test objectGetAFieldNoValue)?
Which method of JSObject allows to provide a default value?
In the test canAccessGlobalThis, why does globalThis.bar give undefined?
What does it say about the function registration you implemented in Q10?
Implement the corresponding interpreter part and verify that the tests marked Q15 pass.
-
We want to implement the write of an instance field.
Which class corresponds to the AST node?
What if the value is not an instance of a class but a primitive type?
What should be done if the field doesn't exist for that instance (see the test objectSetANewFieldValue)?
What is the value of the evaluation of the assignment?
Implement the corresponding interpreter part and verify that the tests marked Q16 pass.
-
We want to implement the method call.
Which class corresponds to the AST node?
What is the difference between a function call and a method call?
What is the value of the receiver and how many times should the receiver be evaluated?
How does this.bar work inside the method of the test objectCallAMethod?
What should happen if the method does not exist (see the test objectCallNonExistingMethod)?
In the test objectCallFunction, a function is the receiver of a method call named call.
Where is this method found (take a look to FUNCTION_PROTO in JSObject)?
Implement the corresponding interpreter part and verify that the tests marked Q17 pass.
© Université de Marne-la-Vallée