creating:statements

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
creating:statements [2025/04/19 19:47] – Use internal wiki links, add link to code repo ahelwercreating:statements [2025/06/18 20:42] (current) – Fixed stale line of code due to print changes ahelwer
Line 24: Line 24:
  
     defineAst(outputDir, "Stmt", Arrays.asList(     defineAst(outputDir, "Stmt", Arrays.asList(
-      "Print    : Expr expression"+      "Print    : Token location, Expr expression"
     ));     ));
   }   }
 </code> </code>
 +
 +The ''Print'' class contains a ''Token'' instance to support reporting error locations.
  
 ===== Parsing statements ===== ===== Parsing statements =====
Line 58: Line 60:
  
 Our ''statement()'' method is different from the book; if we're in REPL mode we parse & return a statement wrapped in a ''Stmt.Print'' object, and error otherwise. Our ''statement()'' method is different from the book; if we're in REPL mode we parse & return a statement wrapped in a ''Stmt.Print'' object, and error otherwise.
 +Use ''peek()'' to get the first token in the expression for error location reporting.
 We'll return to this method later to add parsing logic for operator definitions. We'll return to this method later to add parsing logic for operator definitions.
- 
 <code java> <code java>
   private Stmt statement() {   private Stmt statement() {
-    if (replMode) return new Stmt.Print(expression());+    if (replMode) return new Stmt.Print(peek(), expression());
  
     throw error(peek(), "Expected statement.");     throw error(peek(), "Expected statement.");
Line 71: Line 73:
  
 Add ''Stmt'' to the list of interfaces implemented by the ''Interpreter'' class: Add ''Stmt'' to the list of interfaces implemented by the ''Interpreter'' class:
- 
 <code java [highlight_lines_extra="2"]> <code java [highlight_lines_extra="2"]>
 class Interpreter implements Expr.Visitor<Object>, class Interpreter implements Expr.Visitor<Object>,
Line 79: Line 80:
  
 Now add a visitor method for the ''Stmt.Print'' class, after ''evaluate()'' in the ''Interpreter'' class. Now add a visitor method for the ''Stmt.Print'' class, after ''evaluate()'' in the ''Interpreter'' class.
-This is identical to the book except for one thing, which we will change to improve the testability of our interpreter: +This is identical to the book: 
- +<code java>
-<code java [highlight_lines_extra="4"]>+
   @Override   @Override
   public Void visitPrintStmt(Stmt.Print stmt) {   public Void visitPrintStmt(Stmt.Print stmt) {
     Object value = evaluate(stmt.expression);     Object value = evaluate(stmt.expression);
-    out.println(stringify(value));+    System.out.println(stringify(value));
     return null;     return null;
-  } 
-</code> 
- 
-Instead of printing directly to ''System.out'', we add a ''[[https://docs.oracle.com/javase/8/docs/api/java/io/PrintStream.html|PrintStream]]'' field to the ''Interpreter'' class called ''out''. 
-''System.out'' implements the ''PrintStream'' interface, but so do other things, and if we want to write unit tests for this class it helps to be able to intercept its output. 
-Add a constructor for the ''Interpreter'' class along with the field; also add a ''replMode'' parameter, although don't make use of it just yet: 
- 
-<code java [highlight_lines_extra="3,5,6,7"]> 
-class Interpreter implements Expr.Visitor<Object>, 
-                             Stmt.Visitor<Void> { 
-  private final PrintStream out; 
- 
-  public Interpreter(PrintStream out, boolean replMode) { 
-    this.out = out; 
   }   }
 </code> </code>
Line 106: Line 92:
 Same as the book, modify the old ''interpret()'' method to accept a list of statements. Same as the book, modify the old ''interpret()'' method to accept a list of statements.
 The changed method is identical to the book except for using ''TlaPlus'' instead of ''Lox'': The changed method is identical to the book except for using ''TlaPlus'' instead of ''Lox'':
- 
 <code java [highlight_lines_extra="7"]> <code java [highlight_lines_extra="7"]>
   void interpret(List<Stmt> statements) {   void interpret(List<Stmt> statements) {
Line 120: Line 105:
  
 Also add the ''execute()'' helper method to the ''Interpreter'' class: Also add the ''execute()'' helper method to the ''Interpreter'' class:
- 
 <code java> <code java>
   private void execute(Stmt stmt) {   private void execute(Stmt stmt) {
Line 127: Line 111:
 </code> </code>
  
-At the top of ''Interpreter.java'', import the classes we're now using: +At the top of ''Interpreter.java'', add an import for the ''List'' class that is now being used by ''interpret()''
- +<code java [highlight_lines_extra="5"]>
-<code java [highlight_lines_extra="5,6"]>+
 package tla; package tla;
  
Line 135: Line 118:
 import java.util.HashSet; import java.util.HashSet;
 import java.util.List; import java.util.List;
-import java.io.PrintStream; 
 </code> </code>
  
Line 154: Line 136:
 </code> </code>
  
-Then replace the call to the interpreter with this: +Still in ''run()'', replace the call to the interpreter with this:
 <code java [highlight_lines_extra="3"]> <code java [highlight_lines_extra="3"]>
     if (hadError) return;     if (hadError) return;
Line 176: Line 157:
 <code java [highlight_lines_extra="2,4"]> <code java [highlight_lines_extra="2,4"]>
   private static void runFile(String path) throws IOException {   private static void runFile(String path) throws IOException {
-    interpreter = new Interpreter(System.out, false);+    interpreter = new Interpreter(false);
     byte[] bytes = Files.readAllBytes(Paths.get(path));     byte[] bytes = Files.readAllBytes(Paths.get(path));
     run(new String(bytes, StandardCharsets.UTF_8), false);     run(new String(bytes, StandardCharsets.UTF_8), false);
Line 185: Line 166:
 <code java [highlight_lines_extra="2,10"]> <code java [highlight_lines_extra="2,10"]>
   private static void runPrompt() throws IOException {   private static void runPrompt() throws IOException {
-    interpreter = new Interpreter(System.out, true);+    interpreter = new Interpreter(true);
     InputStreamReader input = new InputStreamReader(System.in);     InputStreamReader input = new InputStreamReader(System.in);
     BufferedReader reader = new BufferedReader(input);     BufferedReader reader = new BufferedReader(input);
Line 196: Line 177:
       hadError = false;       hadError = false;
     }     }
 +  }
 +</code>
 +
 +We just used an ''Interpreter'' constructor accepting a parameter indicating whether we're operating in REPL mode.
 +Write that constructor now, although don't yet do anything with the parameter:
 +<code Java>
 +  public Interpreter(boolean replMode) {
 +
   }   }
 </code> </code>
Line 212: Line 201:
 <code java [highlight_lines_extra="3"]> <code java [highlight_lines_extra="3"]>
     defineAst(outputDir, "Stmt", Arrays.asList(     defineAst(outputDir, "Stmt", Arrays.asList(
-      "Print    : Expr expression",+      "Print    : Token location, Expr expression",
       "OpDef    : Token name, Expr body"       "OpDef    : Token name, Expr body"
     ));     ));
Line 386: Line 375:
  
 Now add an ''Environment'' instance as a field of your ''Interpreter'' class; here's where we make use of the ''replMode'' constructor parameter we added up above: Now add an ''Environment'' instance as a field of your ''Interpreter'' class; here's where we make use of the ''replMode'' constructor parameter we added up above:
- +<code java [highlight_lines_extra="3,6"]>
-<code java [highlight_lines_extra="3,7"]>+
 class Interpreter implements Expr.Visitor<Object>, class Interpreter implements Expr.Visitor<Object>,
                              Stmt.Visitor<Void> {                              Stmt.Visitor<Void> {
   private Environment environment;   private Environment environment;
-  private final PrintStream out; 
  
-  public Interpreter(PrintStream out, boolean replMode) {+  public Interpreter(boolean replMode) {
     this.environment = new Environment(replMode);     this.environment = new Environment(replMode);
-    this.out = out; 
   }   }
 </code> </code>
  
-Now add a visitor method in the ''Interpreter'' class for the ''Expr.Variable'' class, which retrieves the value of the variable from the environment: +Add a visitor method in the ''Interpreter'' class for the ''Expr.Variable'' class, which retrieves the value of the variable from the environment:
 <code java> <code java>
   @Override   @Override
Line 407: Line 392:
   }   }
 </code> </code>
- 
  
 ====== Section 8.4: Assignment ====== ====== Section 8.4: Assignment ======
Line 463: Line 447:
  
 Next up, our greatest parsing challenge yet: [[creating:jlists|conjunction & disjunction lists]]! Next up, our greatest parsing challenge yet: [[creating:jlists|conjunction & disjunction lists]]!
-If your code got out of sync during this tutorial, you can find a snapshot of its expected state in [[https://github.com/tlaplus-community/tlaplus-creator/tree/main/5-statements|this repo directory]].+If your code got out of sync during this tutorial, you can find a snapshot of its expected state in [[https://github.com/tlaplus/devkit/tree/main/5-statements|this repo directory]].
  
 ====== Section 8.5: Challenges ====== ====== Section 8.5: Challenges ======
  
-  - Write some unit tests for your interpreter. Use a ''[[https://docs.oracle.com/javase/8/docs/api/java/io/ByteArrayOutputStream.html|ByteArrayOutputStream]]'' instance as parameter to the ''PrintStream'' constructor, then pass your ''PrintStream'' instance into the ''Interpreter'' class to capture its output.+  - Write some unit tests for your interpreter. Capture the ''System.out'' output; use the ''[[https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#setOut-java.io.PrintStream-|System.setOut()]]'' method with a ''[[https://docs.oracle.com/javase/8/docs/api/java/io/PrintStream.html|PrintStream]]'' instance constructed using a ''[[https://docs.oracle.com/javase/8/docs/api/java/io/ByteArrayOutputStream.html|ByteArrayOutputStream]]''.
   - The ''isAtOpDefStart()'' and ''operatorDefinition()'' methods have some duplicated logic that will only grow more involved when we add operator parameter support. Can you find a way to factor out this logic into a single method?   - The ''isAtOpDefStart()'' and ''operatorDefinition()'' methods have some duplicated logic that will only grow more involved when we add operator parameter support. Can you find a way to factor out this logic into a single method?
  
 [[creating:evaluation|< Previous Page]] | [[creating:start#table_of_contents|Table of Contents]] | [[creating:jlists|Next Page >]] [[creating:evaluation|< Previous Page]] | [[creating:start#table_of_contents|Table of Contents]] | [[creating:jlists|Next Page >]]
  
  • creating/statements.1745092059.txt.gz
  • Last modified: 2025/04/19 19:47
  • by ahelwer