Showing preview only (4,812K chars total). Download the full file or copy to clipboard to get everything.
Repository: munificent/craftinginterpreters
Branch: master
Commit: 4a840f70f69c
Files: 548
Total size: 4.5 MB
Directory structure:
gitextract_s3p1_s2h/
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── asset/
│ ├── index.scss
│ ├── mustache/
│ │ ├── contents-nav.html
│ │ ├── contents-part.html
│ │ ├── contents.html
│ │ ├── footer.html
│ │ ├── header.html
│ │ ├── in_design.html
│ │ ├── index.html
│ │ ├── nav.html
│ │ ├── page.html
│ │ └── prev-next.html
│ ├── sass/
│ │ ├── chapter.scss
│ │ ├── contents.scss
│ │ ├── print.scss
│ │ ├── shared.scss
│ │ └── sign-up.scss
│ └── style.scss
├── book/
│ ├── a-bytecode-virtual-machine.md
│ ├── a-map-of-the-territory.md
│ ├── a-tree-walk-interpreter.md
│ ├── a-virtual-machine.md
│ ├── acknowledgements.md
│ ├── appendix-i.md
│ ├── appendix-ii.md
│ ├── backmatter.md
│ ├── calls-and-functions.md
│ ├── chunks-of-bytecode.md
│ ├── classes-and-instances.md
│ ├── classes.md
│ ├── closures.md
│ ├── compiling-expressions.md
│ ├── contents.md
│ ├── control-flow.md
│ ├── dedication.md
│ ├── evaluating-expressions.md
│ ├── functions.md
│ ├── garbage-collection.md
│ ├── global-variables.md
│ ├── hash-tables.md
│ ├── index.md
│ ├── inheritance.md
│ ├── introduction.md
│ ├── jumping-back-and-forth.md
│ ├── local-variables.md
│ ├── methods-and-initializers.md
│ ├── optimization.md
│ ├── parsing-expressions.md
│ ├── representing-code.md
│ ├── resolving-and-binding.md
│ ├── scanning-on-demand.md
│ ├── scanning.md
│ ├── statements-and-state.md
│ ├── strings.md
│ ├── superclasses.md
│ ├── the-lox-language.md
│ ├── types-of-values.md
│ └── welcome.md
├── c/
│ ├── chunk.c
│ ├── chunk.h
│ ├── clox.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── clox.xcscheme
│ ├── common.h
│ ├── compiler.c
│ ├── compiler.h
│ ├── debug.c
│ ├── debug.h
│ ├── main.c
│ ├── memory.c
│ ├── memory.h
│ ├── object.c
│ ├── object.h
│ ├── scanner.c
│ ├── scanner.h
│ ├── table.c
│ ├── table.h
│ ├── value.c
│ ├── value.h
│ ├── vm.c
│ └── vm.h
├── java/
│ └── com/
│ └── craftinginterpreters/
│ ├── lox/
│ │ ├── AstPrinter.java
│ │ ├── Environment.java
│ │ ├── Expr.java
│ │ ├── Interpreter.java
│ │ ├── Lox.java
│ │ ├── LoxCallable.java
│ │ ├── LoxClass.java
│ │ ├── LoxFunction.java
│ │ ├── LoxInstance.java
│ │ ├── Parser.java
│ │ ├── Resolver.java
│ │ ├── Return.java
│ │ ├── RuntimeError.java
│ │ ├── Scanner.java
│ │ ├── Stmt.java
│ │ ├── Token.java
│ │ └── TokenType.java
│ └── tool/
│ └── GenerateAst.java
├── jlox
├── note/
│ ├── BISAC.txt
│ ├── answers/
│ │ ├── chapter01_introduction/
│ │ │ ├── 1.md
│ │ │ ├── 2/
│ │ │ │ ├── Hello.java
│ │ │ │ └── Makefile
│ │ │ └── 3/
│ │ │ ├── Makefile
│ │ │ ├── linked_list
│ │ │ ├── linked_list.c
│ │ │ └── linked_list.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── project.xcworkspace/
│ │ │ └── contents.xcworkspacedata
│ │ ├── chapter02_map.md
│ │ ├── chapter03_lox.md
│ │ ├── chapter04_scanning.md
│ │ ├── chapter05_representing.md
│ │ ├── chapter06_parsing.md
│ │ ├── chapter07_evaluating.md
│ │ ├── chapter08_statements.md
│ │ ├── chapter09_control.md
│ │ ├── chapter10_functions.md
│ │ ├── chapter11_resolving/
│ │ │ ├── 4/
│ │ │ │ └── com/
│ │ │ │ └── craftinginterpreters/
│ │ │ │ ├── lox/
│ │ │ │ │ ├── AstPrinter.java
│ │ │ │ │ ├── Environment.java
│ │ │ │ │ ├── Expr.java
│ │ │ │ │ ├── Interpreter.java
│ │ │ │ │ ├── Lox.java
│ │ │ │ │ ├── LoxCallable.java
│ │ │ │ │ ├── LoxFunction.java
│ │ │ │ │ ├── Parser.java
│ │ │ │ │ ├── Resolver.java
│ │ │ │ │ ├── Return.java
│ │ │ │ │ ├── RuntimeError.java
│ │ │ │ │ ├── Scanner.java
│ │ │ │ │ ├── Stmt.java
│ │ │ │ │ ├── Token.java
│ │ │ │ │ └── TokenType.java
│ │ │ │ └── tool/
│ │ │ │ └── GenerateAst.java
│ │ │ └── chapter11_resolving.md
│ │ ├── chapter12_classes.md
│ │ ├── chapter13_inheritance/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ └── 3.md
│ │ ├── chapter14_chunks/
│ │ │ ├── 1.md
│ │ │ └── 2.md
│ │ ├── chapter15_virtual/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ └── 3.md
│ │ ├── chapter16_scanning.md
│ │ ├── chapter17_compiling.md
│ │ ├── chapter18_types.md
│ │ ├── chapter19_strings.md
│ │ ├── chapter20_hash/
│ │ │ └── 1.md
│ │ ├── chapter21_global.md
│ │ ├── chapter23_jumping/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ └── 3.md
│ │ ├── chapter24_calls/
│ │ │ ├── 1.md
│ │ │ └── 2.md
│ │ ├── chapter25_closures/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ └── 3.lox
│ │ ├── chapter26_garbage/
│ │ │ ├── 1.md
│ │ │ └── 2.md
│ │ ├── chapter27_classes/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ ├── 3.md
│ │ │ └── 4.md
│ │ ├── chapter28_methods/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ └── 3.md
│ │ └── chapter29_superclasses/
│ │ ├── 1.md
│ │ ├── 2.md
│ │ ├── 3.diff
│ │ └── 3.md
│ ├── blurb.txt
│ ├── contents.txt
│ ├── design breaks.md
│ ├── images.md
│ ├── indexing.md
│ ├── log.txt
│ ├── names.txt
│ ├── objects.txt
│ ├── outline.md
│ ├── research.txt
│ ├── scope.txt
│ ├── struct sizes.txt
│ ├── style guide.md
│ └── todo.txt
├── site/
│ ├── .htaccess
│ ├── 404.html
│ ├── a-bytecode-virtual-machine.html
│ ├── a-map-of-the-territory.html
│ ├── a-tree-walk-interpreter.html
│ ├── a-virtual-machine.html
│ ├── acknowledgements.html
│ ├── appendix-i.html
│ ├── appendix-ii.html
│ ├── backmatter.html
│ ├── calls-and-functions.html
│ ├── chunks-of-bytecode.html
│ ├── classes-and-instances.html
│ ├── classes.html
│ ├── closures.html
│ ├── compiling-expressions.html
│ ├── contents.html
│ ├── control-flow.html
│ ├── dedication.html
│ ├── evaluating-expressions.html
│ ├── functions.html
│ ├── garbage-collection.html
│ ├── global-variables.html
│ ├── hash-tables.html
│ ├── index.css
│ ├── index.html
│ ├── inheritance.html
│ ├── introduction.html
│ ├── jumping-back-and-forth.html
│ ├── local-variables.html
│ ├── methods-and-initializers.html
│ ├── optimization.html
│ ├── parsing-expressions.html
│ ├── representing-code.html
│ ├── resolving-and-binding.html
│ ├── scanning-on-demand.html
│ ├── scanning.html
│ ├── script.js
│ ├── statements-and-state.html
│ ├── strings.html
│ ├── style.css
│ ├── superclasses.html
│ ├── the-lox-language.html
│ ├── types-of-values.html
│ └── welcome.html
├── test/
│ ├── assignment/
│ │ ├── associativity.lox
│ │ ├── global.lox
│ │ ├── grouping.lox
│ │ ├── infix_operator.lox
│ │ ├── local.lox
│ │ ├── prefix_operator.lox
│ │ ├── syntax.lox
│ │ ├── to_this.lox
│ │ └── undefined.lox
│ ├── benchmark/
│ │ ├── binary_trees.lox
│ │ ├── equality.lox
│ │ ├── fib.lox
│ │ ├── instantiation.lox
│ │ ├── invocation.lox
│ │ ├── method_call.lox
│ │ ├── properties.lox
│ │ ├── string_equality.lox
│ │ ├── trees.lox
│ │ ├── zoo.lox
│ │ └── zoo_batch.lox
│ ├── block/
│ │ ├── empty.lox
│ │ └── scope.lox
│ ├── bool/
│ │ ├── equality.lox
│ │ └── not.lox
│ ├── call/
│ │ ├── bool.lox
│ │ ├── nil.lox
│ │ ├── num.lox
│ │ ├── object.lox
│ │ └── string.lox
│ ├── class/
│ │ ├── empty.lox
│ │ ├── inherit_self.lox
│ │ ├── inherited_method.lox
│ │ ├── local_inherit_other.lox
│ │ ├── local_inherit_self.lox
│ │ ├── local_reference_self.lox
│ │ └── reference_self.lox
│ ├── closure/
│ │ ├── assign_to_closure.lox
│ │ ├── assign_to_shadowed_later.lox
│ │ ├── close_over_function_parameter.lox
│ │ ├── close_over_later_variable.lox
│ │ ├── close_over_method_parameter.lox
│ │ ├── closed_closure_in_function.lox
│ │ ├── nested_closure.lox
│ │ ├── open_closure_in_function.lox
│ │ ├── reference_closure_multiple_times.lox
│ │ ├── reuse_closure_slot.lox
│ │ ├── shadow_closure_with_local.lox
│ │ ├── unused_closure.lox
│ │ └── unused_later_closure.lox
│ ├── comments/
│ │ ├── line_at_eof.lox
│ │ ├── only_line_comment.lox
│ │ ├── only_line_comment_and_line.lox
│ │ └── unicode.lox
│ ├── constructor/
│ │ ├── arguments.lox
│ │ ├── call_init_early_return.lox
│ │ ├── call_init_explicitly.lox
│ │ ├── default.lox
│ │ ├── default_arguments.lox
│ │ ├── early_return.lox
│ │ ├── extra_arguments.lox
│ │ ├── init_not_method.lox
│ │ ├── missing_arguments.lox
│ │ ├── return_in_nested_function.lox
│ │ └── return_value.lox
│ ├── empty_file.lox
│ ├── expressions/
│ │ ├── evaluate.lox
│ │ └── parse.lox
│ ├── field/
│ │ ├── call_function_field.lox
│ │ ├── call_nonfunction_field.lox
│ │ ├── get_and_set_method.lox
│ │ ├── get_on_bool.lox
│ │ ├── get_on_class.lox
│ │ ├── get_on_function.lox
│ │ ├── get_on_nil.lox
│ │ ├── get_on_num.lox
│ │ ├── get_on_string.lox
│ │ ├── many.lox
│ │ ├── method.lox
│ │ ├── method_binds_this.lox
│ │ ├── on_instance.lox
│ │ ├── set_evaluation_order.lox
│ │ ├── set_on_bool.lox
│ │ ├── set_on_class.lox
│ │ ├── set_on_function.lox
│ │ ├── set_on_nil.lox
│ │ ├── set_on_num.lox
│ │ ├── set_on_string.lox
│ │ └── undefined.lox
│ ├── for/
│ │ ├── class_in_body.lox
│ │ ├── closure_in_body.lox
│ │ ├── fun_in_body.lox
│ │ ├── return_closure.lox
│ │ ├── return_inside.lox
│ │ ├── scope.lox
│ │ ├── statement_condition.lox
│ │ ├── statement_increment.lox
│ │ ├── statement_initializer.lox
│ │ ├── syntax.lox
│ │ └── var_in_body.lox
│ ├── function/
│ │ ├── body_must_be_block.lox
│ │ ├── empty_body.lox
│ │ ├── extra_arguments.lox
│ │ ├── local_mutual_recursion.lox
│ │ ├── local_recursion.lox
│ │ ├── missing_arguments.lox
│ │ ├── missing_comma_in_parameters.lox
│ │ ├── mutual_recursion.lox
│ │ ├── nested_call_with_arguments.lox
│ │ ├── parameters.lox
│ │ ├── print.lox
│ │ ├── recursion.lox
│ │ ├── too_many_arguments.lox
│ │ └── too_many_parameters.lox
│ ├── if/
│ │ ├── class_in_else.lox
│ │ ├── class_in_then.lox
│ │ ├── dangling_else.lox
│ │ ├── else.lox
│ │ ├── fun_in_else.lox
│ │ ├── fun_in_then.lox
│ │ ├── if.lox
│ │ ├── truth.lox
│ │ ├── var_in_else.lox
│ │ └── var_in_then.lox
│ ├── inheritance/
│ │ ├── constructor.lox
│ │ ├── inherit_from_function.lox
│ │ ├── inherit_from_nil.lox
│ │ ├── inherit_from_number.lox
│ │ ├── inherit_methods.lox
│ │ ├── parenthesized_superclass.lox
│ │ └── set_fields_from_base_class.lox
│ ├── limit/
│ │ ├── loop_too_large.lox
│ │ ├── no_reuse_constants.lox
│ │ ├── stack_overflow.lox
│ │ ├── too_many_constants.lox
│ │ ├── too_many_locals.lox
│ │ └── too_many_upvalues.lox
│ ├── logical_operator/
│ │ ├── and.lox
│ │ ├── and_truth.lox
│ │ ├── or.lox
│ │ └── or_truth.lox
│ ├── method/
│ │ ├── arity.lox
│ │ ├── empty_block.lox
│ │ ├── extra_arguments.lox
│ │ ├── missing_arguments.lox
│ │ ├── not_found.lox
│ │ ├── print_bound_method.lox
│ │ ├── refer_to_name.lox
│ │ ├── too_many_arguments.lox
│ │ └── too_many_parameters.lox
│ ├── nil/
│ │ └── literal.lox
│ ├── number/
│ │ ├── decimal_point_at_eof.lox
│ │ ├── leading_dot.lox
│ │ ├── literals.lox
│ │ ├── nan_equality.lox
│ │ └── trailing_dot.lox
│ ├── operator/
│ │ ├── add.lox
│ │ ├── add_bool_nil.lox
│ │ ├── add_bool_num.lox
│ │ ├── add_bool_string.lox
│ │ ├── add_nil_nil.lox
│ │ ├── add_num_nil.lox
│ │ ├── add_string_nil.lox
│ │ ├── comparison.lox
│ │ ├── divide.lox
│ │ ├── divide_nonnum_num.lox
│ │ ├── divide_num_nonnum.lox
│ │ ├── equals.lox
│ │ ├── equals_class.lox
│ │ ├── equals_method.lox
│ │ ├── greater_nonnum_num.lox
│ │ ├── greater_num_nonnum.lox
│ │ ├── greater_or_equal_nonnum_num.lox
│ │ ├── greater_or_equal_num_nonnum.lox
│ │ ├── less_nonnum_num.lox
│ │ ├── less_num_nonnum.lox
│ │ ├── less_or_equal_nonnum_num.lox
│ │ ├── less_or_equal_num_nonnum.lox
│ │ ├── multiply.lox
│ │ ├── multiply_nonnum_num.lox
│ │ ├── multiply_num_nonnum.lox
│ │ ├── negate.lox
│ │ ├── negate_nonnum.lox
│ │ ├── not.lox
│ │ ├── not_class.lox
│ │ ├── not_equals.lox
│ │ ├── subtract.lox
│ │ ├── subtract_nonnum_num.lox
│ │ └── subtract_num_nonnum.lox
│ ├── precedence.lox
│ ├── print/
│ │ └── missing_argument.lox
│ ├── regression/
│ │ ├── 394.lox
│ │ └── 40.lox
│ ├── return/
│ │ ├── after_else.lox
│ │ ├── after_if.lox
│ │ ├── after_while.lox
│ │ ├── at_top_level.lox
│ │ ├── in_function.lox
│ │ ├── in_method.lox
│ │ └── return_nil_if_no_value.lox
│ ├── scanning/
│ │ ├── identifiers.lox
│ │ ├── keywords.lox
│ │ ├── numbers.lox
│ │ ├── punctuators.lox
│ │ ├── strings.lox
│ │ └── whitespace.lox
│ ├── string/
│ │ ├── error_after_multiline.lox
│ │ ├── literals.lox
│ │ ├── multiline.lox
│ │ └── unterminated.lox
│ ├── super/
│ │ ├── bound_method.lox
│ │ ├── call_other_method.lox
│ │ ├── call_same_method.lox
│ │ ├── closure.lox
│ │ ├── constructor.lox
│ │ ├── extra_arguments.lox
│ │ ├── indirectly_inherited.lox
│ │ ├── missing_arguments.lox
│ │ ├── no_superclass_bind.lox
│ │ ├── no_superclass_call.lox
│ │ ├── no_superclass_method.lox
│ │ ├── parenthesized.lox
│ │ ├── reassign_superclass.lox
│ │ ├── super_at_top_level.lox
│ │ ├── super_in_closure_in_inherited_method.lox
│ │ ├── super_in_inherited_method.lox
│ │ ├── super_in_top_level_function.lox
│ │ ├── super_without_dot.lox
│ │ ├── super_without_name.lox
│ │ └── this_in_superclass_method.lox
│ ├── this/
│ │ ├── closure.lox
│ │ ├── nested_class.lox
│ │ ├── nested_closure.lox
│ │ ├── this_at_top_level.lox
│ │ ├── this_in_method.lox
│ │ └── this_in_top_level_function.lox
│ ├── unexpected_character.lox
│ ├── variable/
│ │ ├── collide_with_parameter.lox
│ │ ├── duplicate_local.lox
│ │ ├── duplicate_parameter.lox
│ │ ├── early_bound.lox
│ │ ├── in_middle_of_block.lox
│ │ ├── in_nested_block.lox
│ │ ├── local_from_method.lox
│ │ ├── redeclare_global.lox
│ │ ├── redefine_global.lox
│ │ ├── scope_reuse_in_different_blocks.lox
│ │ ├── shadow_and_local.lox
│ │ ├── shadow_global.lox
│ │ ├── shadow_local.lox
│ │ ├── undefined_global.lox
│ │ ├── undefined_local.lox
│ │ ├── uninitialized.lox
│ │ ├── unreached_undefined.lox
│ │ ├── use_false_as_var.lox
│ │ ├── use_global_in_initializer.lox
│ │ ├── use_local_in_initializer.lox
│ │ ├── use_nil_as_var.lox
│ │ └── use_this_as_var.lox
│ └── while/
│ ├── class_in_body.lox
│ ├── closure_in_body.lox
│ ├── fun_in_body.lox
│ ├── return_closure.lox
│ ├── return_inside.lox
│ ├── syntax.lox
│ └── var_in_body.lox
├── tool/
│ ├── analysis_options.yaml
│ ├── bin/
│ │ ├── benchmark.dart
│ │ ├── build.dart
│ │ ├── build_xml.dart
│ │ ├── compile_snippets.dart
│ │ ├── split_chapters.dart
│ │ ├── test.dart
│ │ └── tile_pages.dart
│ ├── lib/
│ │ └── src/
│ │ ├── book.dart
│ │ ├── code_tag.dart
│ │ ├── format.dart
│ │ ├── location.dart
│ │ ├── markdown/
│ │ │ ├── block_syntax.dart
│ │ │ ├── code_syntax.dart
│ │ │ ├── html_renderer.dart
│ │ │ ├── inline_syntax.dart
│ │ │ ├── markdown.dart
│ │ │ └── xml_renderer.dart
│ │ ├── mustache.dart
│ │ ├── page.dart
│ │ ├── page_parser.dart
│ │ ├── snippet.dart
│ │ ├── source_file_parser.dart
│ │ ├── split_chapter.dart
│ │ ├── syntax/
│ │ │ ├── grammar.dart
│ │ │ ├── highlighter.dart
│ │ │ ├── language.dart
│ │ │ └── rule.dart
│ │ ├── term.dart
│ │ └── text.dart
│ └── pubspec.yaml
└── util/
├── c.make
├── intellij/
│ ├── chap04_read.iml
│ ├── chap05_scanning.iml
│ ├── chap06_representing.iml
│ ├── chap07_parsing.iml
│ ├── chap08_evaluating.iml
│ ├── chap09_statements.iml
│ ├── chap10_control.iml
│ ├── chap11_functions.iml
│ ├── chap12_resolving.iml
│ ├── chap13_classes.iml
│ ├── chap14_inheritance.iml
│ ├── intellij.iml
│ ├── jlox.iml
│ ├── section_test.iml
│ └── snippet_test.iml
└── java.make
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Intermediate and built stuff.
.sass-cache/
/build/
/gen/
clox
*.class
exercises/chapter01_introduction/3/linked_list
.idea/
# I keep a scratch file at the top level to try stuff out.
temp.lox
# XCode user-specific stuff.
xcuserdata/
# Dart stuff.
/tool/.dart_tool/
/tool/.packages
================================================
FILE: LICENSE
================================================
Copyright (c) 2015 Robert Nystrom
---------------------------------- Commentary ----------------------------------
The licensing story for this repository is a little complex. Here's my
motivation:
* I want you to get as much use out of the material here as possible. I wrote
this book to help you, and I don't want you to be encumbered when it comes to
making the most of it. That's also why I put it online for free.
* With my previous book, collaboration on GitHub was immesensely helpful. I want
to ensure people can fork the repo, send me fixes, etc. without violating the
license or feeling weird.
* When it comes to code, I'm completely comfortable with people redistributing,
remixing, changing, whatever with it. I've been using the MIT license for open
source stuff for decades.
This book contains two complete interpreters and I would be delighted for them
to be the jumping-off point for any number of real full-featured language
implementations.
* When it comes to my prose, illustrations, and the visual design of the site,
that feels a little more, I don't know, *me* than the code. The words are in
my voice, the drawings are literally my handwriting, and the look of the site
is part of the book's and, by extension, my brand.
I feel weird thinking about someone, say taking one of the chapters and making
significant changes to it to fit their writing style while still having some
of it read like it came from me. Likewise, I'd be sad to see another site
online that looked exactly like mine because it reuses my stylesheets.
* My previous book ended up being translated into several languages. I want to
be careful to not be so permissive that it prevents me from signing typical
contracts that give them exclusive translation rights to certain territories
and languages.
* If I allow the prose and illustrations to be redistributed commercially, there
is nothing preventing someone from slapping together a cheap print or ebook
version of the book and putting it up for sale. I'm not too worried about my
own sales being undercut, but I very much want to avoid readers finding
themselves with a low quality book that they incorrectly think is from me.
I worked very hard on this book. I want you to get the best possible
experience.
All of this is way more complex than I'd like, especially since my brain isn't
wired to care about intellectual property. I like thinking about making stuff,
not thinking about the legal rights around the stuff I made. (If your brain is
wired to think about legal stuff and you see that I'm doing something dumb,
please do let me know.)
The best solution I've been able to come up with is to use two licenses:
---------------------------------- License(s) ----------------------------------
Each file in this repository falls under one of two licenses. Files whose
extension is ".c", ".dart", ".h", ".java", or ".lox" use the MIT license:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
All other files, including (but not limited to) ".md" (except for
"book/appendix-i.md" which uses the MIT license above), ".png", ".jpg", ".html",
".scss", ".css", and ".txt" use this Creative Commons license:
Attribution-NonCommercial-NoDerivatives 4.0
International (CC BY-NC-ND 4.0)
https://creativecommons.org/licenses/by-nc-nd/4.0/
================================================
FILE: Makefile
================================================
BUILD_DIR := build
TOOL_SOURCES := tool/pubspec.lock $(shell find tool -name '*.dart')
BUILD_SNAPSHOT := $(BUILD_DIR)/build.dart.snapshot
TEST_SNAPSHOT := $(BUILD_DIR)/test.dart.snapshot
default: book clox jlox
# Run dart pub get on tool directory.
get:
@ cd ./tool; dart pub get
# Remove all build outputs and intermediate files.
clean:
@ rm -rf $(BUILD_DIR)
@ rm -rf gen
# Build the site.
book: $(BUILD_SNAPSHOT)
@ dart $(BUILD_SNAPSHOT)
# Run a local development server for the site that rebuilds automatically.
serve: $(BUILD_SNAPSHOT)
@ dart $(BUILD_SNAPSHOT) --serve
$(BUILD_SNAPSHOT): $(TOOL_SOURCES)
@ mkdir -p build
@ echo "Compiling Dart snapshot..."
@ dart --snapshot=$@ --snapshot-kind=app-jit tool/bin/build.dart >/dev/null
# Run the tests for the final versions of clox and jlox.
test: debug jlox $(TEST_SNAPSHOT)
@- dart $(TEST_SNAPSHOT) clox
@ dart $(TEST_SNAPSHOT) jlox
# Run the tests for the final version of clox.
test_clox: debug $(TEST_SNAPSHOT)
@ dart $(TEST_SNAPSHOT) clox
# Run the tests for the final version of jlox.
test_jlox: jlox $(TEST_SNAPSHOT)
@ dart $(TEST_SNAPSHOT) jlox
# Run the tests for every chapter's version of clox.
test_c: debug c_chapters $(TEST_SNAPSHOT)
@ dart $(TEST_SNAPSHOT) c
# Run the tests for every chapter's version of jlox.
test_java: jlox java_chapters $(TEST_SNAPSHOT)
@ dart $(TEST_SNAPSHOT) java
# Run the tests for every chapter's version of clox and jlox.
test_all: debug jlox c_chapters java_chapters compile_snippets $(TEST_SNAPSHOT)
@ dart $(TEST_SNAPSHOT) all
$(TEST_SNAPSHOT): $(TOOL_SOURCES)
@ mkdir -p build
@ echo "Compiling Dart snapshot..."
@ dart --snapshot=$@ --snapshot-kind=app-jit tool/bin/test.dart clox >/dev/null
# Compile a debug build of clox.
debug:
@ $(MAKE) -f util/c.make NAME=cloxd MODE=debug SOURCE_DIR=c
# Compile the C interpreter.
clox:
@ $(MAKE) -f util/c.make NAME=clox MODE=release SOURCE_DIR=c
@ cp build/clox clox # For convenience, copy the interpreter to the top level.
# Compile the C interpreter as ANSI standard C++.
cpplox:
@ $(MAKE) -f util/c.make NAME=cpplox MODE=debug CPP=true SOURCE_DIR=c
# Compile and run the AST generator.
generate_ast:
@ $(MAKE) -f util/java.make DIR=java PACKAGE=tool
@ java -cp build/java com.craftinginterpreters.tool.GenerateAst \
java/com/craftinginterpreters/lox
# Compile the Java interpreter .java files to .class files.
jlox: generate_ast
@ $(MAKE) -f util/java.make DIR=java PACKAGE=lox
run_generate_ast = @ java -cp build/gen/$(1) \
com.craftinginterpreters.tool.GenerateAst \
gen/$(1)/com/craftinginterpreters/lox
java_chapters: split_chapters
@ $(MAKE) -f util/java.make DIR=gen/chap04_scanning PACKAGE=lox
@ $(MAKE) -f util/java.make DIR=gen/chap05_representing PACKAGE=tool
$(call run_generate_ast,chap05_representing)
@ $(MAKE) -f util/java.make DIR=gen/chap05_representing PACKAGE=lox
@ $(MAKE) -f util/java.make DIR=gen/chap06_parsing PACKAGE=tool
$(call run_generate_ast,chap06_parsing)
@ $(MAKE) -f util/java.make DIR=gen/chap06_parsing PACKAGE=lox
@ $(MAKE) -f util/java.make DIR=gen/chap07_evaluating PACKAGE=tool
$(call run_generate_ast,chap07_evaluating)
@ $(MAKE) -f util/java.make DIR=gen/chap07_evaluating PACKAGE=lox
@ $(MAKE) -f util/java.make DIR=gen/chap08_statements PACKAGE=tool
$(call run_generate_ast,chap08_statements)
@ $(MAKE) -f util/java.make DIR=gen/chap08_statements PACKAGE=lox
@ $(MAKE) -f util/java.make DIR=gen/chap09_control PACKAGE=tool
$(call run_generate_ast,chap09_control)
@ $(MAKE) -f util/java.make DIR=gen/chap09_control PACKAGE=lox
@ $(MAKE) -f util/java.make DIR=gen/chap10_functions PACKAGE=tool
$(call run_generate_ast,chap10_functions)
@ $(MAKE) -f util/java.make DIR=gen/chap10_functions PACKAGE=lox
@ $(MAKE) -f util/java.make DIR=gen/chap11_resolving PACKAGE=tool
$(call run_generate_ast,chap11_resolving)
@ $(MAKE) -f util/java.make DIR=gen/chap11_resolving PACKAGE=lox
@ $(MAKE) -f util/java.make DIR=gen/chap12_classes PACKAGE=tool
$(call run_generate_ast,chap12_classes)
@ $(MAKE) -f util/java.make DIR=gen/chap12_classes PACKAGE=lox
@ $(MAKE) -f util/java.make DIR=gen/chap13_inheritance PACKAGE=tool
$(call run_generate_ast,chap13_inheritance)
@ $(MAKE) -f util/java.make DIR=gen/chap13_inheritance PACKAGE=lox
c_chapters: split_chapters
@ $(MAKE) -f util/c.make NAME=chap14_chunks MODE=release SOURCE_DIR=gen/chap14_chunks
@ $(MAKE) -f util/c.make NAME=chap15_virtual MODE=release SOURCE_DIR=gen/chap15_virtual
@ $(MAKE) -f util/c.make NAME=chap16_scanning MODE=release SOURCE_DIR=gen/chap16_scanning
@ $(MAKE) -f util/c.make NAME=chap17_compiling MODE=release SOURCE_DIR=gen/chap17_compiling
@ $(MAKE) -f util/c.make NAME=chap18_types MODE=release SOURCE_DIR=gen/chap18_types
@ $(MAKE) -f util/c.make NAME=chap19_strings MODE=release SOURCE_DIR=gen/chap19_strings
@ $(MAKE) -f util/c.make NAME=chap20_hash MODE=release SOURCE_DIR=gen/chap20_hash
@ $(MAKE) -f util/c.make NAME=chap21_global MODE=release SOURCE_DIR=gen/chap21_global
@ $(MAKE) -f util/c.make NAME=chap22_local MODE=release SOURCE_DIR=gen/chap22_local
@ $(MAKE) -f util/c.make NAME=chap23_jumping MODE=release SOURCE_DIR=gen/chap23_jumping
@ $(MAKE) -f util/c.make NAME=chap24_calls MODE=release SOURCE_DIR=gen/chap24_calls
@ $(MAKE) -f util/c.make NAME=chap25_closures MODE=release SOURCE_DIR=gen/chap25_closures
@ $(MAKE) -f util/c.make NAME=chap26_garbage MODE=release SOURCE_DIR=gen/chap26_garbage
@ $(MAKE) -f util/c.make NAME=chap27_classes MODE=release SOURCE_DIR=gen/chap27_classes
@ $(MAKE) -f util/c.make NAME=chap28_methods MODE=release SOURCE_DIR=gen/chap28_methods
@ $(MAKE) -f util/c.make NAME=chap29_superclasses MODE=release SOURCE_DIR=gen/chap29_superclasses
@ $(MAKE) -f util/c.make NAME=chap30_optimization MODE=release SOURCE_DIR=gen/chap30_optimization
cpp_chapters: split_chapters
@ $(MAKE) -f util/c.make NAME=cpp_chap14_chunks MODE=release CPP=true SOURCE_DIR=gen/chap14_chunks
@ $(MAKE) -f util/c.make NAME=cpp_chap15_virtual MODE=release CPP=true SOURCE_DIR=gen/chap15_virtual
@ $(MAKE) -f util/c.make NAME=cpp_chap16_scanning MODE=release CPP=true SOURCE_DIR=gen/chap16_scanning
@ $(MAKE) -f util/c.make NAME=cpp_chap17_compiling MODE=release CPP=true SOURCE_DIR=gen/chap17_compiling
@ $(MAKE) -f util/c.make NAME=cpp_chap18_types MODE=release CPP=true SOURCE_DIR=gen/chap18_types
@ $(MAKE) -f util/c.make NAME=cpp_chap19_strings MODE=release CPP=true SOURCE_DIR=gen/chap19_strings
@ $(MAKE) -f util/c.make NAME=cpp_chap20_hash MODE=release CPP=true SOURCE_DIR=gen/chap20_hash
@ $(MAKE) -f util/c.make NAME=cpp_chap21_global MODE=release CPP=true SOURCE_DIR=gen/chap21_global
@ $(MAKE) -f util/c.make NAME=cpp_chap22_local MODE=release CPP=true SOURCE_DIR=gen/chap22_local
@ $(MAKE) -f util/c.make NAME=cpp_chap23_jumping MODE=release CPP=true SOURCE_DIR=gen/chap23_jumping
@ $(MAKE) -f util/c.make NAME=cpp_chap24_calls MODE=release CPP=true SOURCE_DIR=gen/chap24_calls
@ $(MAKE) -f util/c.make NAME=cpp_chap25_closures MODE=release CPP=true SOURCE_DIR=gen/chap25_closures
@ $(MAKE) -f util/c.make NAME=cpp_chap26_garbage MODE=release CPP=true SOURCE_DIR=gen/chap26_garbage
@ $(MAKE) -f util/c.make NAME=cpp_chap27_classes MODE=release CPP=true SOURCE_DIR=gen/chap27_classes
@ $(MAKE) -f util/c.make NAME=cpp_chap28_methods MODE=release CPP=true SOURCE_DIR=gen/chap28_methods
@ $(MAKE) -f util/c.make NAME=cpp_chap29_superclasses MODE=release CPP=true SOURCE_DIR=gen/chap29_superclasses
@ $(MAKE) -f util/c.make NAME=cpp_chap30_optimization MODE=release CPP=true SOURCE_DIR=gen/chap30_optimization
diffs: split_chapters java_chapters
@ mkdir -p build/diffs
@ -diff --recursive --new-file nonexistent/ gen/chap04_scanning/com/craftinginterpreters/ > build/diffs/chap04_scanning.diff
@ -diff --recursive --new-file gen/chap04_scanning/com/craftinginterpreters/ gen/chap05_representing/com/craftinginterpreters/ > build/diffs/chap05_representing.diff
@ -diff --recursive --new-file gen/chap05_representing/com/craftinginterpreters/ gen/chap06_parsing/com/craftinginterpreters/ > build/diffs/chap06_parsing.diff
@ -diff --recursive --new-file gen/chap06_parsing/com/craftinginterpreters/ gen/chap07_evaluating/com/craftinginterpreters/ > build/diffs/chap07_evaluating.diff
@ -diff --recursive --new-file gen/chap07_evaluating/com/craftinginterpreters/ gen/chap08_statements/com/craftinginterpreters/ > build/diffs/chap08_statements.diff
@ -diff --recursive --new-file gen/chap08_statements/com/craftinginterpreters/ gen/chap09_control/com/craftinginterpreters/ > build/diffs/chap09_control.diff
@ -diff --recursive --new-file gen/chap09_control/com/craftinginterpreters/ gen/chap10_functions/com/craftinginterpreters/ > build/diffs/chap10_functions.diff
@ -diff --recursive --new-file gen/chap10_functions/com/craftinginterpreters/ gen/chap11_resolving/com/craftinginterpreters/ > build/diffs/chap11_resolving.diff
@ -diff --recursive --new-file gen/chap11_resolving/com/craftinginterpreters/ gen/chap12_classes/com/craftinginterpreters/ > build/diffs/chap12_classes.diff
@ -diff --recursive --new-file gen/chap12_classes/com/craftinginterpreters/ gen/chap13_inheritance/com/craftinginterpreters/ > build/diffs/chap13_inheritance.diff
@ -diff --new-file nonexistent/ gen/chap14_chunks/ > build/diffs/chap14_chunks.diff
@ -diff --new-file gen/chap14_chunks/ gen/chap15_virtual/ > build/diffs/chap15_virtual.diff
@ -diff --new-file gen/chap15_virtual/ gen/chap16_scanning/ > build/diffs/chap16_scanning.diff
@ -diff --new-file gen/chap16_scanning/ gen/chap17_compiling/ > build/diffs/chap17_compiling.diff
@ -diff --new-file gen/chap17_compiling/ gen/chap18_types/ > build/diffs/chap18_types.diff
@ -diff --new-file gen/chap18_types/ gen/chap19_strings/ > build/diffs/chap19_strings.diff
@ -diff --new-file gen/chap19_strings/ gen/chap20_hash/ > build/diffs/chap20_hash.diff
@ -diff --new-file gen/chap20_hash/ gen/chap21_global/ > build/diffs/chap21_global.diff
@ -diff --new-file gen/chap21_global/ gen/chap22_local/ > build/diffs/chap22_local.diff
@ -diff --new-file gen/chap22_local/ gen/chap23_jumping/ > build/diffs/chap23_jumping.diff
@ -diff --new-file gen/chap23_jumping/ gen/chap24_calls/ > build/diffs/chap24_calls.diff
@ -diff --new-file gen/chap24_calls/ gen/chap25_closures/ > build/diffs/chap25_closures.diff
@ -diff --new-file gen/chap25_closures/ gen/chap26_garbage/ > build/diffs/chap26_garbage.diff
@ -diff --new-file gen/chap26_garbage/ gen/chap27_classes/ > build/diffs/chap27_classes.diff
@ -diff --new-file gen/chap27_classes/ gen/chap28_methods/ > build/diffs/chap28_methods.diff
@ -diff --new-file gen/chap28_methods/ gen/chap29_superclasses/ > build/diffs/chap29_superclasses.diff
@ -diff --new-file gen/chap29_superclasses/ gen/chap30_optimization/ > build/diffs/chap30_optimization.diff
split_chapters:
@ dart tool/bin/split_chapters.dart
compile_snippets:
@ dart tool/bin/compile_snippets.dart
# Generate the XML for importing into InDesign.
xml: $(TOOL_SOURCES)
@ dart --enable-asserts tool/bin/build_xml.dart
.PHONY: book c_chapters clean clox compile_snippets debug default diffs \
get java_chapters jlox serve split_chapters test test_all test_c test_java
================================================
FILE: README.md
================================================
This is the repo used for the in-progress book "[Crafting Interpreters][]". It
contains the Markdown text of the book, full implementations of both
interpreters, as well as the build system to weave the two together into the
final site.
[crafting interpreters]: http://craftinginterpreters.com
If you find an error or have a suggestion, please do file an issue here. Thank
you!
## Contributing
One of the absolute best things about writing a book online and putting it out
there before it's done is that people like you have been kind enough to give me
feedback, point out typos, and find other errors or unclear text.
If you'd like to do that, great! You can just file bugs here on the repo, or
send a pull request if you're so inclined. If you want to send a pull request,
but don't want to get the build system set up to regenerate the HTML too, don't
worry about it. I'll do that when I pull it in.
## Ports and implementations
Another way to get involved is by sharing your own implementation of Lox. Ports
to other languages are particularly useful since not every reader likes Java and
C. Feel free to add your Lox port or implementation to the wiki:
* [Lox implementations][]
[lox implementations]: https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations
## Building Stuff
I am a terribly forgetful, error-prone mammal, so I automated as much as I
could.
### Prerequisites
I develop on an OS X machine, but any POSIX system should work too. With a
little extra effort, you should be able to get this working on Windows as well,
though I can't help you out much.
Most of the work is orchestrated by make. The build scripts, test runner, and
other utilities are all written in [Dart][]. Instructions to install Dart are
[here][install]. Once you have Dart installed and on your path, run:
```sh
$ make get
```
[dart]: https://dart.dev/
[install]: https://dart.dev/get-dart
This downloads all of the packages used by the build and test scripts.
In order to compile the two interpreters, you also need a C compiler on your
path as well as `javac`.
### Building
Once you've got that setup, try:
```sh
$ make
```
If everything is working, that will generate the site for the book as well as
compiling the two interpreters clox and jlox. You can run either interpreter
right from the root of the repo:
```sh
$ ./clox
$ ./jlox
```
### Hacking on the book
The Markdown and snippets of source code are woven together into the final HTML
using a hand-written static site generator that started out as a [single tiny
Python script][py] for [my first book][gpp] and somehow grew into something
approximating a real program.
[py]: https://github.com/munificent/game-programming-patterns/blob/master/script/format.py
[gpp]: http://gameprogrammingpatterns.com/
The generated HTML is committed in the repo under `site/`. It is built from a
combination of Markdown for prose, which lives in `book/`, and snippets of code
that are weaved in from the Java and C implementations in `java/` and `c/`. (All
of those funny looking comments in the source code are how it knows which
snippet goes where.)
The script that does all the magic is `tool/bin/build.dart`. You can run that
directly, or run:
```sh
$ make book
```
That generates the entire site in one batch. If you are incrementally working
on it, you'll want to run the development server:
```sh
$ make serve
```
This runs a little HTTP server on localhost rooted at the `site/` directory.
Any time you request a page, it regenerates any files whose sources have been
changed, including Markdown files, interpreter source files, templates, and
assets. Just let that keep running, edit files locally, and refresh your
browser to see the changes.
### Building the interpreters
You can build each interpreter like so:
```sh
$ make clox
$ make jlox
```
This builds the final version of each interpreter as it appears at the end of
its part in the book.
You can also see what the interpreters look like at the end of each chapter. (I
use this to make sure they are working even in the middle of the book.) This is
driven by a script, `tool/bin/split_chapters.dart` that uses the same comment
markers for the code snippets to determine which chunks of code are present in
each chapter. It takes only the snippets that have been seen by the end of each
chapter and produces a new copy of the source in `gen/`, one directory for each
chapter's code. (These are also an easier way to view the source code since they
have all of the distracting marker comments stripped out.)
Then, each of those can be built separately. Run:
```sh
$ make c_chapters
```
And in the `build/` directory, you'll get an executable for each chapter, like
`chap14_chunks`, etc. Likewise:
```sh
$ make java_chapters
```
This compiles the Java code to classfiles in `build/gen/` in a subdirectory for
each chapter.
## Testing
I have a full Lox test suite that I use to ensure the interpreters in the book
do what they're supposed to do. The test cases live in `test/`. The Dart
program `tool/bin/test.dart` is a test runner that runs each of those test
files on a Lox interpreter, parses the result, and validates that that the test
does what it's expected to do.
There are various interpreters you can run the tests against:
```sh
$ make test # The final versions of clox and jlox.
$ make test_clox # The final version of clox.
$ make test_jlox # The final version of jlox.
$ make test_c # Every chapter's version of clox.
$ make test_java # Every chapter's version of jlox.
$ make test_all # All of the above.
```
### Testing your implementation
You are welcome to use the test suite and the test runner to test your own Lox
implementation. The test runner is at `tool/bin/test.dart` and can be given a
custom interpreter executable to run using `--interpreter`. For example, if you
had an interpreter executable at `my_code/boblox`, you could test it like:
```sh
$ dart tool/bin/test.dart clox --interpreter my_code/boblox
```
You still need to tell it which suite of tests to run because that determines
the test expectations. If your interpreter should behave like jlox, use "jlox"
as the suite name. If it behaves like clox, use "clox". If your interpreter is
only complete up to the end of one of the chapters in the book, you can use
that chapter as the suite, like "chap10_functions". See the Makefile for the
names of all of the chapters.
If your interpreter needs other command line arguments passed to use, pass them
to the test runner using `--arguments` and it will forward to your interpreter.
## Repository Layout
* `asset/` – Sass files and jinja2 templates used to generate the site.
* `book/` - Markdown files for the text of each chapter.
* `build/` - Intermediate files and other build output (except for the site
itself) go here. Not committed to Git.
* `c/` – Source code of clox, the interpreter written in C. Also contains an
XCode project, if that's your thing.
* `gen/` – Java source files generated by GenerateAst.java go here. Not
committed.
* `java/` – Source code of jlox, the interpreter written in Java.
* `note/` – Various research, notes, TODOs, and other miscellanea.
* `note/answers` – Sample answers for the challenges. No cheating!
* `site/` – The final generated site. The contents of this directory directly
mirror craftinginterpreters.com. Most content here is generated by build.py,
but fonts, images, and JS only live here. Everything is committed, even the
generated content.
* `test/` – Test cases for the Lox implementations.
* `tool/` – Dart package containing the build, test, and other scripts.
================================================
FILE: asset/index.scss
================================================
@import 'sass/shared';
@import 'sass/sign-up';
body, h1, h2, h3, h4, p, blockquote, code, ul, ol, dl, dd, img {
margin: 0;
}
body {
background: $dark url('image/background.png') top center / 100% auto no-repeat;
color: #222;
font: normal 16px/24px $serif;
}
a {
color: $primary;
text-decoration: none;
border-bottom: solid 1px transparentize($light, 1.0);
transition: color 0.2s ease,
border-color 0.4s ease;
}
a:hover {
color: $primary;
border-bottom: solid 1px opacify($light, 1.0);
}
article {
margin: 0 auto;
padding: 0 0 12px 0;
max-width: $col * 20;
background: #fff;
}
header {
margin: 0 0 $col 0;
color: $warm-dark;
background: $warm-5;
border-bottom: solid 1px $warm-4;
}
main {
margin: 0 $col;
}
img.header {
display: block;
width: 100%;
}
img.small {
display: none;
}
div.intro {
display: flex;
blockquote {
flex-basis: 40%;
margin: 0 $col 0 0;
font: italic 28px/42px $serif;
}
div.text {
flex-basis: 60%;
margin: 8px 0 24px 0;
}
}
p + p {
margin-top: 24px;
}
.format {
margin: 0 -12px 24px -12px;
padding: 12px 12px 8px 12px;
height: 244px;
box-sizing: border-box;
background: $lighter;
background-size: cover;
background-position: left;
color: #444;
border-radius: 3px;
font: normal 16px/24px $nav;
h3 {
margin: 0;
padding: 0 0 4px 0;
font: 600 16px/24px $nav;
text-transform: uppercase;
letter-spacing: 1px;
}
p {
margin-bottom: 8px;
}
}
.format.print, .format.pdf {
background-position: right;
text-align: right;
}
.format-info {
display: inline-block;
width: $col * 8;
text-align: left;
table {
width: 100%;
border-collapse: collapse;
td + td {
padding-left: 5px;
}
}
}
.format.print { background-image: url("image/format-print.jpg"); }
.format.ebook { background-image: url("image/format-ebook.jpg"); }
.format.pdf { background-image: url("image/format-pdf.jpg"); }
.format.web { background-image: url("image/format-web.jpg"); }
a.action {
display: block;
margin: 0 0 4px 0;
padding: 4px 0;
text-align: center;
border-radius: 3px;
background: $primary;
transition: background-color 0.2s ease,
color 0.2s ease;
font: 400 17px/24px $nav;
color: white;
small {
font-size: 14px;
padding: 4px;
color: hsla(0, 0, 100%, 0.7);
transition: color 0.2s ease;
}
}
a.action:hover {
background-color: hsl(200, 85%, 55%);
small {
color: white;
}
}
h3 {
font: italic 24px/24px $serif;
margin: 12px 0;
}
img.author {
float: left;
width: 240px;
margin: 0 12px 0 -12px;
padding: 12px;
background: $warm-5;
border-radius: 3px;
}
div.author {
vertical-align: top;
margin: 36px 0 0 240px + $col;
}
footer {
position: relative;
border-top: solid 1px $light;
color: $gray-4;
font: 400 15px $nav;
text-align: center;
margin: 12px 0 36px 0;
padding-top: 48px;
a, a:hover {
border: none;
}
}
@media only screen and (max-width: 700px) {
main {
margin: 0 24px;
}
header {
margin-bottom: 24px;
}
img.big {
display: none;
}
img.small {
display: block;
}
div.intro {
display: block;
blockquote {
display: block;
font: italic 24px/36px $serif;
}
div.text {
display: block;
margin: 24px 0 24px 0;
}
}
.format {
margin-bottom: 12px;
height: auto;
background-blend-mode: lighten;
}
.format-info {
display: block;
width: 100%;
}
.format.print { background-color: #a6a29f; }
.format.ebook { background-color: #97a2aa; }
.format.pdf { background-color: #cfccca; }
.format.web { background-color: #d6dbd3; }
img.author {
float: none;
}
div.author {
margin: 0 0 0 0;
}
}
================================================
FILE: asset/mustache/contents-nav.html
================================================
<h2><a href="#top"><small> </small> Table of Contents</a></h2>
<ul>
<li><a href="#welcome"><small>I</small>Welcome</a></li>
<li><a href="#a-tree-walk-interpreter"><small>II</small>A Tree-Walk Interpreter</a></li>
<li><a href="#a-bytecode-virtual-machine"><small>III</small>A Bytecode Virtual Machine</a></li>
<li><a href="#backmatter"><small>❧</small>Backmatter</a></li>
</ul>
{{> prev-next }}
================================================
FILE: asset/mustache/contents-part.html
================================================
<h2><span class="num">{{ number }}.</span><a href="{{ file }}.html" name="{{ file }}">{{ title }}</a></h2>
<ul>
{{# chapters }}
<li><span class="num">{{ number }}.</span><a href="{{ file }}.html">{{ title }}</a>
</li>
{{# design_note }}
<li class="design-note">
<span class="num"> </span><a href="{{ file }}.html#design-note">Design Note: {{{ design_note }}}</a>
</li>
{{/ design_note }}
{{/ chapters }}
</ul>
================================================
FILE: asset/mustache/contents.html
================================================
{{> header }}
<nav class="wide">
<a href="/"><img src="image/logotype.png" title="Crafting Interpreters"></a>
<div class="contents">
{{> contents-nav }}
</div>
</nav>
<nav class="narrow">
<a href="/"><img src="image/logotype.png" title="Crafting Interpreters"></a>
{{# has_prev }}
<a href="{{ prev_file }}.html" title="{{ prev }}" class="prev">←</a>
{{/ has_prev }}
{{# has_next }}
<a href="{{ next_file }}.html" title="{{ next }}" class="next">→</a>
{{/ has_next }}
</nav>
<div class="page">
<div class="nav-wrapper">
<nav class="floating">
<a href="/"><img src="image/logotype.png" title="Crafting Interpreters"></a>
<div class="expandable">
{{> contents-nav }}
</div>
<a id="expand-nav">≡</a>
</nav>
</div>
<article class="contents">
<h1 class="part">{{title}}</h1>
<div class="chapters">
<div class="row">
<div class="first">
<h2><span class="num">❧</span>Frontmatter</h2>
<ul>
<li><span class="num"> </span><a href="dedication.html">Dedication</a></li>
<li><span class="num"> </span><a href="acknowledgements.html">Acknowledgements</a></li>
</ul>
{{# part_1 }}
{{> contents-part }}
{{/ part_1 }}
{{# part_2 }}
{{> contents-part }}
{{/ part_2 }}
</div>
<div class="second">
{{# part_3 }}
{{> contents-part }}
{{/ part_3 }}
<h2><span class="num">❧</span><a href="backmatter.html" name="backmatter">Backmatter</a></h2>
<ul>
<li><span class="num">A1.</span><a href="appendix-i.html">Appendix I: Lox Grammar</a></li>
<li><span class="num">A2.</span><a href="appendix-ii.html">Appendix II: Generated Syntax Tree Classes</a></li>
</ul>
</div>
</div>
</div>
<footer>
<a href="{{ next_file }}.html" class="next">
First {{ next_type }}: “{{ next }}” →
</a>
Handcrafted by Robert Nystrom — <a href="https://github.com/munificent/craftinginterpreters/blob/master/LICENSE" target="_blank">© 2015 – 2020</a>
</footer>
</article>
{{> footer }}
================================================
FILE: asset/mustache/footer.html
================================================
</div>
</body>
</html>
================================================
FILE: asset/mustache/header.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>{{title}} · Crafting Interpreters</title>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="stylesheet" type="text/css" href="style.css" />
<!-- Oh, God, Source Code Pro is so beautiful it makes me want to cry. -->
<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400|Source+Sans+Pro:300,400,600' rel='stylesheet' type='text/css'>
<link rel="icon" type="image/png" href="image/favicon.png" />
<script src="jquery-3.4.1.min.js"></script>
<script src="script.js"></script>
<!-- Google analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-42804721-2', 'auto');
ga('send', 'pageview');
</script>
</head>
<body id="top">
<!-- <div class="scrim"></div> -->
================================================
FILE: asset/mustache/in_design.html
================================================
<chapter>
<chapter-number>{{ number }}</chapter-number>
<title>{{ title }}</title>
<part>{{ part }}</part>
{{{ body }}}
</chapter>
================================================
FILE: asset/mustache/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Crafting Interpreters</title>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="stylesheet" type="text/css" href="index.css" />
<!-- Oh, God, Source Code Pro is so beautiful it makes me want to cry. -->
<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400|Source+Sans+Pro:300,400,600' rel='stylesheet' type='text/css'>
<link rel="icon" type="image/png" href="image/favicon.png" />
<!-- Google analytics -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-42804721-2', 'auto');
ga('send', 'pageview');
</script>
</head>
<body>
<article>
<header>
<a href="dedication.html"><img class="header big" src="image/header.png" alt="Crafting Interpreters by Robert Nystrom" /><img class="header small" src="image/header-small.png" alt="Crafting Interpreters by Robert Nystrom" /></a>
</header>
<main>
<div class="intro">
<blockquote><p>Ever wanted to make your own programming language or wondered how
they are designed and built?</p><p>If so, this book is for you.</p></blockquote>
<div class="text">
<p><em>Crafting Interpreters</em> contains everything you need to implement a
full-featured, efficient scripting language. You’ll learn both high-level
concepts around parsing and semantics and gritty details like bytecode
representation and garbage collection. Your brain will light up with new ideas,
and your hands will get dirty and calloused. It’s a blast.</p>
<p>Starting from <code>main()</code>, you build a language that features rich
syntax, dynamic typing, garbage collection, lexical scope, first-class
functions, closures, classes, and inheritance. All packed into a few thousand
lines of clean, fast code that you thoroughly understand because you write each
one yourself.</p>
<p>The book is available in four delectable formats:</p>
</div>
</div>
<div class="format print">
<div class="format-info">
<h3>Print</h3>
<p>640 pages of beautiful typography and high resolution hand-drawn
illustrations. Each page lovingly typeset by the author. The premiere reading
experience.</p>
<table>
<tr>
<td>
<a class="action" href="https://www.amazon.com/dp/0990582930" target="_blank">Amazon<small>.com</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.ca/dp/0990582930" target="_blank"><small>.ca</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.co.uk/dp/0990582930" target="_blank"><small>.uk</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.com.au/dp/0990582930" target="_blank"><small>.au</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.de/dp/0990582930" target="_blank"><small>.de</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.fr/dp/0990582930" target="_blank"><small>.fr</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.es/dp/0990582930" target="_blank"><small>.es</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.it/dp/0990582930" target="_blank"><small>.it</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.co.jp/dp/0990582930" target="_blank"><small>.jp</small></a>
</td>
</tr>
</table>
<table>
<tr>
<td>
<a class="action" href="https://www.barnesandnoble.com/w/crafting-interpreters-robert-nystrom/1139915245?ean=9780990582939" target="_blank">Barnes and Noble</a>
</td>
<td>
<a class="action" href="https://www.bookdepository.com/Crafting-Interpreters-Robert-Nystrom/9780990582939" target="_blank">Book Depository</a>
</td>
</tr>
</table>
<a class="action" href="/sample.pdf" target="_blank">Download Sample <small>PDF</small></a>
</div>
</div>
<div class="format ebook">
<div class="format-info">
<h3>eBook</h3>
<p>Carefully tuned CSS fits itself to your ebook reader and screen size.
Full-color syntax highlighting and live hyperlinks. Like Alan Kay's Dynabook
but real.</p>
<table>
<tr>
<td>
<a class="action" href="https://www.amazon.com/dp/B09BCCVLCL" target="_blank">Kindle <small class="hide-small"><span class="hide-medium">Amazon</span>.com</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.co.uk/dp/B09BCCVLCL" target="_blank"><small>.uk</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.ca/dp/B09BCCVLCL" target="_blank"><small>.ca</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.com.au/dp/B09BCCVLCL" target="_blank"><small>.au</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.de/dp/B09BCCVLCL" target="_blank"><small>.de</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.in/dp/B09BCCVLCL" target="_blank"><small>.in</small></a>
</td>
</tr>
</table>
<table>
<tr>
<td>
<a class="action" href="https://www.amazon.fr/dp/B09BCCVLCL" target="_blank"><small>.fr</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.es/dp/B09BCCVLCL" target="_blank"><small>.es</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.it/dp/B09BCCVLCL" target="_blank"><small>.it</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.co.jp/dp/B09BCCVLCL" target="_blank"><small>.jp</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.com.br/dp/B09BCCVLCL" target="_blank"><small>.br</small></a>
</td>
<td>
<a class="action" href="https://www.amazon.com.mx/dp/B09BCCVLCL" target="_blank"><small>.mx</small></a>
</td>
<td>
<a class="action" href="https://books.apple.com/us/book/crafting-interpreters/id1578795812" target="_blank">Apple Books</a>
</td>
</tr>
</table>
<table>
<tr>
<td>
<a class="action" href="https://play.google.com/store/books/details?id=q0c6EAAAQBAJ" target="_blank">Play Books <small class="hide-small">Google</small></a>
</td>
<td>
<a class="action" href="https://www.barnesandnoble.com/w/crafting-interpreters-robert-nystrom/1139915245?ean=2940164977092" target="_blank">Nook <small class="hide-small">B&N</small></a>
</td>
<td>
<a class="action" href="https://www.smashwords.com/books/view/1096463" target="_blank">EPUB <small class="hide-small">Smashwords</small></a>
</td>
</tr>
</table>
</div>
</div>
<div class="format pdf">
<div class="format-info">
<h3>PDF</h3>
<p>Perfectly mirrors the hand-crafted typesetting and sharp illustrations of
the print book, but much easier to carry around.</p>
<a class="action" href="https://payhip.com/b/F0zkr" target="_blank">Buy from Payhip</a>
<a class="action" href="/sample.pdf" target="_blank">Download Free Sample</a>
</div>
</div>
<div class="format web">
<div class="format-info">
<h3>Web</h3>
<p>Meticulous responsive design looks great from your desktop down to your
phone. Every chapter, aside, and illustration is there. Read the whole book
for free. Really.</p>
<a class="action" href="contents.html">Read Now</a>
</div>
</div>
<img src="image/dogshot.jpg" class="author" />
<div class="author">
<h3>About Robert Nystrom</h3>
<p>I got bitten by the language bug years ago while on paternity leave between
midnight feedings. I cobbled together a <a href="http://wren.io/"
target="_blank">number</a> <a href="http://magpie-lang.org/"
target="_blank">of</a> <a href="http://finch.stuffwithstuff.com/"
target="_blank">hobby</a> <a href="https://github.com/munificent/vigil"
target="_blank">languages</a> before worming my way into an honest-to-God,
full-time programming language job. Today, I work at Google on the <a
href="http://dart.dev/" target="_blank">Dart language</a>.</p>
<p>Before I fell in love with languages, I developed games at Electronic Arts
for eight years. I wrote the best-selling book <em><a
href="http://gameprogrammingpatterns.com/" target="_blank">Game Programming
Patterns</a></em> based on what I learned there. You can read that book for free
too.</p>
<p>If you want more, you can find me on Twitter (<a
href="https://twitter.com/intent/user?screen_name=munificentbob"
target="_blank"><code>@munificentbob</code></a>), email me at <code>bob</code>
at this site's domain (though I am slow to respond), read <a
href="http://journal.stuffwithstuff.com/" target="_blank">my blog</a>, or join
my low frequency mailing list:</p>
<div class="sign-up">
<!-- Begin MailChimp Signup Form -->
<div id="mc_embed_signup">
<form action="//gameprogrammingpatterns.us7.list-manage.com/subscribe/post?u=0952ca43ed2536d6717766b88&id=6e96334109" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
<input type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="Your email address" required>
<!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups -->
<div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_0952ca43ed2536d6717766b88_6e96334109" tabindex="-1" value=""></div>
<input type="submit" value="Sign me up!" name="subscribe" id="mc-embedded-subscribe" class="button">
</form>
</div>
<!--End mc_embed_signup -->
</div>
</div>
<footer>
Handcrafted by Robert Nystrom — <a href="https://github.com/munificent/craftinginterpreters/blob/master/LICENSE" target="_blank">© 2015 – 2021</a>
</footer>
</main>
</article>
</body>
</html>
================================================
FILE: asset/mustache/nav.html
================================================
{{# is_chapter }}
<h3><a href="#top">{{ title }}<small>{{ number }}</small></a></h3>
<ul>
{{# sections }}
<li><a href="#{{ anchor }}"><small>{{ number }}.{{ index }}</small> {{ name }}</a></li>
{{/ sections }}
{{# has_challenges_or_design_note }}
<li class="divider"></li>
{{/ has_challenges_or_design_note }}
{{# has_challenges }}
<li class="end-part"><a href="#challenges">Challenges</a></li>
{{/ has_challenges }}
{{# has_design_note }}
<li class="end-part"><a href="#design-note"><small>note</small>{{ design_note }}</a></li>
{{/ has_design_note }}
</ul>
{{/ is_chapter }}
{{# is_part }}
<h2><small>{{ number }}</small>{{ title }}</h2>
<ul>
{{# chapters }}
<li><a href="{{ file }}.html"><small>{{ number }}</small>{{ title }}</a></li>
{{/ chapters }}
</ul>
{{/ is_part }}
{{# is_frontmatter }}
<h2><small>{{ number }}</small>{{ title }}</h2>
<hr>
{{/ is_frontmatter }}
{{> prev-next }}
================================================
FILE: asset/mustache/page.html
================================================
{{> header }}
<nav class="wide">
<a href="/"><img src="image/logotype.png" title="Crafting Interpreters"></a>
<div class="contents">
{{> nav }} </div>
</nav>
<nav class="narrow">
<a href="/"><img src="image/logotype.png" title="Crafting Interpreters"></a>
{{# has_prev }}
<a href="{{ prev_file }}.html" title="{{ prev }}" class="prev">←</a>
{{/ has_prev }}
{{# has_next }}
<a href="{{ next_file }}.html" title="{{ next }}" class="next">→</a>
{{/ has_next }}
</nav>
<div class="page">
<div class="nav-wrapper">
<nav class="floating">
<a href="/"><img src="image/logotype.png" title="Crafting Interpreters"></a>
<div class="expandable">
{{> nav }}
</div>
<a id="expand-nav">≡</a>
</nav>
</div>
<article class="chapter">
{{# has_number }}
<div class="number">{{ number }}</div>
{{/ has_number }}
{{# is_chapter }}
<h1>{{ title }}</h1>
{{/ is_chapter }}
{{^ is_chapter }}
<h1 class="part">{{ title }}</h1>
{{/ is_chapter }}
{{{ body }}}
<footer>
{{# has_next }}
<a href="{{ next_file }}.html" class="next">
Next {{ next_type }}: “{{ next }}” →
</a>
{{/ has_next }}
Handcrafted by Robert Nystrom — <a href="https://github.com/munificent/craftinginterpreters/blob/master/LICENSE" target="_blank">© 2015 – 2021</a>
</footer>
</article>
{{> footer }}
================================================
FILE: asset/mustache/prev-next.html
================================================
<div class="prev-next">
{{# has_prev }}
<a href="{{ prev_file }}.html" title="{{ prev }}" class="left">← Previous</a>
{{/ has_prev }}
{{# has_up }}
<a href="{{ up_file }}.html" title="{{ up }}">↑ Up</a>
{{/ has_up }}
{{# has_next }}
<a href="{{ next_file }}.html" title="{{ next }}" class="right">Next →</a>
{{/ has_next }}
</div>
================================================
FILE: asset/sass/chapter.scss
================================================
article.chapter {
h2 {
font: 600 30px/24px $serif;
margin: 69px 0 0 0;
padding-bottom: 3px;
small {
font: 800 22px/24px $serif;
float: right;
}
}
h3 {
font: italic 24px/24px $serif;
margin: 71px 0 0 0;
padding-bottom: 1px;
small {
font: 600 16px/24px $serif;
float: right;
}
}
h2 a, h3 a {
color: #222;
border-bottom: none;
}
h2 a:hover, h3 a:hover {
border-bottom: none;
color: inherit;
}
h2 a::before, h3 a::before {
position: absolute;
left: -$col;
width: $col;
content: "\000A7";
color: #fff;
transition: color 0.2s ease;
text-align: center;
}
h2 a:hover::before, h3 a:hover::before {
color: #ddd;
}
.challenges, .design-note {
border-radius: 3px;
padding: 12px;
margin: -2px -12px 26px -12px;
font: normal 16px/24px $nav;
color: #444;
h2 {
margin: 0 0 -12px 0;
padding: 0;
font: 600 16px/24px $nav;
text-transform: uppercase;
letter-spacing: 1px;
}
h2 a {
color: inherit;
}
h2 a::before {
content: none;
}
ol {
padding: 0 0 0 18px;
li {
padding: 0 0 0 6px;
font-weight: 600;
p {
font-weight: 400;
}
}
}
pre {
margin: 0;
}
// Chapter 23 has some blockquotes in the design note.
> blockquote {
p {
margin: 0 24px;
font: italic 16px/24px $nav;
color: #444;
}
&::before, &::after {
content: none;
}
}
// Use the regular code colors in asides, and not the tinted versions used
// inside the challenge or design notes boxes themselves.
aside {
code, .codehilite {
color: $warm-dark;
background: $warm-light;
}
}
// Remove the extra padding at the bottom of the box.
*:last-child {
margin-bottom: 0;
}
}
.challenges .codehilite,
.design-note .codehilite {
margin: -12px 0 -12px 0;
}
.challenges {
background: $lighter;
code, .codehilite {
background: hsl(195, 30%, 92%);
}
}
.design-note {
background: hsl(80, 30%, 96%);
code, .codehilite {
background: hsl(80, 20%, 93%);
}
}
table {
width: 100%;
border-collapse: collapse;
thead {
font: 700 15px $serif;
}
td {
border-bottom: solid 1px $light;
line-height: 22px;
padding: 3px 0 0 0;
margin: 0;
}
td + td {
padding-left: 12px;
}
}
}
// Tablets and mobile go single column.
@media only screen and (max-width: $col * 20) {
article.chapter {
// Now that the asides are inline, make them match the challenge/design-note
// colors and font.
.challenges, .design-note {
aside {
font: normal 15px/24px $nav;
padding-bottom: 4px;
}
}
.challenges {
aside {
code, .codehilite {
background: hsl(195, 30%, 92%);
}
}
}
.design-note {
aside {
code, .codehilite {
background: hsl(80, 20%, 93%);
}
}
}
}
}
// Then bring the margins in some.
// The cut-off sizes here are based on trying to get 72 columns of code to fit.
@media only screen and (max-width: 630px) {
article.chapter {
h2 a::before, h3 a::before {
left: -($col / 2);
width: $col / 2;
}
}
}
// Finally start shrinking text.
@media only screen and (max-width: 580px) {
article.chapter {
h2 {
margin-top: 64px;
padding-bottom: 2px;
font-size: 22px;
line-height: 22px;
}
h3 {
margin-top: 64px;
padding-bottom: 0;
font-size: 20px;
}
.challenges, .design-note {
padding: 11px 11px 8px 11px;
margin: 25px 0 0 0;
font-size: 15px;
line-height: 22px;
code, .codehilite {
font-size: 14px;
}
h2 {
padding: 5px 0 4px 6px;
font-size: 17px;
line-height: 22px;
}
aside {
line-height: 22px;
}
}
}
}
================================================
FILE: asset/sass/contents.scss
================================================
article.contents {
h2 {
margin: 22px 0 6px 0;
font: 600 normal 18px/24px $nav;
text-transform: uppercase;
letter-spacing: 1px;
.num {
display: inline-block;
width: 36px;
}
}
ul {
margin: -12px 0 0 0;
padding: 6px 0 14px 0;
}
li {
padding: 12px 0 0 36px;
font: normal 16px/24px $nav;
color: $gray-4;
list-style-type: none;
.num {
display: inline-block;
letter-spacing: 1px;
width: 36px;
}
a {
font: 600 17px/24px $nav;
}
}
li.design-note {
padding-top: 0;
a {
font: 400 16px/23px $nav;
}
}
// Format the chapter list in two columns.
.chapters {
display: table;
width: $col * 18;
}
.row {
display: table-row;
}
.first, .second {
display: table-cell;
vertical-align: top;
}
.second {
padding-left: $col;
}
footer {
width: $col * 18;
}
}
// Go single-column with the chapter list.
@media only screen and (max-width: 1344px) {
article.contents {
.chapters, .row, .first, .second {
display: block;
width: auto;
}
.second {
padding-left: 0;
}
footer {
width: inherit;
}
}
}
// Then bring the margins in some.
@media only screen and (max-width: 630px) {
article.contents {
h2 .num, li .num {
width: 28px;
}
ol, ul {
margin-left: 0;
}
li {
padding-left: 0;
}
}
}
// Finally start shrinking text.
@media only screen and (max-width: 580px) {
article.contents {
h2 {
margin: 19px 0 6px 0;
font-size: 17px;
line-height: 22px;
}
h3 {
padding: 1px 0 2px 0;
font-size: 17px;
line-height: 22px;
}
p {
font-size: 15px;
line-height: 22px;
}
ol, ul {
padding-bottom: 8px;
}
li {
font-size: 14px;
line-height: 22px;
padding: 4px 0 3px 0;
}
}
}
================================================
FILE: asset/sass/print.scss
================================================
@import 'shared';
@media print {
// Pure black text.
body, a, code {
color: #000 !important;
background: none !important;
}
// Hide non-content stuff.
nav, .sign-up {
display: none;
}
// Get rid of extra margins. The page margin will handle this.
.page {
margin: 0 !important;
}
// Tweak how code is formatted since we don't want to use a background color.
.codehilite {
pre {
color: #000 !important;
}
margin: 0 !important;
// Borders above and below and no background.
background: none !important;
border-radius: 0 !important;
border-left: solid 1px $warm-4;
border-right: solid 1px $warm-4;
// Show thicker borders on the left and right instead of a background.
.insert {
border-left: solid 3px $warm-4 !important;
border-right: solid 3px $warm-4 !important;
background: none !important;
}
.delete {
-webkit-print-color-adjust: exact;
color-adjust: exact;
}
// Browsers don't honor the specific authored colors when printing if the
// color is too close the background. Tell the browser not to do that.
.insert-before span, .insert-after span {
-webkit-print-color-adjust: exact;
color-adjust: exact;
}
}
}
================================================
FILE: asset/sass/shared.scss
================================================
// Font stacks.
$serif: "Crimson", Georgia, serif;
$mono: "Source Code Pro", Menlo, Consolas, Monaco, monospace;
$nav: "Source Sans Pro", sans-serif;
// The main intense primary accent color.
$primary: hsl(200, 80%, 40%);
$primary-dark: hsl(200, 100%, 20%);
$primary-light: hsl(200, 70%, 60%);
// A ramp of washed out blues from dark to light.
$dark: hsl(215, 20%, 20%);
$gray-1: hsl(212, 23%, 30%);
$gray-2: hsl(209, 26%, 40%);
$gray-3: hsl(206, 30%, 50%);
$gray-4: hsl(203, 30%, 60%);
$light: hsl(195, 30%, 90%);
$lighter: hsl(195, 35%, 95%);
// An opposing warm light color (code background).
$warm-dark: hsl(40, 0%, 35%);
$warm-light: hsl(40, 30%, 97%);
$warm-1: mix($warm-light, $warm-dark, 15%);
$warm-2: mix($warm-light, $warm-dark, 40%);
$warm-3: mix($warm-light, $warm-dark, 60%);
$warm-4: mix($warm-light, $warm-dark, 80%);
$warm-5: hsl(40, 20%, 95%);
// The full-size design is 28 units wide, in three columns:
// [][][][][][][][][][][][][][][][][][][][][][][][][][][][]
// ( 5 ) ( 12 ) ( 6 )
// They are asymmetric because the left column has a dark background, which
// requires a double margin.
$col: 48px;
@font-face {
font-family: 'Crimson';
src: url('font/crimson-roman.woff') format('woff');
}
@font-face {
font-family: 'Crimson';
src: url('font/crimson-italic.woff') format('woff');
font-style: italic;
}
@font-face {
font-family: 'Crimson';
src: url('font/crimson-semibold.woff') format('woff');
font-weight: 600;
}
@font-face {
font-family: 'Crimson';
src: url('font/crimson-semibolditalic.woff') format('woff');
font-style: italic;
font-weight: 600;
}
@font-face {
font-family: 'Crimson';
src: url('font/crimson-bold.woff') format('woff');
font-weight: bold;
}
@font-face {
font-family: 'Crimson';
src: url('font/crimson-bolditalic.woff') format('woff');
font-style: italic;
font-weight: bold;
}
// Reset stuff.
body, h1, h2, h3, h4, p, blockquote, code, ul, ol, dl, dd, img {
margin: 0;
}
img {
outline: none;
}
img.arrow {
width: auto;
height: 11px;
}
img.dot {
width: auto;
height: 18px;
vertical-align: text-bottom;
}
// Basic styles.
body {
color: #222;
font: normal 16px/24px $serif;
}
================================================
FILE: asset/sass/sign-up.scss
================================================
.sign-up {
padding: 12px;
margin: 24px 0 24px 0;
background: hsl(40, 80%, 95%);
color: hsl(40, 50%, 50%);
border-radius: 3px;
form {
display: flex;
}
input {
padding: 4px;
font: 16px $nav;
outline: none;
border-radius: 3px;
border: solid 2px hsl(40, 100%, 75%);
color: hsl(40, 70%, 30%);
height: 32px;
}
input.email {
display: block;
box-sizing: border-box;
width: 100%;
}
input.button {
margin-left: 8px;
padding: 4px 8px;
font: 600 13px $nav;
text-transform: uppercase;
letter-spacing: 1px;
background: hsl(40, 100%, 60%);
border: none;
transition: background-color 0.2s ease;
}
input.button:hover {
background: hsl(40, 100%, 75%);
}
input:focus {
border-color: hsl(40, 100%, 50%);
}
}
================================================
FILE: asset/style.scss
================================================
@import 'sass/shared';
@import 'sass/chapter';
@import 'sass/contents';
@import 'sass/sign-up';
@import 'sass/print';
// Make sure we don't split on the thin spaces around an em dash.
.emdash {
white-space: nowrap;
}
.scrim {
position: absolute;
width: 100%;
height: 10000px;
z-index: 4;
// background: url('columns.png');
background: url('rows.png');
}
// Used for drawing the bitwise operators "AND", "OR", and "NOT" in small caps.
.small-caps {
font-weight: 600;
font-size: 13px;
}
a {
color: $primary;
text-decoration: none;
border-bottom: solid 1px transparentize($light, 1.0);
transition: color 0.2s ease,
border-color 0.4s ease;
}
a:hover {
color: $primary;
border-bottom: solid 1px opacify($light, 1.0);
}
nav {
font: 300 15px/24px $nav;
background: $dark;
color: $gray-2;
a, h2 a {
color: $gray-4;
text-decoration: none;
border-bottom: none;
}
a:hover {
color: $light;
text-decoration: none;
border-bottom: none;
}
img {
box-sizing: border-box;
width: 100%;
padding: 55px $col 23px $col;
}
h2 {
font: 400 16px/24px $nav;
text-transform: uppercase;
letter-spacing: 1px;
color: $gray-4;
}
h3 {
font: 400 18px/24px $nav;
color: $gray-4;
}
h2 small, h3 small {
float: right;
font-size: 16px;
color: $gray-2;
}
ol, ul {
margin: 6px 0 3px 0;
padding: 6px 0 4px 24px;
border-top: solid 1px $gray-1;
border-bottom: solid 1px $gray-1;
}
ul {
list-style-type: none;
padding-left: 0;
}
hr {
border: none;
border-top: solid 1px $gray-1;
margin: 6px 0 0 0;
padding: 0 0 3px 0;
}
li small {
float: right;
font-size: 14px;
color: $gray-2;
}
li.divider {
margin: 5px 0 7px 0;
border-top: solid 1px $gray-1;
}
li.end-part {
font-size: 12px;
font-weight: 400;
text-transform: uppercase;
letter-spacing: 1px;
small {
font-weight: 300;
text-transform: none;
letter-spacing: 0;
}
}
.prev-next {
padding-top: 7px;
font: 400 12px/18px $nav;
text-align: center;
text-transform: uppercase;
letter-spacing: 1px;
}
}
nav.wide {
position: fixed;
width: $col * 7;
height: 100%;
.contents {
margin: 24px $col;
}
}
// This is needed to make the nav fixed (not scrolling with the content) but
// still positioned horizontally based on the page.
// See: http://stackoverflow.com/a/11833892/9457
.nav-wrapper {
position: absolute;
right: $col * 6;
}
// For medium-sized screens, the navigation floats over the same column as the
// asides.
nav.floating {
// Only shown on narrower screens.
display: none;
z-index: 2;
position: absolute;
width: $col * 6;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
#expand-nav {
padding: 0 0 4px 0;
display: block;
font-size: 20px;
text-align: center;
color: $gray-2;
cursor: pointer;
transition: padding 0.2s ease,
margin 0.2s ease,
color 0.2s ease;
}
#expand-nav, #expand-nav:hover {
border-bottom: none;
}
#expand-nav:hover {
color: $light;
}
.expandable {
overflow: hidden;
padding: 0 12px;
// Using max-height instead of height to allow the list to navigation to
// automatically choose its height based on the size of the list while
// still transitioning.
// See: http://stackoverflow.com/a/8331169/9457
max-height: 0;
transition: margin 0.2s ease,
max-height 1.0s ease;
.prev-next {
padding-bottom: 6px;
}
}
.expandable.shown {
// This should be as small as possible while still being large enough for
// the worst case chapter.
max-height: 550px;
}
img {
padding: 110px $col/2 23px $col/2;
}
}
nav.floating.pinned {
position: fixed;
top: -85px;
.expandable {
margin-top: -13px;
}
#expand-nav {
margin-top: -14px;
}
}
nav.narrow {
display: none;
text-align: center;
img {
box-sizing: content-box;
padding: 11px 0 3px 0;
width: auto;
height: 27px;
}
.prev, .next {
font-size: 32px;
position: absolute;
top: 12px;
padding: 0 $col;
}
.prev {
left: 0;
}
.next {
right: 0;
}
}
.left {
float: left;
}
.right {
float: right;
}
.page {
position: relative;
width: $col * 19;
margin: 0 auto 0 $col * 8;
}
// Make em dashes look pretty. Goals:
//
// - Add a tiny bit of space on either side. Completely unspaced em dashes
// look too tight to me.
// - Allow an em dash at the end of a line.
// - Prevent an em dash at the beginning of a line.
//
// Wrapping each `—` in a span with this class and consuming the
// preceding whitespace seems to accomplish that.
.em {
padding: 0 .1em;
white-space: nowrap;
}
// Make ellipses follow Chicago style. The `…` entity puts a tiny amount
// of space between each `.`, but not as much as Chicago style specificies. It
// also doesn't put any space before. Instead, the build system writes a span
// of this class with thin-space separated dots. This class here ensures there
// is no splitting between the dots.
.ellipse {
white-space: nowrap;
}
code {
font: normal 16px $mono;
color: $warm-1;
white-space: nowrap;
padding: 2px;
}
strong code {
font-weight: bold;
color: inherit;
}
a code {
color: $primary;
}
.codehilite {
color: $warm-dark;
background: $warm-light;
border-radius: 3px;
padding: 12px;
margin: -12px;
}
pre {
font: normal 13px/20px $mono;
margin: 0;
padding: 0;
// If the code doesn't fit, just force it to wrap instead of cropping it. It
// doesn't look great, but it ensures the code is visible and can be correctly
// copy-pasted.
white-space: pre-wrap;
overflow-wrap: anywhere;
}
// If the chapter ends with code, don't overlap the challenges box.
div.codehilite + div.challenges {
margin-top: $col / 2;
}
article {
position: relative;
width: $col * 12;
h1 {
position: relative;
font: 48px/48px $serif;
padding: 109px 0 19px 0;
z-index: 2;
}
h1.part {
font: 600 36px/48px $nav;
padding: 108px 0 20px 0;
text-transform: uppercase;
letter-spacing: 1px;
}
.number {
position: absolute;
top: 50px;
left: $col * 13;
z-index: 1;
font: 300 96px $nav;
color: $light;
}
p {
margin: 24px 0;
}
ol, ul {
margin: 24px 0;
padding: 0 0 0 24px;
}
img {
max-width: 100%;
}
img.wide {
max-width: none;
width: $col * 19;
}
}
aside {
position: absolute;
right: -$col * 7;
width: $col * 6;
font: normal 14px/20px $serif;
border-top: solid 1px $light;
p {
margin: 20px 0;
}
p:first-child,
img:first-child {
margin-top: 4px;
}
p:last-child {
margin-bottom: 4px;
}
code {
font-size: 14px;
border-radius: 2px;
padding: 1px 2px;
}
.codehilite {
padding: 6px;
margin: -12px 0;
}
.codehilite:last-child {
margin-bottom: 4px;
}
img.above {
position: absolute;
bottom: 100%;
margin-bottom: 16px;
}
blockquote {
margin: 20px 0;
&::before, &::after {
content: none;
}
p {
margin: 0 12px;
font: italic 15px/20px $serif;
color: inherit;
}
}
}
// Sometimes there isn't room to hang the aside *down* next to the content it's
// annotating, so support asides where the bottom is aligned with the content.
aside.bottom {
border-top: none;
border-bottom: solid 1px $light;
}
blockquote {
position: relative;
margin: 29px 0 31px 0;
&::before, &::after {
position: absolute;
top: -20px;
font: italic 72px $serif;
color: $light;
}
&::before {
content: "\201c";
left: -7px;
}
&::after {
content: "\201d";
right: 8px;
}
p {
margin: 0 $col;
font: italic 24px/36px $serif;
color: $gray-3;
em {
font-style: normal;
}
}
cite {
display: block;
text-align: right;
color: $gray-4;
font-style: normal;
font-size: 18px;
&::before {
content: "\2014\00a0";
color: $light;
}
em {
font-style: italic;
}
}
}
footer {
position: relative;
border-top: solid 1px $light;
color: $gray-4;
font: 400 15px $nav;
text-align: center;
margin: 48px 0;
padding-top: 48px;
a, a:hover {
border: none;
}
.next {
position: absolute;
right: 0;
top: -13px;
padding-left: 4px;
background: #fff;
font: 400 17px/24px $nav;
text-transform: uppercase;
letter-spacing: 1px;
}
.next:hover {
color: $primary-dark;
border: none;
}
}
.dedication {
margin: 96px 0 128px 0;
text-align: center;
img {
width: 50%;
}
}
.source-file, .source-file-narrow {
font: normal 11px/16px $mono;
color: $warm-3;
em {
color: $warm-2;
font-style: normal;
}
}
.source-file-narrow {
// Don't show unless in single-column.
display: none;
margin: 0px -12px 0 0;
padding: 14px 0 0 0;
text-align: right;
}
.source-file {
position: absolute;
right: -$col * 7;
width: $col * 6;
padding: 2px 0 0 0;
&::before {
content: "<<";
color: $warm-4;
position: absolute;
left: -($col - 12px);
width: $col - 12px;
text-align: center;
}
}
// Syntax highlighting.
.codehilite {
pre { color: mix($warm-light, $warm-dark, 20%); }
.k { color: hsl(200, 100%, 45%); } // Keyword.
.n { color: hsl( 20, 70%, 55%); } // Number.
.s { color: hsl( 40, 70%, 45%); } // String.
.e { color: hsl( 45, 80%, 55%); } // String escape.
.c { color: mix($warm-light, $warm-dark, 50%); } // Comment.
.a { color: hsl(270, 50%, 60%); } // Preprocessor, annotation.
.i { color: hsl(200, 70%, 35%); } // Identifier.
.t { color: hsl(185, 100%, 35%); } // Type name.
.insert {
margin: -2px -12px;
padding: 2px 10px;
border-left: solid 2px $warm-4;
border-right: solid 2px $warm-4;
background: $warm-5;
}
.delete {
margin: -2px -12px;
padding: 2px 10px;
border-left: solid 2px $warm-4;
border-right: solid 2px $warm-4;
// Hatched lines.
background: repeating-linear-gradient(
-45deg,
$warm-4,
$warm-4 1px,
rgba(0, 0, 0, 0.0) 1px,
rgba(0, 0, 0, 0.0) 6px
);
span {
color: $warm-3;
}
}
// Snippets of code before and after real code to show where to insert it.
.insert-before, .insert-after {
color: $warm-3;
}
// When we just add a trailing comma to a line, highlight it specially.
.insert-before .insert-comma {
margin: -2px -1px;
padding: 2px 1px;
border-radius: 2px;
background: $warm-5;
color: $warm-dark;
}
}
// On a not-entirely-large screen, don't show the fixed nav on the left.
@media only screen and (max-width: 1344px) {
nav.wide { display: none; }
nav.floating { display: block; }
body {
margin: 0 24px;
}
.page {
position: relative;
width: inherit;
max-width: $col * 19;
margin: 0 auto;
}
article {
width: inherit;
margin-right: $col * 7;
// Move the number over to not be hidden behind the navigation.
.number {
top: 73px;
left: inherit;
right: 0;
font-size: 72px;
}
h1 {
padding: 110px 0 18px 0;
font-size: 44px;
}
}
}
// Tablets and mobile go single column.
@media only screen and (max-width: $col * 20) {
body {
margin: 0;
}
nav.floating {
display: none;
}
nav.narrow {
display: block;
}
.page {
margin: 0 $col;
width: inherit;
}
article {
margin: 0;
// Size wide images to fit inside the column again.
img.wide {
width: inherit;
max-width: 100%;
}
}
aside {
position: inherit;
right: inherit;
width: inherit;
border-bottom: solid 1px $light;
p:first-child {
margin-top: 8px;
}
p:last-child {
margin-bottom: 8px;
}
// If an aside ends with code (like in "classes.html"), then make sure we
// give it some margin.
div.codehilite:last-child {
margin-bottom: 12px;
}
// Make sure aside images don't get too big when the asides are inlined
// in single column mode.
img {
display: block;
max-width: $col * 6;
margin: 0 auto;
}
img.above {
position: relative;
}
}
// If aside is right before a code block (when the asides are inline), make
// sure they don't overlap.
aside + div.codehilite {
margin-top: 12px;
}
div.codehilite + aside {
margin-top: 24px;
}
.source-file {
display: none;
}
.source-file-narrow {
display: block;
}
}
// Then bring the margins in some.
// The cut-off sizes here are based on trying to get 72 columns of code to fit.
@media only screen and (max-width: 630px) {
.page {
margin: 0 $col / 2;
width: inherit;
}
nav.narrow {
.prev, .next {
padding: 0 $col / 2;
}
}
}
// Finally, shrink the grid to 22px and shrink the text.
@media only screen and (max-width: 580px) {
body {
font-size: 15px;
line-height: 22px;
}
.small-caps {
font-size: 12px;
}
.scrim {
background: url('rows-22.png');
}
nav.narrow {
img {
padding: 9px 0 1px 0;
height: 27px;
}
.prev, .next {
top: 11px;
}
}
article {
h1 {
font-size: 36px;
padding: 100px 0 14px 0;
}
h1.part {
font-size: 30px;
padding: 97px 0 17px 0;
}
.number {
top: 61px;
font-size: 72px;
}
p {
margin: 22px 0;
}
ol, ul {
margin: 22px 0;
padding: 0 0 0 22px;
}
}
blockquote {
margin: 27px 0 28px 0;
&::before, &::after {
top: -17px;
font-size: 52px;
}
p {
margin: 0 22px;
font-size: 20px;
line-height: 33px;
}
}
footer {
.next {
font-size: 15px;
}
}
}
================================================
FILE: book/a-bytecode-virtual-machine.md
================================================
Our Java interpreter, jlox, taught us many of the fundamentals of programming
languages, but we still have much to learn. First, if you run any interesting
Lox programs in jlox, you'll discover it's achingly slow. The style of
interpretation it uses -- walking the AST directly -- is good enough for *some*
real-world uses, but leaves a lot to be desired for a general-purpose scripting
language.
Also, we implicitly rely on runtime features of the JVM itself. We take for
granted that things like `instanceof` in Java work *somehow*. And we never for a
second worry about memory management because the JVM's garbage collector takes
care of it for us.
When we were focused on high-level concepts, it was fine to gloss over those.
But now that we know our way around an interpreter, it's time to dig down to
those lower layers and build our own virtual machine from scratch using nothing
more than the C standard library...
================================================
FILE: book/a-map-of-the-territory.md
================================================
> You must have a map, no matter how rough. Otherwise you wander all over the
> place. In *The Lord of the Rings* I never made anyone go farther than he could
> on a given day.
>
> <cite>J. R. R. Tolkien</cite>
We don't want to wander all over the place, so before we set off, let's scan
the territory charted by previous language implementers. It will help us
understand where we are going and the alternate routes others have taken.
First, let me establish a shorthand. Much of this book is about a language's
*implementation*, which is distinct from the *language itself* in some sort of
Platonic ideal form. Things like "stack", "bytecode", and "recursive descent",
are nuts and bolts one particular implementation might use. From the user's
perspective, as long as the resulting contraption faithfully follows the
language's specification, it's all implementation detail.
We're going to spend a lot of time on those details, so if I have to write
"language *implementation*" every single time I mention them, I'll wear my
fingers off. Instead, I'll use "language" to refer to either a language or an
implementation of it, or both, unless the distinction matters.
## The Parts of a Language
Engineers have been building programming languages since the Dark Ages of
computing. As soon as we could talk to computers, we discovered doing so was too
hard, and we enlisted their help. I find it fascinating that even though today's
machines are literally a million times faster and have orders of magnitude more
storage, the way we build programming languages is virtually unchanged.
Though the area explored by language designers is vast, the trails they've
carved through it are <span name="dead">few</span>. Not every language takes the
exact same path -- some take a shortcut or two -- but otherwise they are
reassuringly similar, from Rear Admiral Grace Hopper's first COBOL compiler all
the way to some hot, new, transpile-to-JavaScript language whose "documentation"
consists entirely of a single, poorly edited README in a Git repository
somewhere.
<aside name="dead">
There are certainly dead ends, sad little cul-de-sacs of CS papers with zero
citations and now-forgotten optimizations that only made sense when memory was
measured in individual bytes.
</aside>
I visualize the network of paths an implementation may choose as climbing a
mountain. You start off at the bottom with the program as raw source text,
literally just a string of characters. Each phase analyzes the program and
transforms it to some higher-level representation where the semantics -- what
the author wants the computer to do -- become more apparent.
Eventually we reach the peak. We have a bird's-eye view of the user's program
and can see what their code *means*. We begin our descent down the other side of
the mountain. We transform this highest-level representation down to
successively lower-level forms to get closer and closer to something we know how
to make the CPU actually execute.
<img src="image/a-map-of-the-territory/mountain.png" alt="The branching paths a language may take over the mountain." class="wide" />
Let's trace through each of those trails and points of interest. Our journey
begins on the left with the bare text of the user's source code:
<img src="image/a-map-of-the-territory/string.png" alt="var average = (min + max) / 2;" />
### Scanning
The first step is **scanning**, also known as **lexing**, or (if you're trying
to impress someone) **lexical analysis**. They all mean pretty much the same
thing. I like "lexing" because it sounds like something an evil supervillain
would do, but I'll use "scanning" because it seems to be marginally more
commonplace.
A **scanner** (or **lexer**) takes in the linear stream of characters and chunks
them together into a series of something more akin to <span
name="word">"words"</span>. In programming languages, each of these words is
called a **token**. Some tokens are single characters, like `(` and `,`. Others
may be several characters long, like numbers (`123`), string literals (`"hi!"`),
and identifiers (`min`).
<aside name="word">
"Lexical" comes from the Greek root "lex", meaning "word".
</aside>
Some characters in a source file don't actually mean anything. Whitespace is
often insignificant, and comments, by definition, are ignored by the language.
The scanner usually discards these, leaving a clean sequence of meaningful
tokens.
<img src="image/a-map-of-the-territory/tokens.png" alt="[var] [average] [=] [(] [min] [+] [max] [)] [/] [2] [;]" />
### Parsing
The next step is **parsing**. This is where our syntax gets a **grammar** -- the
ability to compose larger expressions and statements out of smaller parts. Did
you ever diagram sentences in English class? If so, you've done what a parser
does, except that English has thousands and thousands of "keywords" and an
overflowing cornucopia of ambiguity. Programming languages are much simpler.
A **parser** takes the flat sequence of tokens and builds a tree structure that
mirrors the nested nature of the grammar. These trees have a couple of different
names -- **parse tree** or **abstract syntax tree** -- depending on how
close to the bare syntactic structure of the source language they are. In
practice, language hackers usually call them **syntax trees**, **ASTs**, or
often just **trees**.
<img src="image/a-map-of-the-territory/ast.png" alt="An abstract syntax tree." />
Parsing has a long, rich history in computer science that is closely tied to the
artificial intelligence community. Many of the techniques used today to parse
programming languages were originally conceived to parse *human* languages by AI
researchers who were trying to get computers to talk to us.
It turns out human languages were too messy for the rigid grammars those parsers
could handle, but they were a perfect fit for the simpler artificial grammars of
programming languages. Alas, we flawed humans still manage to use those simple
grammars incorrectly, so the parser's job also includes letting us know when we
do by reporting **syntax errors**.
### Static analysis
The first two stages are pretty similar across all implementations. Now, the
individual characteristics of each language start coming into play. At this
point, we know the syntactic structure of the code -- things like which
expressions are nested in which -- but we don't know much more than that.
In an expression like `a + b`, we know we are adding `a` and `b`, but we don't
know what those names refer to. Are they local variables? Global? Where are they
defined?
The first bit of analysis that most languages do is called **binding** or
**resolution**. For each **identifier**, we find out where that name is defined
and wire the two together. This is where **scope** comes into play -- the region
of source code where a certain name can be used to refer to a certain
declaration.
If the language is <span name="type">statically typed</span>, this is when we
type check. Once we know where `a` and `b` are declared, we can also figure out
their types. Then if those types don't support being added to each other, we
report a **type error**.
<aside name="type">
The language we'll build in this book is dynamically typed, so it will do its
type checking later, at runtime.
</aside>
Take a deep breath. We have attained the summit of the mountain and a sweeping
view of the user's program. All this semantic insight that is visible to us from
analysis needs to be stored somewhere. There are a few places we can squirrel it
away:
* Often, it gets stored right back as **attributes** on the syntax tree
itself -- extra fields in the nodes that aren't initialized during parsing
but get filled in later.
* Other times, we may store data in a lookup table off to the side. Typically,
the keys to this table are identifiers -- names of variables and declarations.
In that case, we call it a **symbol table** and the values it associates with
each key tell us what that identifier refers to.
* The most powerful bookkeeping tool is to transform the tree into an entirely
new data structure that more directly expresses the semantics of the code.
That's the next section.
Everything up to this point is considered the **front end** of the
implementation. You might guess everything after this is the **back end**, but
no. Back in the days of yore when "front end" and "back end" were coined,
compilers were much simpler. Later researchers invented new phases to stuff
between the two halves. Rather than discard the old terms, William Wulf and
company lumped those new phases into the charming but spatially paradoxical name
**middle end**.
### Intermediate representations
You can think of the compiler as a pipeline where each stage's job is to
organize the data representing the user's code in a way that makes the next
stage simpler to implement. The front end of the pipeline is specific to the
source language the program is written in. The back end is concerned with the
final architecture where the program will run.
In the middle, the code may be stored in some <span name="ir">**intermediate
representation**</span> (**IR**) that isn't tightly tied to either the source or
destination forms (hence "intermediate"). Instead, the IR acts as an interface
between these two languages.
<aside name="ir">
There are a few well-established styles of IRs out there. Hit your search engine
of choice and look for "control flow graph", "static single-assignment",
"continuation-passing style", and "three-address code".
</aside>
This lets you support multiple source languages and target platforms with less
effort. Say you want to implement Pascal, C, and Fortran compilers, and you want
to target x86, ARM, and, I dunno, SPARC. Normally, that means you're signing up
to write *nine* full compilers: Pascal→x86, C→ARM, and every other
combination.
A <span name="gcc">shared</span> intermediate representation reduces that
dramatically. You write *one* front end for each source language that produces
the IR. Then *one* back end for each target architecture. Now you can mix and
match those to get every combination.
<aside name="gcc">
If you've ever wondered how [GCC][] supports so many crazy languages and
architectures, like Modula-3 on Motorola 68k, now you know. Language front ends
target one of a handful of IRs, mainly [GIMPLE][] and [RTL][]. Target back ends
like the one for 68k then take those IRs and produce native code.
[gcc]: https://en.wikipedia.org/wiki/GNU_Compiler_Collection
[gimple]: https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
[rtl]: https://gcc.gnu.org/onlinedocs/gccint/RTL.html
</aside>
There's another big reason we might want to transform the code into a form that
makes the semantics more apparent...
### Optimization
Once we understand what the user's program means, we are free to swap it out
with a different program that has the *same semantics* but implements them more
efficiently -- we can **optimize** it.
A simple example is **constant folding**: if some expression always evaluates to
the exact same value, we can do the evaluation at compile time and replace the
code for the expression with its result. If the user typed in this:
```java
pennyArea = 3.14159 * (0.75 / 2) * (0.75 / 2);
```
we could do all of that arithmetic in the compiler and change the code to:
```java
pennyArea = 0.4417860938;
```
Optimization is a huge part of the programming language business. Many language
hackers spend their entire careers here, squeezing every drop of performance
they can out of their compilers to get their benchmarks a fraction of a percent
faster. It can become a sort of obsession.
We're mostly going to <span name="rathole">hop over that rathole</span> in this
book. Many successful languages have surprisingly few compile-time
optimizations. For example, Lua and CPython generate relatively unoptimized
code, and focus most of their performance effort on the runtime.
<aside name="rathole">
If you can't resist poking your foot into that hole, some keywords to get you
started are "constant propagation", "common subexpression elimination", "loop
invariant code motion", "global value numbering", "strength reduction", "scalar
replacement of aggregates", "dead code elimination", and "loop unrolling".
</aside>
### Code generation
We have applied all of the optimizations we can think of to the user's program.
The last step is converting it to a form the machine can actually run. In other
words, **generating code** (or **code gen**), where "code" here usually refers to
the kind of primitive assembly-like instructions a CPU runs and not the kind of
"source code" a human might want to read.
Finally, we are in the **back end**, descending the other side of the mountain.
From here on out, our representation of the code becomes more and more
primitive, like evolution run in reverse, as we get closer to something our
simple-minded machine can understand.
We have a decision to make. Do we generate instructions for a real CPU or a
virtual one? If we generate real machine code, we get an executable that the OS
can load directly onto the chip. Native code is lightning fast, but generating
it is a lot of work. Today's architectures have piles of instructions, complex
pipelines, and enough <span name="aad">historical baggage</span> to fill a 747's
luggage bay.
Speaking the chip's language also means your compiler is tied to a specific
architecture. If your compiler targets [x86][] machine code, it's not going to
run on an [ARM][] device. All the way back in the '60s, during the
Cambrian explosion of computer architectures, that lack of portability was a
real obstacle.
<aside name="aad">
For example, the [AAD][] ("ASCII Adjust AX Before Division") instruction lets
you perform division, which sounds useful. Except that instruction takes, as
operands, two binary-coded decimal digits packed into a single 16-bit register.
When was the last time *you* needed BCD on a 16-bit machine?
[aad]: http://www.felixcloutier.com/x86/AAD.html
</aside>
[x86]: https://en.wikipedia.org/wiki/X86
[arm]: https://en.wikipedia.org/wiki/ARM_architecture
To get around that, hackers like Martin Richards and Niklaus Wirth, of BCPL and
Pascal fame, respectively, made their compilers produce *virtual* machine code.
Instead of instructions for some real chip, they produced code for a
hypothetical, idealized machine. Wirth called this **p-code** for *portable*,
but today, we generally call it **bytecode** because each instruction is often a
single byte long.
These synthetic instructions are designed to map a little more closely to the
language's semantics, and not be so tied to the peculiarities of any one
computer architecture and its accumulated historical cruft. You can think of it
like a dense, binary encoding of the language's low-level operations.
### Virtual machine
If your compiler produces bytecode, your work isn't over once that's done. Since
there is no chip that speaks that bytecode, it's your job to translate. Again,
you have two options. You can write a little mini-compiler for each target
architecture that converts the bytecode to native code for that machine. You
still have to do work for <span name="shared">each</span> chip you support, but
this last stage is pretty simple and you get to reuse the rest of the compiler
pipeline across all of the machines you support. You're basically using your
bytecode as an intermediate representation.
<aside name="shared" class="bottom">
The basic principle here is that the farther down the pipeline you push the
architecture-specific work, the more of the earlier phases you can share across
architectures.
There is a tension, though. Many optimizations, like register allocation and
instruction selection, work best when they know the strengths and capabilities
of a specific chip. Figuring out which parts of your compiler can be shared and
which should be target-specific is an art.
</aside>
Or you can write a <span name="vm">**virtual machine**</span> (**VM**), a
program that emulates a hypothetical chip supporting your virtual architecture
at runtime. Running bytecode in a VM is slower than translating it to native
code ahead of time because every instruction must be simulated at runtime each
time it executes. In return, you get simplicity and portability. Implement your
VM in, say, C, and you can run your language on any platform that has a C
compiler. This is how the second interpreter we build in this book works.
<aside name="vm">
The term "virtual machine" also refers to a different kind of abstraction. A
**system virtual machine** emulates an entire hardware platform and operating
system in software. This is how you can play Windows games on your Linux
machine, and how cloud providers give customers the user experience of
controlling their own "server" without needing to physically allocate separate
computers for each user.
The kind of VMs we'll talk about in this book are **language virtual machines**
or **process virtual machines** if you want to be unambiguous.
</aside>
### Runtime
We have finally hammered the user's program into a form that we can execute. The
last step is running it. If we compiled it to machine code, we simply tell the
operating system to load the executable and off it goes. If we compiled it to
bytecode, we need to start up the VM and load the program into that.
In both cases, for all but the basest of low-level languages, we usually need
some services that our language provides while the program is running. For
example, if the language automatically manages memory, we need a garbage
collector going in order to reclaim unused bits. If our language supports
"instance of" tests so you can see what kind of object you have, then we need
some representation to keep track of the type of each object during execution.
All of this stuff is going at runtime, so it's called, appropriately, the
**runtime**. In a fully compiled language, the code implementing the runtime
gets inserted directly into the resulting executable. In, say, [Go][], each
compiled application has its own copy of Go's runtime directly embedded in it.
If the language is run inside an interpreter or VM, then the runtime lives
there. This is how most implementations of languages like Java, Python, and
JavaScript work.
[go]: https://golang.org/
## Shortcuts and Alternate Routes
That's the long path covering every possible phase you might implement. Many
languages do walk the entire route, but there are a few shortcuts and alternate
paths.
### Single-pass compilers
Some simple compilers interleave parsing, analysis, and code generation so that
they produce output code directly in the parser, without ever allocating any
syntax trees or other IRs. These <span name="sdt">**single-pass
compilers**</span> restrict the design of the language. You have no intermediate
data structures to store global information about the program, and you don't
revisit any previously parsed part of the code. That means as soon as you see
some expression, you need to know enough to correctly compile it.
<aside name="sdt">
[**Syntax-directed translation**][pass] is a structured technique for building
these all-at-once compilers. You associate an *action* with each piece of the
grammar, usually one that generates output code. Then, whenever the parser
matches that chunk of syntax, it executes the action, building up the target
code one rule at a time.
[pass]: https://en.wikipedia.org/wiki/Syntax-directed_translation
</aside>
Pascal and C were designed around this limitation. At the time, memory was so
precious that a compiler might not even be able to hold an entire *source file*
in memory, much less the whole program. This is why Pascal's grammar requires
type declarations to appear first in a block. It's why in C you can't call a
function above the code that defines it unless you have an explicit forward
declaration that tells the compiler what it needs to know to generate code for a
call to the later function.
### Tree-walk interpreters
Some programming languages begin executing code right after parsing it to an AST
(with maybe a bit of static analysis applied). To run the program, the
interpreter traverses the syntax tree one branch and leaf at a time, evaluating
each node as it goes.
This implementation style is common for student projects and little languages,
but is not widely used for <span name="ruby">general-purpose</span> languages
since it tends to be slow. Some people use "interpreter" to mean only these
kinds of implementations, but others define that word more generally, so I'll
use the inarguably explicit **tree-walk interpreter** to refer to these. Our
first interpreter rolls this way.
<aside name="ruby">
A notable exception is early versions of Ruby, which were tree walkers. At 1.9,
the canonical implementation of Ruby switched from the original MRI (Matz's Ruby
Interpreter) to Koichi Sasada's YARV (Yet Another Ruby VM). YARV is a
bytecode virtual machine.
</aside>
### Transpilers
<span name="gary">Writing</span> a complete back end for a language can be a lot
of work. If you have some existing generic IR to target, you could bolt your
front end onto that. Otherwise, it seems like you're stuck. But what if you
treated some other *source language* as if it were an intermediate
representation?
You write a front end for your language. Then, in the back end, instead of doing
all the work to *lower* the semantics to some primitive target language, you
produce a string of valid source code for some other language that's about as
high level as yours. Then, you use the existing compilation tools for *that*
language as your escape route off the mountain and down to something you can
execute.
They used to call this a **source-to-source compiler** or a **transcompiler**.
After the rise of languages that compile to JavaScript in order to run in the
browser, they've affected the hipster sobriquet **transpiler**.
<aside name="gary">
The first transcompiler, XLT86, translated 8080 assembly into 8086 assembly.
That might seem straightforward, but keep in mind the 8080 was an 8-bit chip and
the 8086 a 16-bit chip that could use each register as a pair of 8-bit ones.
XLT86 did data flow analysis to track register usage in the source program and
then efficiently map it to the register set of the 8086.
It was written by Gary Kildall, a tragic hero of computer science if there
ever was one. One of the first people to recognize the promise of
microcomputers, he created PL/M and CP/M, the first high-level language and OS
for them.
He was a sea captain, business owner, licensed pilot, and motorcyclist. A TV
host with the Kris Kristofferson-esque look sported by dashing bearded dudes in
the '80s. He took on Bill Gates and, like many, lost, before meeting his end in
a biker bar under mysterious circumstances. He died too young, but sure as hell
lived before he did.
</aside>
While the first transcompiler translated one assembly language to another,
today, most transpilers work on higher-level languages. After the viral spread
of UNIX to machines various and sundry, there began a long tradition of
compilers that produced C as their output language. C compilers were available
everywhere UNIX was and produced efficient code, so targeting C was a good way
to get your language running on a lot of architectures.
Web browsers are the "machines" of today, and their "machine code" is
JavaScript, so these days it seems [almost every language out there][js] has a
compiler that targets JS since that's the <span name="js">main</span> way to get
your code running in a browser.
[js]: https://github.com/jashkenas/coffeescript/wiki/list-of-languages-that-compile-to-js
<aside name="js">
JS used to be the *only* way to execute code in a browser. Thanks to
[WebAssembly][], compilers now have a second, lower-level language they can
target that runs on the web.
[webassembly]: https://github.com/webassembly/
</aside>
The front end -- scanner and parser -- of a transpiler looks like other
compilers. Then, if the source language is only a simple syntactic skin over the
target language, it may skip analysis entirely and go straight to outputting the
analogous syntax in the destination language.
If the two languages are more semantically different, you'll see more of the
typical phases of a full compiler including analysis and possibly even
optimization. Then, when it comes to code generation, instead of outputting some
binary language like machine code, you produce a string of grammatically correct
source (well, destination) code in the target language.
Either way, you then run that resulting code through the output language's
existing compilation pipeline, and you're good to go.
### Just-in-time compilation
This last one is less a shortcut and more a dangerous alpine scramble best
reserved for experts. The fastest way to execute code is by compiling it to
machine code, but you might not know what architecture your end user's machine
supports. What to do?
You can do the same thing that the HotSpot Java Virtual Machine (JVM),
Microsoft's Common Language Runtime (CLR), and most JavaScript interpreters do.
On the end user's machine, when the program is loaded -- either from source in
the case of JS, or platform-independent bytecode for the JVM and CLR -- you
compile it to native code for the architecture their computer supports.
Naturally enough, this is called **just-in-time compilation**. Most hackers just
say "JIT", pronounced like it rhymes with "fit".
The most sophisticated JITs insert profiling hooks into the generated code to
see which regions are most performance critical and what kind of data is flowing
through them. Then, over time, they will automatically recompile those <span
name="hot">hot spots</span> with more advanced optimizations.
<aside name="hot">
This is, of course, exactly where the HotSpot JVM gets its name.
</aside>
## Compilers and Interpreters
Now that I've stuffed your head with a dictionary's worth of programming
language jargon, we can finally address a question that's plagued coders since
time immemorial: What's the difference between a compiler and an interpreter?
It turns out this is like asking the difference between a fruit and a vegetable.
That seems like a binary either-or choice, but actually "fruit" is a *botanical*
term and "vegetable" is *culinary*. One does not strictly imply the negation of
the other. There are fruits that aren't vegetables (apples) and vegetables that
aren't fruits (carrots), but also edible plants that are both fruits *and*
vegetables, like tomatoes.
<span name="veg"></span>
<img src="image/a-map-of-the-territory/plants.png" alt="A Venn diagram of edible plants" />
<aside name="veg">
Peanuts (which are not even nuts) and cereals like wheat are actually fruit, but
I got this drawing wrong. What can I say, I'm a software engineer, not a
botanist. I should probably erase the little peanut guy, but he's so cute that I
can't bear to.
Now *pine nuts*, on the other hand, are plant-based foods that are neither
fruits nor vegetables. At least as far as I can tell.
</aside>
So, back to languages:
* **Compiling** is an *implementation technique* that involves translating a
source language to some other -- usually lower-level -- form. When you
generate bytecode or machine code, you are compiling. When you transpile to
another high-level language, you are compiling too.
* When we say a language implementation "is a **compiler**", we mean it
translates source code to some other form but doesn't execute it. The user has
to take the resulting output and run it themselves.
* Conversely, when we say an implementation "is an **interpreter**", we mean it
takes in source code and executes it immediately. It runs programs "from
source".
Like apples and oranges, some implementations are clearly compilers and *not*
interpreters. GCC and Clang take your C code and compile it to machine code. An
end user runs that executable directly and may never even know which tool was
used to compile it. So those are *compilers* for C.
In older versions of Matz's canonical implementation of Ruby, the user ran Ruby
from source. The implementation parsed it and executed it directly by traversing
the syntax tree. No other translation occurred, either internally or in any
user-visible form. So this was definitely an *interpreter* for Ruby.
But what of CPython? When you run your Python program using it, the code is
parsed and converted to an internal bytecode format, which is then executed
inside the VM. From the user's perspective, this is clearly an interpreter --
they run their program from source. But if you look under CPython's scaly skin,
you'll see that there is definitely some compiling going on.
The answer is that it is <span name="go">both</span>. CPython *is* an
interpreter, and it *has* a compiler. In practice, most scripting languages work
this way, as you can see:
<aside name="go">
The [Go tool][go] is even more of a horticultural curiosity. If you run `go
build`, it compiles your Go source code to machine code and stops. If you type
`go run`, it does that, then immediately executes the generated executable.
So `go` *is* a compiler (you can use it as a tool to compile code without
running it), *is* an interpreter (you can invoke it to immediately run a program
from source), and also *has* a compiler (when you use it as an interpreter, it
is still compiling internally).
[go tool]: https://golang.org/cmd/go/
</aside>
<img src="image/a-map-of-the-territory/venn.png" alt="A Venn diagram of compilers and interpreters" />
That overlapping region in the center is where our second interpreter lives too,
since it internally compiles to bytecode. So while this book is nominally about
interpreters, we'll cover some compilation too.
## Our Journey
That's a lot to take in all at once. Don't worry. This isn't the chapter where
you're expected to *understand* all of these pieces and parts. I just want you
to know that they are out there and roughly how they fit together.
This map should serve you well as you explore the territory beyond the guided
path we take in this book. I want to leave you yearning to strike out on your
own and wander all over that mountain.
But, for now, it's time for our own journey to begin. Tighten your bootlaces,
cinch up your pack, and come along. From <span name="here">here</span> on out,
all you need to focus on is the path in front of you.
<aside name="here">
Henceforth, I promise to tone down the whole mountain metaphor thing.
</aside>
<div class="challenges">
## Challenges
1. Pick an open source implementation of a language you like. Download the
source code and poke around in it. Try to find the code that implements the
scanner and parser. Are they handwritten, or generated using tools like
Lex and Yacc? (`.l` or `.y` files usually imply the latter.)
1. Just-in-time compilation tends to be the fastest way to implement dynamically
typed languages, but not all of them use it. What reasons are there to *not*
JIT?
1. Most Lisp implementations that compile to C also contain an interpreter that
lets them execute Lisp code on the fly as well. Why?
</div>
================================================
FILE: book/a-tree-walk-interpreter.md
================================================
With this part, we begin jlox, the first of our two interpreters. Programming
languages are a huge topic with piles of concepts and terminology to cram into
your brain all at once. Programming language theory requires a level of mental
rigor that you probably haven't had to summon since your last calculus final.
(Fortunately there isn't too much theory in this book.)
Implementing an interpreter uses a few architectural tricks and design
patterns uncommon in other kinds of applications, so we'll be getting used to
the engineering side of things too. Given all of that, we'll keep the code we
have to write as simple and plain as possible.
In less than two thousand lines of clean Java code, we'll build a complete
interpreter for Lox that implements every single feature of the language,
exactly as we've specified. The first few chapters work front-to-back through
the phases of the interpreter -- [scanning][], [parsing][], and
[evaluating code][]. After that, we add language features one at a time,
growing a simple calculator into a full-fledged scripting language.
[scanning]: scanning.html
[parsing]: parsing-expressions.html
[evaluating code]: evaluating-expressions.html
================================================
FILE: book/a-virtual-machine.md
================================================
> Magicians protect their secrets not because the secrets are large and
> important, but because they are so small and trivial. The wonderful effects
> created on stage are often the result of a secret so absurd that the magician
> would be embarrassed to admit that that was how it was done.
>
> <cite>Christopher Priest, <em>The Prestige</em></cite>
We've spent a lot of time talking about how to represent a program as a sequence
of bytecode instructions, but it feels like learning biology using only stuffed,
dead animals. We know what instructions are in theory, but we've never seen them
in action, so it's hard to really understand what they *do*. It would be hard to
write a compiler that outputs bytecode when we don't have a good understanding
of how that bytecode behaves.
So, before we go and build the front end of our new interpreter, we will begin
with the back end -- the virtual machine that executes instructions. It breathes
life into the bytecode. Watching the instructions prance around gives us a
clearer picture of how a compiler might translate the user's source code into a
series of them.
## An Instruction Execution Machine
The virtual machine is one part of our interpreter's internal architecture. You
hand it a chunk of code -- literally a Chunk -- and it runs it. The code and
data structures for the VM reside in a new module.
^code vm-h
As usual, we start simple. The VM will gradually acquire a whole pile of state
it needs to keep track of, so we define a struct now to stuff that all in.
Currently, all we store is the chunk that it executes.
Like we do with most of the data structures we create, we also define functions
to create and tear down a VM. Here's the implementation:
^code vm-c
OK, calling those functions "implementations" is a stretch. We don't have any
interesting state to initialize or free yet, so the functions are empty. Trust
me, we'll get there.
The slightly more interesting line here is that declaration of `vm`. This module
is eventually going to have a slew of functions and it would be a chore to pass
around a pointer to the VM to all of them. Instead, we declare a single global
VM object. We need only one anyway, and this keeps the code in the book a little
lighter on the page.
<aside name="one">
The choice to have a static VM instance is a concession for the book, but not
necessarily a sound engineering choice for a real language implementation. If
you're building a VM that's designed to be embedded in other host applications,
it gives the host more flexibility if you *do* explicitly take a VM pointer
and pass it around.
That way, the host app can control when and where memory for the VM is
allocated, run multiple VMs in parallel, etc.
What I'm doing here is a global variable, and [everything bad you've heard about
global variables][global] is still true when programming in the large. But when
keeping things small for a book...
[global]: http://gameprogrammingpatterns.com/singleton.html
</aside>
Before we start pumping fun code into our VM, let's go ahead and wire it up to
the interpreter's main entrypoint.
^code main-init-vm (1 before, 1 after)
We spin up the VM when the interpreter first starts. Then when we're about to
exit, we wind it down.
^code main-free-vm (1 before, 1 after)
One last ceremonial obligation:
^code main-include-vm (1 before, 2 after)
Now when you run clox, it starts up the VM before it creates that hand-authored
chunk from the [last chapter][]. The VM is ready and waiting, so let's teach it
to do something.
[last chapter]: chunks-of-bytecode.html#disassembling-chunks
### Executing instructions
The VM springs into action when we command it to interpret a chunk of bytecode.
^code main-interpret (1 before, 1 after)
This function is the main entrypoint into the VM. It's declared like so:
^code interpret-h (1 before, 2 after)
The VM runs the chunk and then responds with a value from this enum:
^code interpret-result (2 before, 2 after)
We aren't using the result yet, but when we have a compiler that reports static
errors and a VM that detects runtime errors, the interpreter will use this to
know how to set the exit code of the process.
We're inching towards some actual implementation.
^code interpret
First, we store the chunk being executed in the VM. Then we call `run()`, an
internal helper function that actually runs the bytecode instructions. Between
those two parts is an intriguing line. What is this `ip` business?
As the VM works its way through the bytecode, it keeps track of where it is --
the location of the instruction currently being executed. We don't use a <span
name="local">local</span> variable inside `run()` for this because eventually
other functions will need to access it. Instead, we store it as a field in VM.
<aside name="local">
If we were trying to squeeze every ounce of speed out of our bytecode
interpreter, we would store `ip` in a local variable. It gets modified so often
during execution that we want the C compiler to keep it in a register.
</aside>
^code ip (2 before, 1 after)
Its type is a byte pointer. We use an actual real C pointer pointing right into
the middle of the bytecode array instead of something like an integer index
because it's faster to dereference a pointer than look up an element in an array
by index.
The name "IP" is traditional, and -- unlike many traditional names in CS --
actually makes sense: it's an **[instruction pointer][ip]**. Almost every
instruction set in the <span name="ip">world</span>, real and virtual, has a
register or variable like this.
[ip]: https://en.wikipedia.org/wiki/Program_counter
<aside name="ip">
x86, x64, and the CLR call it "IP". 68k, PowerPC, ARM, p-code, and the JVM call
it "PC", for **program counter**.
</aside>
We initialize `ip` by pointing it at the first byte of code in the chunk. We
haven't executed that instruction yet, so `ip` points to the instruction *about
to be executed*. This will be true during the entire time the VM is running: the
IP always points to the next instruction, not the one currently being handled.
The real fun happens in `run`().
^code run
This is the single most <span name="important">important</span> function in all
of clox, by far. When the interpreter executes a user's program, it will spend
something like 90% of its time inside `run()`. It is the beating heart of the
VM.
<aside name="important">
Or, at least, it *will* be in a few chapters when it has enough content to be
useful. Right now, it's not exactly a wonder of software wizardry.
</aside>
Despite that dramatic intro, it's conceptually pretty simple. We have an outer
loop that goes and goes. Each turn through that loop, we read and execute a
single bytecode instruction.
To process an instruction, we first figure out what kind of instruction we're
dealing with. The `READ_BYTE` macro reads the byte currently pointed at by `ip`
and then <span name="next">advances</span> the instruction pointer. The first
byte of any instruction is the opcode. Given a numeric opcode, we need to get to
the right C code that implements that instruction's semantics. This process is
called **decoding** or **dispatching** the instruction.
<aside name="next">
Note that `ip` advances as soon as we read the opcode, before we've actually
started executing the instruction. So, again, `ip` points to the *next*
byte of code to be used.
</aside>
We do that process for every single instruction, every single time one is
executed, so this is the most performance critical part of the entire virtual
machine. Programming language lore is filled with <span
name="dispatch">clever</span> techniques to do bytecode dispatch efficiently,
going all the way back to the early days of computers.
<aside name="dispatch">
If you want to learn some of these techniques, look up "direct threaded code",
"jump table", and "computed goto".
</aside>
Alas, the fastest solutions require either non-standard extensions to C, or
handwritten assembly code. For clox, we'll keep it simple. Just like our
disassembler, we have a single giant `switch` statement with a case for each
opcode. The body of each case implements that opcode's behavior.
So far, we handle only a single instruction, `OP_RETURN`, and the only thing it
does is exit the loop entirely. Eventually, that instruction will be used to
return from the current Lox function, but we don't have functions yet, so we'll
repurpose it temporarily to end the execution.
Let's go ahead and support our one other instruction.
^code op-constant (1 before, 1 after)
We don't have enough machinery in place yet to do anything useful with a
constant. For now, we'll just print it out so we interpreter hackers can see
what's going on inside our VM. That call to `printf()` necessitates an include.
^code vm-include-stdio (1 after)
We also have a new macro to define.
^code read-constant (1 before, 2 after)
`READ_CONSTANT()` reads the next byte from the bytecode, treats the resulting
number as an index, and looks up the corresponding Value in the chunk's constant
table. In later chapters, we'll add a few more instructions with operands that
refer to constants, so we're setting up this helper macro now.
Like the previous `READ_BYTE` macro, `READ_CONSTANT` is only used inside
`run()`. To make that scoping more explicit, the macro definitions themselves
are confined to that function. We <span name="macro">define</span> them at the
beginning and -- because we care -- undefine them at the end.
^code undef-read-constant (1 before, 1 after)
<aside name="macro">
Undefining these macros explicitly might seem needlessly fastidious, but C tends
to punish sloppy users, and the C preprocessor doubly so.
</aside>
### Execution tracing
If you run clox now, it executes the chunk we hand-authored in the last chapter
and spits out `1.2` to your terminal. We can see that it's working, but that's
only because our implementation of `OP_CONSTANT` has temporary code to log the
value. Once that instruction is doing what it's supposed to do and plumbing that
constant along to other operations that want to consume it, the VM will become a
black box. That makes our lives as VM implementers harder.
To help ourselves out, now is a good time to add some diagnostic logging to the
VM like we did with chunks themselves. In fact, we'll even reuse the same code.
We don't want this logging enabled all the time -- it's just for us VM hackers,
not Lox users -- so first we create a flag to hide it behind.
^code define-debug-trace (1 before, 2 after)
When this flag is defined, the VM disassembles and prints each instruction right
before executing it. Where our previous disassembler walked an entire chunk
once, statically, this disassembles instructions dynamically, on the fly.
^code trace-execution (1 before, 1 after)
Since `disassembleInstruction()` takes an integer byte *offset* and we store the
current instruction reference as a direct pointer, we first do a little pointer
math to convert `ip` back to a relative offset from the beginning of the
bytecode. Then we disassemble the instruction that begins at that byte.
As ever, we need to bring in the declaration of the function before we can call
it.
^code vm-include-debug (1 before, 1 after)
I know this code isn't super impressive so far -- it's literally a switch
statement wrapped in a `for` loop but, believe it or not, this is one of the two
major components of our VM. With this, we can imperatively execute instructions.
Its simplicity is a virtue -- the less work it does, the faster it can do it.
Contrast this with all of the complexity and overhead we had in jlox with the
Visitor pattern for walking the AST.
## A Value Stack Manipulator
In addition to imperative side effects, Lox has expressions that produce,
modify, and consume values. Thus, our compiled bytecode needs a way to shuttle
values around between the different instructions that need them. For example:
```lox
print 3 - 2;
```
We obviously need instructions for the constants 3 and 2, the `print` statement,
and the subtraction. But how does the subtraction instruction know that 3 is
the <span name="word">minuend</span> and 2 is the subtrahend? How does the print
instruction know to print the result of that?
<aside name="word">
Yes, I did have to look up "subtrahend" and "minuend" in a dictionary. But
aren't they delightful words? "Minuend" sounds like a kind of Elizabethan dance
and "subtrahend" might be some sort of underground Paleolithic monument.
</aside>
To put a finer point on it, look at this thing right here:
```lox
fun echo(n) {
print n;
return n;
}
print echo(echo(1) + echo(2)) + echo(echo(4) + echo(5));
```
I wrapped each subexpression in a call to `echo()` that prints and returns its
argument. That side effect means we can see the exact order of operations.
Don't worry about the VM for a minute. Think about just the semantics of Lox
itself. The operands to an arithmetic operator obviously need to be evaluated
before we can perform the operation itself. (It's pretty hard to add `a + b` if
you don't know what `a` and `b` are.) Also, when we implemented expressions in
jlox, we <span name="undefined">decided</span> that the left operand must be
evaluated before the right.
<aside name="undefined">
We could have left evaluation order unspecified and let each implementation
decide. That leaves the door open for optimizing compilers to reorder arithmetic
expressions for efficiency, even in cases where the operands have visible side
effects. C and Scheme leave evaluation order unspecified. Java specifies
left-to-right evaluation like we do for Lox.
I think nailing down stuff like this is generally better for users. When
expressions are not evaluated in the order users intuit -- possibly in different
orders across different implementations! -- it can be a burning hellscape of
pain to figure out what's going on.
</aside>
Here is the syntax tree for the `print` statement:
<img src="image/a-virtual-machine/ast.png" alt="The AST for the example
statement, with numbers marking the order that the nodes are evaluated." />
Given left-to-right evaluation, and the way the expressions are nested, any
correct Lox implementation *must* print these numbers in this order:
```text
1 // from echo(1)
2 // from echo(2)
3 // from echo(1 + 2)
4 // from echo(4)
5 // from echo(5)
9 // from echo(4 + 5)
12 // from print 3 + 9
```
Our old jlox interpreter accomplishes this by recursively traversing the AST. It
does a postorder traversal. First it recurses down the left operand branch,
then the right operand, then finally it evaluates the node itself.
After evaluating the left operand, jlox needs to store that result somewhere
temporarily while it's busy traversing down through the right operand tree. We
use a local variable in Java for that. Our recursive tree-walk interpreter
creates a unique Java call frame for each node being evaluated, so we could have
as many of these local variables as we needed.
In clox, our `run()` function is not recursive -- the nested expression tree is
flattened out into a linear series of instructions. We don't have the luxury of
using C local variables, so how and where should we store these temporary
values? You can probably <span name="guess">guess</span> already, but I want to
really drill into this because it's an aspect of programming that we take for
granted, but we rarely learn *why* computers are architected this way.
<aside name="guess">
Hint: it's in the name of this section, and it's how Java and C manage recursive
calls to functions.
</aside>
Let's do a weird exercise. We'll walk through the execution of the above program
a step at a time:
<img src="image/a-virtual-machine/bars.png" alt="The series of instructions with
bars showing which numbers need to be preserved across which instructions." />
On the left are the steps of code. On the right are the values we're tracking.
Each bar represents a number. It starts when the value is first produced --
either a constant or the result of an addition. The length of the bar tracks
when a previously produced value needs to be kept around, and it ends when that
value finally gets consumed by an operation.
As you step through, you see values appear and then later get eaten. The
longest-lived ones are the values produced from the left-hand side of an
addition. Those stick around while we work through the right-hand operand
expression.
In the above diagram, I gave each unique number its own visual column. Let's be
a little more parsimonious. Once a number is consumed, we allow its column to be
reused for another later value. In other words, we take all of those gaps
up there and fill them in, pushing in numbers from the right:
<img src="image/a-virtual-machine/bars-stacked.png" alt="Like the previous
diagram, but with number bars pushed to the left, forming a stack." />
There's some interesting stuff going on here. When we shift everything over,
each number still manages to stay in a single column for its entire life. Also,
there are no gaps left. In other words, whenever a number appears earlier than
another, then it will live at least as long as that second one. The first number
to appear is the last to be consumed. Hmm... last-in, first-out... why, that's a
<span name="pancakes">stack</span>!
<aside name="pancakes">
This is also a stack:
<img src="image/a-virtual-machine/pancakes.png" alt="A stack... of pancakes." />
</aside>
In the second diagram, each time we introduce a number, we push it onto the
stack from the right. When numbers are consumed, they are always popped off from
rightmost to left.
Since the temporary values we need to track naturally have stack-like behavior,
our VM will use a stack to manage them. When an instruction "produces" a value,
it pushes it onto the stack. When it needs to consume one or more values, it
gets them by popping them off the stack.
### The VM's Stack
Maybe this doesn't seem like a revelation, but I *love* stack-based VMs. When
you first see a magic trick, it feels like something actually magical. But then
you learn how it works -- usually some mechanical gimmick or misdirection -- and
the sense of wonder evaporates. There are a <span name="wonder">couple</span> of
ideas in computer science where even after I pulled them apart and learned all
the ins and outs, some of the initial sparkle remained. Stack-based VMs are one
of those.
<aside name="wonder">
Heaps -- [the data structure][heap], not [the memory management thing][heap mem]
-- are another. And Vaughan Pratt's top-down operator precedence parsing scheme,
which we'll learn about [in due time][pratt].
[heap]: https://en.wikipedia.org/wiki/Heap_(data_structure)
[heap mem]: https://en.wikipedia.org/wiki/Memory_management#HEAP
[pratt]: compiling-expressions.html
</aside>
As you'll see in this chapter, executing instructions in a stack-based VM is
dead <span name="cheat">simple</span>. In later chapters, you'll also discover
that compiling a source language to a stack-based instruction set is a piece of
cake. And yet, this architecture is fast enough to be used by production
language implementations. It almost feels like cheating at the programming
language game.
<aside name="cheat">
To take a bit of the sheen off: stack-based interpreters aren't a silver bullet.
They're often *adequate*, but modern implementations of the JVM, the CLR, and
JavaScript all use sophisticated [just-in-time compilation][jit] pipelines to
generate *much* faster native code on the fly.
[jit]: https://en.wikipedia.org/wiki/Just-in-time_compilation
</aside>
Alrighty, it's codin' time! Here's the stack:
^code vm-stack (3 before, 1 after)
We implement the stack semantics ourselves on top of a raw C array. The bottom
of the stack -- the first value pushed and the last to be popped -- is at
element zero in the array, and later pushed values follow it. If we push the
letters of "crepe" -- my favorite stackable breakfast item -- onto the stack, in
order, the resulting C array looks like this:
<img src="image/a-virtual-machine/array.png" alt="An array containing the
letters in 'crepe' in order starting at element 0." />
Since the stack grows and shrinks as values are pushed and popped, we need to
track where the top of the stack is in the array. As with `ip`, we use a direct
pointer instead of an integer index since it's faster to dereference the pointer
than calculate the offset from the index each time we need it.
The pointer points at the array element just *past* the element containing the
top value on the stack. That seems a little odd, but almost every implementation
does this. It means we can indicate that the stack is empty by pointing at
element zero in the array.
<img src="image/a-virtual-machine/stack-empty.png" alt="An empty array with
stackTop pointing at the first element." />
If we pointed to the top element, then for an empty stack we'd need to point at
element -1. That's <span name="defined">undefined</span> in C. As we push values
onto the stack...
<aside name="defined">
What about when the stack is *full*, you ask, Clever Reader? The C standard is
one step ahead of you. It *is* allowed and well-specified to have an array
pointer that points just past the end of an array.
</aside>
<img src="image/a-virtual-machine/stack-c.png" alt="An array with 'c' at element
zero." />
...`stackTop` always points just past the last item.
<img src="image/a-virtual-machine/stack-crepe.png" alt="An array with 'c', 'r',
'e', 'p', and 'e' in the first five elements." />
I remember it like this: `stackTop` points to where the next value to be pushed
will go. The maximum number of values we can store on the stack (for now, at
least) is:
^code stack-max (1 before, 2 after)
Giving our VM a fixed stack size means it's possible for some sequence of
instructions to push too many values and run out of stack space -- the classic
"stack overflow". We could grow the stack dynamically as needed, but for now
we'll keep it simple. Since VM uses Value, we need to include its declaration.
^code vm-include-value (1 before, 2 after)
Now that VM has some interesting state, we get to initialize it.
^code call-reset-stack (1 before, 1 after)
That uses this helper function:
^code reset-stack
Since the stack array is declared directly inline in the VM struct, we don't
need to allocate it. We don't even need to clear the unused cells in the
array -- we simply won't access them until after values have been stored in
them. The only initialization we need is to set `stackTop` to point to the
beginning of the array to indicate that the stack is empty.
The stack protocol supports two operations:
^code push-pop (1 before, 2 after)
You can push a new value onto the top of the stack, and you can pop the most
recently pushed value back off. Here's the first function:
^code push
If you're rusty on your C pointer syntax and operations, this is a good warm-up.
The first line stores `value` in the array element at the top of the stack.
Remember, `stackTop` points just *past* the last used element, at the next
available one. This stores the value in that slot. Then we increment the pointer
itself to point to the next unused slot in the array now that the previous slot
is occupied.
Popping is the mirror image.
^code pop
First, we move the stack pointer *back* to get to the most recent used slot in
the array. Then we look up the value at that index and return it. We don't need
to explicitly "remove" it from the array -- moving `stackTop` down is enough to
mark that slot as no longer in use.
### Stack tracing
We have a working stack, but it's hard to *see* that it's working. When we start
implementing more complex instructions and compiling and running larger pieces
of code, we'll end up with a lot of values crammed into that array. It would
make our lives as VM hackers easier if we had some visibility into the stack.
To that end, whenever we're tracing execution, we'll also show the current
contents of the stack before we interpret each instruction.
^code trace-stack (1 before, 1 after)
We loop, printing each value in the array, starting at the first (bottom of the
stack) and ending when we reach the top. This lets us observe the effect of each
instruction on the stack. The output is pretty verbose, but it's useful when
we're surgically extracting a nasty bug from the bowels of the interpreter.
Stack in hand, let's revisit our two instructions. First up:
^code push-constant (2 before, 1 after)
In the last chapter, I was hand-wavey about how the `OP_CONSTANT` instruction
"loads" a constant. Now that we have a stack you know what it means to actually
produce a value: it gets pushed onto the stack.
^code print-return (1 before, 1 after)
Then we make `OP_RETURN` pop the stack and print the top value before exiting.
When we add support for real functions to clox, we'll change this code. But, for
now, it gives us a way to get the VM executing simple instruction sequences and
displaying the result.
## An Arithmetic Calculator
The heart and soul of our VM are in place now. The bytecode loop dispatches and
executes instructions. The stack grows and shrinks as values flow through it.
The two halves work, but it's hard to get a feel for how cleverly they interact
with only the two rudimentary instructions we have so far. So let's teach our
interpreter to do arithmetic.
We'll start with the simplest arithmetic operation, unary negation.
```lox
var a = 1.2;
print -a; // -1.2.
```
The prefix `-` operator takes one operand, the value to negate. It produces a
single result. We aren't fussing with a parser yet, but we can add the
bytecode instruction that the above syntax will compile to.
^code negate-op (1 before, 1 after)
We execute it like so:
^code op-negate (1 before, 1 after)
The instruction needs a value to operate on, which it gets by popping from the
stack. It negates that, then pushes the result back on for later instructions to
use. Doesn't get much easier than that. We can disassemble it too.
^code disassemble-negate (2 before, 1 after)
And we can try it out in our test chunk.
^code main-negate (1 before, 2 after)
After loading the constant, but before returning, we execute the negate
instruction. That replaces the constant on the stack with its negation. Then the
return instruction prints that out:
```text
-1.2
```
Magical!
### Binary operators
OK, unary operators aren't *that* impressive. We still only ever have a single
value on the stack. To really see some depth, we need binary operators. Lox has
four binary <span name="ops">arithmetic</span> operators: addition, subtraction,
multiplication, and division. We'll go ahead and implement them all at the same
time.
<aside name="ops">
Lox has some other binary operators -- comparison and equality -- but those
don't produce numbers as a result, so we aren't ready for them yet.
</aside>
^code binary-ops (1 before, 1 after)
Back in the bytecode loop, they are executed like this:
^code op-binary (1 before, 1 after)
The only difference between these four instructions is which underlying C
operator they ultimately use to combine the two operands. Surrounding that core
arithmetic expression is some boilerplate code to pull values off the stack and
push the result. When we later add dynamic typing, that boilerplate will grow.
To avoid repeating that code four times, I wrapped it up in a macro.
^code binary-op (1 before, 2 after)
I admit this is a fairly <span name="operator">adventurous</span> use of the C
preprocessor. I hesitated to do this, but you'll be glad in later chapters when
we need to add the type checking for each operand and stuff. It would be a chore
to walk you through the same code four times.
<aside name="operator">
Did you even know you can pass an *operator* as an argument to a macro? Now you
do. The preprocessor doesn't care that operators aren't first class in C. As far
as it's concerned, it's all just text tokens.
I know, you can just *feel* the temptation to abuse this, can't you?
</aside>
If you aren't familiar with the trick already, that outer `do while` loop
probably looks really weird. This macro needs to expand to a series of
statements. To be careful macro authors, we want to ensure those statements all
end up in the same scope when the macro is expanded. Imagine if you defined:
```c
#define WAKE_UP() makeCoffee(); drinkCoffee();
```
And then used it like:
```c
if (morning) WAKE_UP();
```
The intent is to execute both statements of the macro body only if `morning` is
true. But it expands to:
```c
if (morning) makeCoffee(); drinkCoffee();;
```
Oops. The `if` attaches only to the *first* statement. You might think you could
fix this using a block.
```c
#define WAKE_UP() { makeCoffee(); drinkCoffee(); }
```
That's better, but you still risk:
```c
if (morning)
WAKE_UP();
else
sleepIn();
```
Now you get a compile error on the `else` because of that trailing `;` after the
macro's block. Using a `do while` loop in the macro looks funny, but it gives
you a way to contain multiple statements inside a block that *also* permits a
semicolon at the end.
Where were we? Right, so what the body of that macro does is straightforward. A
binary operator takes two operands, so it pops twice. It performs the operation
on those two values and then pushes the result.
Pay close attention to the *order* of the two pops. Note that we assign the
first popped operand to `b`, not `a`. It looks backwards. When the operands
themselves are calculated, the left is evaluated first, then the right. That
means the left operand gets pushed before the right operand. So the right
operand will be on top of the stack. Thus, the first value we pop is `b`.
For example, if we compile `3 - 1`, the data flow between the instructions looks
like so:
<img src="image/a-virtual-machine/reverse.png" alt="A sequence of instructions
with the stack for each showing how pushing and then popping values reverses
their order." />
As we did with the other macros inside `run()`, we clean up after ourselves at
the end of the function.
^code undef-binary-op (1 before, 1 after)
Last is disassembler support.
^code disassemble-binary (2 before, 1 after)
The arithmetic instruction formats are simple, like `OP_RETURN`. Even though the
arithmetic *operators* take operands -- which are found on the stack -- the
arithmetic *bytecode instructions* do not.
Let's put some of our new instructions through their paces by evaluating a
larger expression:
<img src="image/a-virtual-machine/chunk.png" alt="The expression being
evaluated: -((1.2 + 3.4) / 5.6)" />
Building on our existing example chunk, here's the additional instructions we
need to hand-compile that AST to bytecode.
^code main-chunk (3 before, 3 after)
The addition goes first. The instruction for the left constant, 1.2, is already
there, so we add another for 3.4. Then we add those two using `OP_ADD`, leaving
it on the stack. That covers the left side of the division. Next we push the
5.6, and divide the result of the addition by it. Finally, we negate the result
of that.
Note how the output of the `OP_ADD` implicitly flows into being an operand of
`OP_DIVIDE` without either instruction being directly coupled to each other.
That's the magic of the stack. It lets us freely compose instructions without
them needing any complexity or awareness of the data flow. The stack acts like a
shared workspace that they all read from and write to.
In this tiny example chunk, the stack still only gets two values tall, but when
we start compiling Lox source to bytecode, we'll have chunks that use much more
of the stack. In the meantime, try playing around with this hand-authored chunk
to calculate different nested arithmetic expressions and see how values flow
through the instructions and stack.
You may as well get it out of your system now. This is the last chunk we'll
build by hand. When we next revisit bytecode, we will be writing a compiler to
generate it for us.
<div class="challenges">
## Challenges
1. What bytecode instruction sequences would you generate for the following
expressions:
```lox
1 * 2 + 3
1 + 2 * 3
3 - 2 - 1
1 + 2 * 3 - 4 / -5
```
(Remember that Lox does not have a syntax for negative number literals, so
the `-5` is negating the number 5.)
1. If we really wanted a minimal instruction set, we could eliminate either
`OP_NEGATE` or `OP_SUBTRACT`. Show the bytecode instruction sequence you
would generate for:
```lox
4 - 3 * -2
```
First, without using `OP_NEGATE`. Then, without using `OP_SUBTRACT`.
Given the above, do you think it makes sense to have both instructions? Why
or why not? Are there any other redundant instructions you would consider
including?
1. Our VM's stack has a fixed size, and we don't check if pushing a value
overflows it. This means the wrong series of instructions could cause our
interpreter to crash or go into undefined behavior. Avoid that by
dynamically growing the stack as needed.
What are the costs and benefits of doing so?
1. To interpret `OP_NEGATE`, we pop the operand, negate the value, and then
push the result. That's a simple implementation, but it increments and
decrements `stackTop` unnecessarily, since the stack ends up the same height
in the end. It might be faster to simply negate the value in place on the
stack and leave `stackTop` alone. Try that and see if you can measure a
performance difference.
Are there other instructions where you can do a similar optimization?
</div>
<div class="design-note">
## Design Note: Register-Based Bytecode
For the remainder of this book, we'll meticulously implement an interpreter
around a stack-based bytecode instruction set. There's another family of
bytecode architectures out there -- *register-based*. Despite the name, these
bytecode instructions aren't quite as difficult to work with as the registers in
an actual chip like <span name="x64">x64</span>. With real hardware registers,
you usually have only a handful for the entire program, so you spend a lot of
effort [trying to use them efficiently and shuttling stuff in and out of
them][register allocation].
[register allocation]: https://en.wikipedia.org/wiki/Register_allocation
<aside name="x64">
Register-based bytecode is a little closer to the [*register windows*][window]
supported by SPARC chips.
[window]: https://en.wikipedia.org/wiki/Register_window
</aside>
In a register-based VM, you still have a stack. Temporary values still get
pushed onto it and popped when no longer needed. The main difference is that
instructions can read their inputs from anywhere in the stack and can store
their outputs into specific stack slots.
Take this little Lox script:
```lox
var a = 1;
var b = 2;
var c = a + b;
```
In our stack-based VM, the last statement will get compiled to something like:
```lox
load <a> // Read local variable a and push onto stack.
load <b> // Read local variable b and push onto stack.
add // Pop two values, add, push result.
store <c> // Pop value and store in local variable c.
```
(Don't worry if you don't fully understand the load and store instructions yet.
We'll go over them in much greater detail [when we implement
variables][variables].) We have four separate instructions. That means four
times through the bytecode interpret loop, four instructions to decode and
dispatch. It's at least seven bytes of code -- four for the opcodes and another
three for the operands identifying which locals to load and store. Three pushes
and three pops. A lot of work!
[variables]: global-variables.html
In a register-based instruction set, instructions can read from and store
directly into local variables. The bytecode for the last statement above looks
like:
```lox
add <a> <b> <c> // Read values from a and b, add, store in c.
```
The add instruction is bigger -- it has three instruction operands that define
where in the stack it reads its inputs from and writes the result to. But since
local variables live on the stack, it can read directly from `a` and `b` and
then store the result right into `c`.
There's only a single instruction to decode and dispatch, and the whole thing
fits in four bytes. Decoding is more complex because of the additional operands,
but it's still a net win. There's no pushing and popping or other stack
manipulation.
The main implementation of Lua used to be stack-based. For <span name="lua">Lua
5.0</span>, the implementers switched to a register instruction set and noted a
speed improvement. The amount of improvement, naturally, depends heavily on the
details of the language semantics, specific instruction set, and compiler
sophistication, but that should get your attention.
<aside name="lua">
The Lua dev team -- Roberto Ierusalimschy, Waldemar Celes, and Luiz Henrique de
Figueiredo -- wrote a *fantastic* paper on this, one of my all time favorite
computer science papers, "[The Implementation of Lua 5.0][lua]" (PDF).
[lua]: https://www.lua.org/doc/jucs05.pdf
</aside>
That raises the obvious question of why I'm going to spend the rest of the book
doing a stack-based bytecode. Register VMs are neat, but they are quite a bit
harder to write a compiler for. For what is likely to be your very first
compiler, I wanted to stick with an instruction set that's easy to generate and
easy to execute. Stack-based bytecode is marvelously simple.
It's also *much* better known in the literature and the community. Even though
you may eventually move to something more advanced, it's a good common ground to
share with the rest of your language hacker peers.
</div>
================================================
FILE: book/acknowledgements.md
================================================
When the first copy of "[Game Programming Patterns][gpp]" sold, I guess I had
the right to call myself an author. But it took time to feel comfortable with
that label. Thank you to everyone who bought copies of my first book, and to the
publishers and translators who brought it to other languages. You gave me the
confidence to believe I could tackle a project of this scope. Well, that, and
massively underestimating what I was getting myself into, but that's on me.
[gpp]: https://gameprogrammingpatterns.com/
A fear particular to technical writing is *getting stuff wrong*. Tests and
static analysis only get you so far. Once the code and prose is in ink on paper,
there's no fixing it. I am deeply grateful to the many people who filed issues
and pull requests on the [open source repo][repo] for the book. Special thanks
go to cm1776, who filed 145 tactfully worded issues pointing out hundreds of
code errors, typos, and unclear sentences. The book is more accurate and
readable because of you all.
[repo]: https://github.com/munificent/craftinginterpreters
I'm grateful to my copy editor Kari Somerton who braved a heap of computer
science jargon and an unfamilar workflow in order to fix my many grammar errors
and stylistic inconsistencies.
When the pandemic turned everyone's life upside down, a number of people reached
out to tell me that my book provided a helpful distraction. This book that I
spent six years writing forms a chapter in my own life's story and I'm grateful
to the readers who contacted me and made that chapter more meaningful.
Finally, the deepest thanks go to my wife Megan and my daughters Lily and
Gretchen. You patiently endured the time I had to sink into the book, and my
stress while writing it. There's no one I'd rather be stuck at home with.
================================================
FILE: book/appendix-i.md
================================================
Here is a complete grammar for Lox. The chapters that introduce each part of the
language include the grammar rules there, but this collects them all into one
place.
## Syntax Grammar
The syntactic grammar is used to parse the linear sequence of tokens into the
nested syntax tree structure. It starts with the first rule that matches an
entire Lox program (or a single REPL entry).
```ebnf
program → declaration* EOF ;
```
### Declarations
A program is a series of declarations, which are the statements that bind new
identifiers or any of the other statement types.
```ebnf
declaration → classDecl
| funDecl
| varDecl
| statement ;
classDecl → "class" IDENTIFIER ( "<" IDENTIFIER )?
"{" function* "}" ;
funDecl → "fun" function ;
varDecl → "var" IDENTIFIER ( "=" expression )? ";" ;
```
### Statements
The remaining statement rules produce side effects, but do not introduce
bindings.
```ebnf
statement → exprStmt
| forStmt
| ifStmt
| printStmt
| returnStmt
| whileStmt
| block ;
exprStmt → expression ";" ;
forStmt → "for" "(" ( varDecl | exprStmt | ";" )
expression? ";"
expression? ")" statement ;
ifStmt → "if" "(" expression ")" statement
( "else" statement )? ;
printStmt → "print" expression ";" ;
returnStmt → "return" expression? ";" ;
whileStmt → "while" "(" expression ")" statement ;
block → "{" declaration* "}" ;
```
Note that `block` is a statement rule, but is also used as a nonterminal in a
couple of other rules for things like function bodies.
### Expressions
Expressions produce values. Lox has a number of unary and binary operators with
different levels of precedence. Some grammars for languages do not directly
encode the precedence relationships and specify that elsewhere. Here, we use a
separate rule for each precedence level to make it explicit.
```ebnf
expression → assignment ;
assignment → ( call "." )? IDENTIFIER "=" assignment
| logic_or ;
logic_or → logic_and ( "or" logic_and )* ;
logic_and → equality ( "and" equality )* ;
equality → comparison ( ( "!=" | "==" ) comparison )* ;
comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ;
term → factor ( ( "-" | "+" ) factor )* ;
factor → unary ( ( "/" | "*" ) unary )* ;
unary → ( "!" | "-" ) unary | call ;
call → primary ( "(" arguments? ")" | "." IDENTIFIER )* ;
primary → "true" | "false" | "nil" | "this"
| NUMBER | STRING | IDENTIFIER | "(" expression ")"
| "super" "." IDENTIFIER ;
```
### Utility rules
In order to keep the above rules a little cleaner, some of the grammar is
split out into a few reused helper rules.
```ebnf
function → IDENTIFIER "(" parameters? ")" block ;
parameters → IDENTIFIER ( "," IDENTIFIER )* ;
arguments → expression ( "," expression )* ;
```
## Lexical Grammar
The lexical grammar is used by the scanner to group characters into tokens.
Where the syntax is [context free][], the lexical grammar is [regular][] -- note
that there are no recursive rules.
[context free]: https://en.wikipedia.org/wiki/Context-free_grammar
[regular]: https://en.wikipedia.org/wiki/Regular_grammar
```ebnf
NUMBER → DIGIT+ ( "." DIGIT+ )? ;
STRING → "\"" <any char except "\"">* "\"" ;
IDENTIFIER → ALPHA ( ALPHA | DIGIT )* ;
ALPHA → "a" ... "z" | "A" ... "Z" | "_" ;
DIGIT → "0" ... "9" ;
```
================================================
FILE: book/appendix-ii.md
================================================
For your edification, here is the code produced by [the little script
we built][generator] to automate generating the syntax tree classes for jlox.
[generator]: representing-code.html#metaprogramming-the-trees
## Expressions
Expressions are the first syntax tree nodes we see, introduced in "[Representing
Code](representing-code.html)". The main Expr class defines the visitor
interface used to dispatch against the specific expression types, and contains
the other expression subclasses as nested classes.
^code expr
### Assign expression
Variable assignment is introduced in "[Statements and
State](statements-and-state.html#assignment)".
^code expr-assign
### Binary expression
Binary operators are introduced in "[Representing
Code](representing-code.html)".
^code expr-binary
### Call expression
Function call expressions are introduced in
"[Functions](functions.html#function-calls)".
^code expr-call
### Get expression
Property access, or "get" expressions are introduced in
"[Classes](classes.html#properties-on-instances)".
^code expr-get
### Grouping expression
Using parentheses to group expressions is introduced in "[Representing
Code](representing-code.html)".
^code expr-grouping
### Literal expression
Literal value expressions are introduced in "[Representing
Code](representing-code.html)".
^code expr-literal
### Logical expression
The logical `and` and `or` operators are introduced in "[Control
Flow](control-flow.html#logical-operators)".
^code expr-logical
### Set expression
Property assignment, or "set" expressions are introduced in
"[Classes](classes.html#properties-on-instances)".
^code expr-set
### Super expression
The `super` expression is introduced in
"[Inheritance](inheritance.html#calling-superclass-methods)".
^code expr-super
### This expression
The `this` expression is introduced in "[Classes](classes.html#this)".
^code expr-this
### Unary expression
Unary operators are introduced in "[Representing Code](representing-code.html)".
^code expr-unary
### Variable expression
Variable access expressions are introduced in "[Statements and
State](statements-and-state.html#variable-syntax)".
^code expr-variable
## Statements
Statements form a second hierarchy of syntax tree nodes independent of
expressions. We add the first couple of them in "[Statements and
State](statements-and-state.html)".
^code stmt
### Block statement
The curly-braced block statement that defines a local scope is introduced in
"[Statements and State](statements-and-state.html#block-syntax-and-semantics)".
^code stmt-block
### Class statement
Class declarations are introduced in, unsurprisingly,
"[Classes](classes.html#class-declarations)".
^code stmt-class
### Expression statement
The expression statement is introduced in "[Statements and
State](statements-and-state.html#statements)".
^code stmt-expression
### Function statement
Function declarations are introduced in, you guessed it,
"[Functions](functions.html#function-declarations)".
^code stmt-function
### If statement
The `if` statement is introduced in "[Control
Flow](control-flow.html#conditional-execution)".
^code stmt-if
### Print statement
The `print` statement is introduced in "[Statements and
State](statements-and-state.html#statements)".
^code stmt-print
### Return statement
You need a function to return from, so `return` statements are introduced in
"[Functions](functions.html#return-statements)".
^code stmt-return
### Variable statement
Variable declarations are introduced in "[Statements and
State](statements-and-state.html#variable-syntax)".
^code stmt-var
### While statement
The `while` statement is introduced in "[Control
Flow](control-flow.html#while-loops)".
^code stmt-while
================================================
FILE: book/backmatter.md
================================================
You've reached the end of the book! There are two pieces of supplementary
material you may find helpful:
* **[Appendix I][]** contains a complete grammar for Lox, all in one place.
* **[Appendix II][]** shows the Java classes produced by [the AST generator][]
we use for jlox.
[appendix i]: appendix-i.html
[appendix ii]: appendix-ii.html
[the ast generator]: representing-code.html#metaprogramming-the-trees
================================================
FILE: book/calls-and-functions.md
================================================
> Any problem in computer science can be solved with another level of
> indirection. Except for the problem of too many layers of indirection.
>
> <cite>David Wheeler</cite>
This chapter is a beast. I try to break features into bite-sized pieces, but
sometimes you gotta swallow the whole <span name="eat">meal</span>. Our next
task is functions. We could start with only function declarations, but that's
not very useful when you can't call them. We could do calls, but there's nothing
to call. And all of the runtime support needed in the VM to support both of
those isn't very rewarding if it isn't hooked up to anything you can see. So
we're going to do it all. It's a lot, but we'll feel good when we're done.
<aside name="eat">
Eating -- consumption -- is a weird metaphor for a creative act. But most of the
biological processes that produce "output" are a little less, ahem, decorous.
</aside>
## Function Objects
The most interesting structural change in the VM is around the stack. We already
*have* a stack for local variables and temporaries, so we're partway there. But
we have no notion of a *call* stack. Before we can make much progress, we'll
have to fix that. But first, let's write some code. I always feel better once I
start moving. We can't do much without having some kind of representation for
functions, so we'll start there. From the VM's perspective, what is a function?
A function has a body that can be executed, so that means some bytecode. We
could compile the entire program and all of its function declarations into one
big monolithic Chunk. Each function would have a pointer to the first
instruction of its code inside the Chunk.
This is roughly how compilation to native code works where you end up with one
solid blob of machine code. But for our bytecode VM, we can do something a
little higher level. I think a cleaner model is to give each function its own
Chunk. We'll want some other metadata too, so let's go ahead and stuff it all in
a struct now.
^code obj-function (2 before, 2 after)
Functions are first class in Lox, so they need to be actual Lox objects. Thus
ObjFunction has the same Obj header that all object types share. The `arity`
field stores the number of parameters the function expects. Then, in addition to
the chunk, we store the function's <span name="name">name</span>. That will be
handy for reporting readable runtime errors.
<aside name="name">
Humans don't seem to find numeric bytecode offsets particularly illuminating in
crash dumps.
</aside>
This is the first time the "object" module has needed to reference Chunk, so we
get an include.
^code object-include-chunk (1 before, 1 after)
Like we did with strings, we define some accessories to make Lox functions
easier to work with in C. Sort of a poor man's object orientation. First, we'll
declare a C function to create a new Lox function.
^code new-function-h (3 before, 1 after)
The implementation is over here:
^code new-function
We use our friend `ALLOCATE_OBJ()` to allocate memory and initialize the
object's header so that the VM knows what type of object it is. Instead of
passing in arguments to initialize the function like we did with ObjString, we
set the function up in a sort of blank state -- zero arity, no name, and no
code. That will get filled in later after the function is created.
Since we have a new kind of object, we need a new object type in the enum.
^code obj-type-function (1 before, 2 after)
When we're done with a function object, we must return the bits it borrowed back
to the operating system.
^code free-function (1 before, 1 after)
This switch case is <span name="free-name">responsible</span> for freeing the
ObjFunction itself as well as any other memory it owns. Functions own their
chunk, so we call Chunk's destructor-like function.
<aside name="free-name">
We don't need to explicitly free the function's name because it's an ObjString.
That means we can let the garbage collector manage its lifetime for us. Or, at
least, we'll be able to once we [implement a garbage collector][gc].
[gc]: garbage-collection.html
</aside>
Lox lets you print any object, and functions are first-class objects, so we
need to handle them too.
^code print-function (1 before, 1 after)
This calls out to:
^code print-function-helper
Since a function knows its name, it may as well say it.
Finally, we have a couple of macros for converting values to functions. First,
make sure your value actually *is* a function.
^code is-function (2 before, 1 after)
Assuming that evaluates to true, you can then safely cast the Value to an
ObjFunction pointer using this:
^code as-function (2 before, 1 after)
With that, our object model knows how to represent functions. I'm feeling warmed
up now. You ready for something a little harder?
## Compiling to Function Objects
Right now, our compiler assumes it is always compiling to one single chunk. With
each function's code living in separate chunks, that gets more complex. When the
compiler reaches a function declaration, it needs to emit code into the
function's chunk when compiling its body. At the end of the function body, the
compiler needs to return to the previous chunk it was working with.
That's fine for code inside function bodies, but what about code that isn't? The
"top level" of a Lox program is also imperative code and we need a chunk to
compile that into. We can simplify the compiler and VM by placing that top-level
code inside an automatically defined function too. That way, the compiler is
always within some kind of function body, and the VM always runs code by
invoking a function. It's as if the entire program is <span
name="wrap">wrapped</span> inside an implicit `main()` function.
<aside name="wrap">
One semantic corner where that analogy breaks down is global variables. They
have special scoping rules different from local variables, so in that way, the
top level of a script isn't like a function body.
</aside>
Before we get to user-defined functions, then, let's do the reorganization to
support that implicit top-level function. It starts with the Compiler struct.
Instead of pointing directly to a Chunk that the compiler writes to, it instead
has a reference to the function object being built.
^code function-fields (1 before, 1 after)
We also have a little FunctionType enum. This lets the compiler tell when it's
compiling top-level code versus the body of a function. Most of the compiler
doesn't care about this -- that's why it's a useful abstraction -- but in one or
two places the distinction is meaningful. We'll get to one later.
^code function-type-enum
Every place in the compiler that was writing to the Chunk now needs to go
through that `function` pointer. Fortunately, many <span
name="current">chapters</span> ago, we encapsulated access to the chunk in the
`currentChunk()` function. We only need to fix that and the rest of the compiler
is happy.
<aside name="current">
It's almost like I had a crystal ball that could see into the future and knew
we'd need to change the code later. But, really, it's because I wrote all the
code for the book before any of the text.
</aside>
^code current-chunk (1 before, 2 after)
The current chunk is always the chunk owned by the function we're in the middle
of compiling. Next, we need to actually create that function. Previously, the VM
passed a Chunk to the compiler which filled it with code. Instead, the compiler
will create and return a function that contains the compiled top-level code --
which is all we support right now -- of the user's program.
### Creating functions at compile time
We start threading this through in `compile()`, which is the main entry point
into the compiler.
^code call-init-compiler (1 before, 2 after)
There are a bunch of changes in how the compiler is initialized. First, we
initialize the new Compiler fields.
^code init-compiler (1 after)
Then we allocate a new function object to compile into.
^code init-function (1 before, 1 after)
<span name="null"></span>
<aside name="null">
I know, it looks dumb to null the `function` field only to immediately assign it
a value a few lines later. More garbage collection-related paranoia.
</aside>
Creating an ObjFunction in the compiler might seem a little strange. A function
object is the *runtime* representation of a function, but here we are creating
it at compile time. The way to think of it is that a function is similar to a
string or number literal. It forms a bridge between the compile time and runtime
worlds. When we get to function *declarations*, those really *are* literals
-- they are a notation that produces values of a built-in type. So the <span
name="closure">compiler</span> creates function objects during compilation.
Then, at runtime, they are simply invoked.
<aside name="closure">
We can create functions at compile time because they contain only data available
at compile time. The function's code, name, and arity are all fixed. When we add
closures in the [next chapter][closures], which capture variables at runtime,
the story gets more complex.
[closures]: closures.html
</aside>
Here is another strange piece of code:
^code init-function-slot (1 before, 1 after)
Remember that the compiler's `locals` array keeps track of which stack slots are
associated with which local variables or temporaries. From now on, the compiler
implicitly claims stack slot zero for the VM's own internal use. We give it an
empty name so that the user can't write an identifier that refers to it. I'll
explain what this is about when it becomes useful.
That's the initialization side. We also need a couple of changes on the other
end when we finish compiling some code.
^code end-compiler (1 after)
Previously, when `interpret()` called into the compiler, it passed in a Chunk to
be written to. Now that the compiler creates the function object itself, we
return that function. We grab it from the current compiler here:
^code end-function (1 before, 1 after)
And then return it to `compile()` like so:
^code return-function (1 before, 1 after)
Now is a good time to make another tweak in this function. Earlier, we added
some diagnostic code to have the VM dump the disassembled bytecode so we could
debug the compiler. We should fix that to keep working now that the generated
chunk is wrapped in a function.
^code disassemble-end (2 before, 2 after)
Notice the check in here to see if the function's name is `NULL`? User-defined
functions have names, but the implicit function we create for the top-level code
does not, and we need to handle that gracefully even in our own diagnostic code.
Speaking of which:
^code print-script (1 before, 1 after)
There's no way for a *user* to get a reference to the top-level function and try
to print it, but our `DEBUG_TRACE_EXECUTION` <span
name="debug">diagnostic</span> code that prints the entire stack can and does.
<aside name="debug">
It is no fun if the diagnostic code we use to find bugs itself causes the VM to
segfault!
</aside>
Bumping up a level to `compile()`, we adjust its signature.
^code compile-h (2 before, 2 after)
Instead of taking a chunk, now it returns a function. Over in the
implementation:
^code compile-signature (1 after)
Finally we get to some actual code. We change the very end of the function to
this:
^code call-end-compiler (4 before, 1 after)
We get the function object from the compiler. If there were no compile errors,
we return it. Otherwise, we signal an error by returning `NULL`. This way, the
VM doesn't try to execute a function that may contain invalid bytecode.
Eventually, we will update `interpret()` to handle the new declaration of
`compile()`, but first we have some other changes to make.
## Call Frames
It's time for a big conceptual leap. Before we can implement function
declarations and calls, we need to get the VM ready to handle them. There are
two main problems we need to worry about:
### Allocating local variables
The compiler allocates stack slots for local variables. How should that work
when the set of local variables in a program is distributed across multiple
functions?
One option would be to keep them totally separate. Each function would get its
own dedicated set of slots in the VM stack that it would own <span
name="static">forever</span>, even when the function isn't being called. Each
local variable in the entire program would have a bit of memory in the VM that
it keeps to itself.
<aside name="static">
It's basically what you'd get if you declared every local variable in a C
program using `static`.
</aside>
Believe it or not, early programming language implementations worked this way.
The first Fortran compilers statically allocated memory for each variable. The
obvious problem is that it's really inefficient. Most functions are not in the
middle of being called at any point in time, so sitting on unused memory for
them is wasteful.
The more fundamental problem, though, is recursion. With recursion, you can be
"in" multiple calls to the same function at the same time. Each needs its <span
name="fortran">own</span> memory for its local variables. In jlox, we solved
this by dynamically allocating memory for an environment each time a function
was called or a block entered. In clox, we don't want that kind of performance
cost on every function call.
<aside name="fortran">
Fortran avoided this problem by disallowing recursion entirely. Recursion was
considered an advanced, esoteric feature at the time.
</aside>
Instead, our solution lies somewhere between Fortran's static allocation and
jlox's dynamic approach. The value stack in the VM works on the observation that
local variables and temporaries behave in a last-in first-out fashion.
Fortunately for us, that's still true even when you add function calls into the
mix. Here's an example:
```lox
fun first() {
var a = 1;
second();
var b = 2;
}
fun second() {
var c = 3;
var d = 4;
}
first();
```
Step through the program and look at which variables are in memory at each point
in time:
<img src="image/calls-and-functions/calls.png" alt="Tracing through the execution of the previous program, showing the stack of variables at each step." />
As execution flows through the two calls, every local variable obeys the
principle that any variable declared after it will be discarded before the first
variable needs to be. This is true even across calls. We know we'll be done with
`c` and `d` before we are done with `a`. It seems we should be able to allocate
local variables on the VM's value stack.
Ideally, we still determine *where* on the stack each variable will go at
compile time. That keeps the bytecode instructions for working with variables
simple and fast. In the above example, we could <span
name="imagine">imagine</span> doing so in a straightforward way, but that
doesn't always work out. Consider:
<aside name="imagine">
I say "imagine" because the compiler can't actually figure this out. Because
functions are first class in Lox, we can't determine which functions call which
others at compile time.
</aside>
```lox
fun first() {
var a = 1;
second();
var b = 2;
second();
}
fun second() {
var c = 3;
var d = 4;
}
first();
```
In the first call to `second()`, `c` and `d` would go into slots 1 and 2. But in
the second call, we need to have made room for `b`, so `c` and `d` need to be in
slots 2 and 3. Thus the compiler can't pin down an exact slot for each local
variable across function calls. But *within* a given function, the *relative*
locations of each local variable are fixed. Variable `d` is always in the slot
right after `c`. This is the key insight.
When a function is called, we don't know where the top of the stack will be
because it can be called from different contexts. But, wherever that top happens
to be, we do know where all of the function's local variables will be relative
to that starting point. So, like many problems, we solve our allocation problem
with a level of indirection.
At the beginning of each function call, the VM records the location of the first
slot where that function's own locals begin. The instructions for working with
local variables access them by a slot index relative to that, instead of
relative to the bottom of the stack like they do today. At compile time, we
calculate those relative slots. At runtime, we convert that relative slot to an
absolute stack index by adding the function call's starting slot.
It's as if the function gets a "window" or "frame" within the larger stack where
it can store its locals. The position of the **call frame** is determined at
runtime, but within and relative to that region, we know where to find things.
<img src="image/calls-and-functions/window.png" alt="The stack at the two points when second() is called, with a window hovering over each one showing the pair of stack slots used by the function." />
The historical name for this recorded location where the function's locals start
is a **frame pointer** because it points to the beginning of the function's call
frame. Sometimes you hear **base pointer**, because it points to the base stack
slot on top of which all of the function's variables live.
That's the first piece of data we need to track. Every time we call a function,
the VM determines the first stack slot where that function's variables begin.
### Return addresses
Right now, the VM works its way through the instruction stream by incrementing
the `ip` field. The only interesting behavior is around control flow
instructions which offset the `ip` by larger amounts. *Calling* a function is
pretty straightforward -- simply set `ip` to point to the first instruction in
that function's chunk. But what about when the function is done?
The VM needs to <span name="return">return</span> back to the chunk where the
function was called from and resume execution at the instruction immediately
after the call. Thus, for each function call, we need to track where we jump
back to when the call completes. This is called a **return address** because
it's the address of the instruction that the VM returns to after the call.
Again, thanks to recursion, there may be multiple return addresses for a single
function, so this is a property of each *invocation* and not the function
itself.
<aside name="return">
The authors of early Fortran compilers had a clever trick for implementing
return addresses. Since they *didn't* support recursion, any given function
needed only a single return address at any point in time. So when a function was
called at runtime, the program would *modify its own code* to change a jump
instruction at the end of the function to jump back to its caller. Sometimes the
line between genius and madness is hair thin.
</aside>
### The call stack
So for each live function invocation -- each call that hasn't returned yet -- we
need to track where on the stack that function's locals begin, and where the
caller should resume. We'll put this, along with some other stuff, in a new
struct.
^code call-frame (1 before, 2 after)
A CallFrame represents a single ongoing function call. The `slots` field points
into the VM's value stack at the first slot that this function can use. I gave
it a plural name because -- thanks to C's weird "pointers are sort of arrays"
thing -- we'll treat it like an array.
The implementation of return addresses is a little different from what I
described above. Instead of storing the return address in the callee's frame,
the caller stores its own `ip`. When we return from a function, the VM will jump
to the `ip` of the caller's CallFrame and resume from there.
I also stuffed a pointer to the function being called in here. We'll use that to
look up constants and for a few other things.
Each time a function is called, we create one of these structs. We could <span
name="heap">dynamically</span> allocate them on the heap, but that's slow.
Function calls are a core operation, so they need to be as fast as possible.
Fortunately, we can make the same observation we made for variables: function
calls have stack semantics. If `first()` calls `second()`, the call to
`second()` will complete before `first()` does.
<aside name="heap">
Many Lisp implementations dynamically allocate stack frames because it
simplifies implementing [continuations][cont]. If your language supports
continuations, then function calls do *not* always have stack semantics.
[cont]: https://en.wikipedia.org/wiki/Continuation
</aside>
So over in the VM, we create an array of these CallFrame structs up front and
treat it as a stack, like we do with the value array.
^code frame-array (1 before, 1 after)
This array replaces the `chunk` and `ip` fields we used to have directly in the
VM. Now each CallFrame has its own `ip` and its own pointer to the ObjFunction
that it's executing. From there, we can get to the function's chunk.
The new `frameCount` field in the VM stores the current height of the CallFrame
stack -- the number of ongoing function calls. To keep clox simple, the array's
capacity is fixed. This means, as in many language implementations, there is a
maximum call depth we can handle. For clox, it's defined here:
^code frame-max (2 before, 2 after)
We also redefine the value stack's <span name="plenty">size</span> in terms of
that to make sure we have plenty of stack slots even in very deep call trees.
When the VM starts up, the CallFrame stack is empty.
<aside name="plenty">
It is still possible to overflow the stack if enough function calls use enough
temporaries in addition to locals. A robust implementation would guard against
this, but I'm trying to keep things simple.
</aside>
^code reset-frame-count (1 before, 1 after)
The "vm.h" header needs access to ObjFunction, so we add an include.
^code vm-include-object (2 before, 1 after)
Now we're ready to move over to the VM's implementation file. We've got some
grunt work ahead of us. We've moved `ip` out of the VM struct and into
CallFrame. We need to fix every line of code in the VM that touches `ip` to
handle that. Also, the instructions that access local variables by stack slot
need to be updated to do so relative to the current CallFrame's `slots` field.
We'll start at the top and plow through it.
^code run (1 before, 1 after)
First, we store the current topmost CallFrame in a <span
name="local">local</span> variable inside the main bytecode execution function.
Then we replace the bytecode access macros with versions that access `ip`
through that variable.
<aside name="local">
We could access the current frame by going through the CallFrame array every
time, but that's verbose. More importantly, storing the frame in a local
variable encourages the C compiler to keep that pointer in a register. That
speeds up access to the frame's `ip`. There's no *guarantee* that the compiler
will do this, but there's a good chance it will.
</aside>
Now onto each instruction that needs a little tender loving care.
^code push-local (2 before, 1 after)
Previously, `OP_GET_LOCAL` read the given local slot directly from the VM's
stack array, which meant it indexed the slot starting from the bottom of the
stack. Now, it accesses the current frame's `slots` array, which means it
accesses the given numbered slot relative to the beginning of that frame.
Setting a local variable works the same way.
^code set-local (2 before, 1 after)
The jump instructions used to modify the VM's `ip` field. Now, they do the same
for the current frame's `ip`.
^code jump (2 before, 1 after)
Same with the conditional jump:
^code jump-if-false (2 before, 1 after)
And our backward-jumping loop instruction:
^code loop (2 before, 1 after)
We have some diagnostic code that prints each instruction as it executes to help
us debug our VM. That needs to work with the new structure too.
^code trace-execution (1 before, 1 after)
Instead of passing in the VM's `chunk` and `ip` fields, now we read from the
current CallFrame.
You know, that wasn't too bad, actually. Most instructions just use the macros
so didn't need to be touched. Next, we jump up a level to the code that calls
`run()`.
^code interpret-stub (1 before, 2 after)
We finally get to wire up our earlier compiler changes to the back-end changes
we just made. First, we pass the source code to the compiler. It returns us a
new ObjFunction containing the compiled top-level code. If we get `NULL` back,
it means there was some compile-time error which the compiler has already
reported. In that case, we bail out since we can't run anything.
Otherwise, we store the function on the stack and prepare an initial CallFrame
to execute its code. Now you can see why the compiler sets aside stack slot zero
-- that stores the function being called. In the new CallFrame, we point to the
function, initialize its `ip` to point to the beginning of the function's
bytecode, and set up its stack window to start at the very bottom of the VM's
value stack.
This gets the interpreter ready to start executing code. After finishing, the VM
used to free the hardcoded chunk. Now that the ObjFunction owns that code, we
don't need to do that anymore, so the end of `interpret()` is simply this:
^code end-interpret (2 before, 1 after)
The last piece of code referring to the old VM fields is `runtimeError()`. We'll
revisit that later in the chapter, but for now let's change it to this:
^code runtime-error-temp (2 before, 1 after)
Instead of reading the chunk and `ip` directly from the VM, it pulls those from
the topmost CallFrame on the stack. That should get the function working again
and behaving as it did before.
Assuming we did all of that correctly, we got clox back to a runnable
state. Fire it up and it does... exactly what it did before. We haven't added
any new features yet, so this is kind of a let down. But all of the
infrastructure is there and ready for us now. Let's take advantage of it.
## Function Declarations
Before we can do call expressions, we need something to call, so we'll do
function declarations first. The <span name="fun">fun</span> starts with a
keyword.
<aside name="fun">
Yes, I am going to make a dumb joke about the `fun` keyword every time it
comes up.
</aside>
^code match-fun (1 before, 1 after)
That passes control to here:
^code fun-declaration
Functions are first-class values, and a function declaration simply creates and
stores one in a newly declared variable. So we parse the name just like any
other variable declaration. A function declaration at the top level will bind
the function to a global variable. Inside a block or other function, a function
declaration creates a local variable.
In an earlier chapter, I explained how variables [get defined in two
stages][stage]. This ensures you can't access a variable's value inside the
variable's own initializer. That would be bad because the variable doesn't
*have* a value yet.
[stage]: local-variables.html#another-scope-edge-case
Functions don't suffer from this problem. It's safe for a function to refer to
its own name inside its body. You can't *call* the function and execute the body
until after it's fully defined, so you'll never see the variable in an
uninitialized state. Practically speaking, it's useful to allow this in order to
support recursive local functions.
To make that work, we mark the function declaration's variable "initialized" as
soon as we compile the name, before we compile the body. That way the name can
be referenced inside the body without generating an error.
We do need one check, though.
^code check-depth (1 before, 1 after)
Before, we called `markInitialized()` only when we already knew we were in a
local scope. Now, a top-level function declaration will also call this function.
When that happens, there is no local variable to mark initialized -- the
function is bound to a global variable.
Next, we compile the function itself -- its parameter list and block body. For
that, we use a separate helper function. That helper generates code that
leaves the resulting function object on top of the stack. After that, we call
`defineVariable()` to store that function back into the variable we declared for
it.
I split out the code to compile the parameters and body because we'll reuse it
later for parsing method declarations inside classes. Let's build it
incrementally, starting with this:
^code compile-function
<aside name="no-end-scope">
This `beginScope()` doesn't have a corresponding `endScope()` call. Because we
end Compiler completely when we reach the end of the function body, there's no
need to close the lingering outermost scope.
</aside>
For now, we won't worry about parameters. We parse an empty pair of parentheses
followed by the body. The body starts with a left curly brace, which we parse
here. Then we call our existing `block()` function, which knows how to compile
the rest of a block including the closing brace.
### A stack of compilers
The interesting parts are the compiler stuff at the top and bottom. The Compiler
struct stores data like which slots are owned by which local variables, how many
blocks of nesting we're currently in, etc. All of that is specific to a single
function. But now the front end needs to handle compiling multiple functions
<span name="nested">nested</span> within each other.
<aside name="nested">
Remember that the compiler treats top-level code as the body of an implicit
function, so as soon as we add *any* function declarations, we're in a world of
nested functions.
</aside>
The trick for managing that is to create a separate Compiler for each function
being compiled. When we start compiling a function declaration, we create a new
Compiler on the C stack and initialize it. `initCompiler()` sets that Compiler
to be the current one. Then, as we compile the body, all of the functions that
emit bytecode write to the chunk owned by the new Compiler's function.
After we reach the end of the function's block body, we call `endCompiler()`.
That yields the newly compiled function object, which we store as a constant in
the *surrounding* function's constant table. But, wait, how do we get back to
the surrounding function? We lost it when `initCompiler()` overwrote the current
compiler pointer.
We fix that by treating the series of nested Compiler structs as a stack. Unlike
the Value and CallFrame stacks in the VM, we won't use an array. Instead, we use
a linked list. Each Compiler points back to the Compiler for the function that
encloses it, all the way back to the root Compiler for the top-level code.
^code enclosing-field (2 before, 1 after)
Inside the Compiler struct, we can't reference the Compiler *typedef* since that
declaration hasn't finished yet. Instead, we give a name to the struct itself
and use that for the field's type. C is weird.
When initializing a new Compiler, we capture the about-to-no-longer-be-current
one in that pointer.
^code store-enclosing (1 before, 1 after)
Then when a Compiler finishes, it pops itself off the stack by restoring the
previous compiler to be the new current one.
^code restore-enclosing (2 before, 1 after)
Note that we don't even need to <span name="compiler">dynamically</span>
allocate the Compiler structs. Each is stored as a local variable in the C stack
-- either in `compile()` or `function()`. The linked list of Compilers threads
through the C stack. The reason we can get an unbounded number of them is
because our compiler uses recursive descent, so `function()` ends up calling
itself recursively when you have nested function declarations.
<aside name="compiler">
Using the native stack for Compiler structs does mean our compiler has a
practical limit on how deeply nested function declarations can be. Go too far
and you could overflow the C stack. If we want the compiler to be more robust
against pathological or even malicious code -- a real concern for tools like
JavaScript VMs -- it would be good to have our compiler artificially limit the
amount of function nesting it permits.
</aside>
### Function parameters
Functions aren't very useful if you can't pass arguments to them, so let's do
parameters next.
^code parameters (1 before, 1 after)
Semantically, a parameter is simply a local variable declared in the outermost
lexical scope of the function body. We get to use the existing compiler support
for declaring named local variables to parse and compile parameters. Unlike
local variables, which have initializers, there's no code here to initialize the
parameter's value. We'll see how they are initialized later when we do argument
passing in function calls.
While we're at it, we note the function's arity by counting how many parameters
we parse. The other piece of metadata we store with a function is its name. When
compiling a function declaration, we call `initCompiler()` right after we parse
the function's name. That means we can grab the name right then from the
previous token.
^code init-function-name (1 before, 2 after)
Note that we're careful to create a copy of the name string. Remember, the
lexeme points directly into the original source code string. That string may get
freed once the code is finished compiling. The function object we create in the
compiler outlives the compiler and persists until runtime. So it needs its own
heap-allocated name string that it can keep around.
Rad. Now we can compile function declarations, like this:
```lox
fun areWeHavingItYet() {
print "Yes we are!";
}
print areWeHavingItYet;
```
We just can't do anything <span name="useful">useful</span> with them.
<aside name="useful">
We can print them! I guess that's not very useful, though.
</aside>
## Function Calls
By the end of this section, we'll start to see some interesting behavior. The
next step is calling functions. We don't usually think of it this way, but a
function call expression is kind of an infix `(` operator. You have a
high-precedence expression on the left for the thing being called -- usually
just a single identifier. Then the `(` in the middle, followed by the argument
expressions separated by commas, and a final `)` to wrap it up at the end.
That odd grammatical perspective explains how to hook the syntax into our
parsing table.
^code infix-left-paren (1 before, 1 after)
When the parser encounters a left parenthesis following an expression, it
dispatches to a new parser function.
^code compile-call
We've already consumed the `(` token, so next we compile the arguments using a
separate `argumentList()` helper. That function returns the number of arguments
it compiled. Each argument expression generates code that leaves its value on
the stack in preparation for the call. After that, we emit a new `OP_CALL`
instruction to invoke the function, using the argument count as an operand.
We compile the arguments using this friend:
^code argument-list
That code should look familiar from jlox. We chew through arguments as long as
we find commas after each expression. Once we run out, we consume the final
closing parenthesis and we're done.
Well, almost. Back in jlox, we added a compile-time check that you don't pass
more than 255 arguments to a call. At the time, I said that was because clox
would need a similar limit. Now you can see why -- since we stuff the argument
count into the bytecode as a single-byte operand, we can only go up to 255. We
need to verify that in this compiler too.
^code arg-limit (1 before, 1 after)
That's the front end. Let's skip over to the back end, with a quick stop in the
middle to declare the new instruction.
^code op-call (1 before, 1 after)
### Binding arguments to parameters
Before we get to the implementation, we should think about what the stack looks
like at the point of a call and what we need to do from there. When we reach the
call instruction, we have already executed the expression for the function being
called, followed by its arguments. Say our program looks like this:
```lox
fun sum(a, b, c) {
return a + b + c;
}
print 4 + sum(5, 6, 7);
```
If we pause the VM right on the `OP_CALL` instruction for that call to `sum()`,
the stack looks like this:
<img src="image/calls-and-functions/argument-stack.png" alt="Stack: 4, fn sum, 5, 6, 7." />
Picture this from the perspective of `sum()` itself. When the compiler compiled
`sum()`, it automatically allocated slot zero. Then, after that, it allocated
local slots for the parameters `a`, `b`, and `c`, in order. To perform a call to
`sum()`, we need a CallFrame initialized with the function being called and a
region of stack slots that it can use. Then we need to collect the arguments
passed to the function and get them into the corresponding slots for the
parameters.
When the VM starts executing the body of `sum()`, we want its stack window to
look like this:
<img src="image/calls-and-functions/parameter-window.png" alt="The same stack with the sum() function's call frame window surrounding fn sum, 5, 6, and 7." />
Do you notice how the argument slots that the caller sets up and the parameter
slots the callee needs are both in exactly the right order? How convenient! This
is no coincidence. When I talked about each CallFrame having its own window into
the stack, I never said those windows must be *disjoint*. There's nothing
preventing us from overlapping them, like this:
<img src="image/calls-and-functions/overlapping-windows.png" alt="The same stack with the top-level call frame covering the entire stack and the sum() function's call frame window surrounding fn sum, 5, 6, and 7." />
<span name="lua">The</span> top of the caller's stack contains the function
being called followed by the arguments in order. We know the caller doesn't have
any other slots above those in use because any temporaries needed when
evaluating argument expressions have been discarded by now. The bottom of the
callee's stack overlaps so that the parameter slots exactly line up with where
the argument values already live.
<aside name="lua">
Different bytecode VMs and real CPU architectures have different *calling
conventions*, which is the specific mechanism they use to pass arguments, store
the return address, etc. The mechanism I use here is based on Lua's clean, fast
virtual machine.
</aside>
This means that we don't need to do *any* work to "bind an argument to a
parameter". There's no copying values between slots or across environments. The
arguments are already exactly where they need to be. It's hard to beat that for
performance.
Time to implement the call instruction.
^code interpret-call (1 before, 1 after)
We need to know the function being called and the number of arguments passed to
it. We get the latter from the instruction's operand. That also tells us where
to find the function on the stack by counting past the argument slots from the
top of the stack. We hand that data off to a separate `callValue()` function. If
that returns `false`, it means the call caused some sort of runtime error. When
that happens, we abort the interpreter.
If `callValue()` is successful, there will be a new frame on the CallFrame stack
for the called function. The `run()` function has its own cached pointer to the
current frame, so we need to update that.
^code update-frame-after-call (2 before, 1 after)
Since the bytecode dispatch loop reads from that `frame` variable, when the VM
goes to execute the next instruction, it will read the `ip` from the newly
called function's CallFrame and jump to its code. The work for executing that
call begins here:
^code call-value
<aside name="switch">
Using a `switch` statement to check a single type is overkill now, but will make
sense when we add cases to handle other callable types.
</aside>
There's more going on here than just initializing a new CallFrame. Because Lox
is dynamically typed, there's nothing to prevent a user from writing bad code
like:
```lox
var notAFunction = 123;
notAFunction();
```
If that happens, the runtime needs to safely report an error and halt. So the
first thing we do is check the type of the value that we're trying to call. If
it's not a function, we error out. Otherwise, the actual call happens here:
^code call
This simply initializes the next CallFrame on the stack. It stores a pointer to
the function being called and points the frame's `ip` to the beginning of the
function's bytecode. Finally, it sets up the `slots` pointer to give the frame
its window into the stack. The arithmetic there ensures that the arguments
already on the stack line up with the function's parameters:
<img src="image/calls-and-functions/arithmetic.png" alt="The arithmetic to calculate frame->slots from stackTop and argCount." />
The funny little `- 1` is to account for stack slot zero which the compiler set
aside for when we add methods later. The parameters start at slot one so we
make the window start one slot earlier to align them with the arguments.
Before we move on, let's add the new instruction to our disassembler.
^code disassemble-call (1 before, 1 after)
And one more quick side trip. Now that we have a handy function for initiating a
CallFrame, we may as well use it to set up the first frame for executing the
top-level code.
^code interpret (1 before, 2 after)
OK, now back to calls...
### Runtime error checking
The overlapping stack windows work based on the assumption that a call passes
exactly one argument for each of the function's parameters. But, again, because
Lox ain't statically typed, a foolish user could pass too many or too few
arguments. In Lox, we've defined that to be a runtime error, which we report
like so:
^code check-arity (1 before, 1 after)
Pretty straightforward. This is why we store the arity of each function inside
the ObjFunction for it.
There's another error we need to report that's less to do with the user's
foolishness than our own. Because the CallFrame array has a fixed size, we need
to ensure a deep call chain doesn't overflow it.
^code check-overflow (2 before, 1 after)
In practice, if a program gets anywhere close to this limit, there's most likely
a bug in some runaway recursive code.
### Printing stack traces
While we're on the subject of runtime errors, let's spend a little time making
them more useful. Stopping on a runtime error is important to prevent the VM
from crashing and burning in some ill-defined way. But simply aborting doesn't
help the user fix their code that *caused* that error.
The classic tool to aid debugging runtime failures is a **stack trace** -- a
print out of each function that was still executing when the program died, and
where the execution was at the point that it died. Now that we have a call stack
and we've conveniently stored each function's name, we can show that entire
stack when a runtime error disrupts the harmony of the user's existence. It
looks like this:
^code runtime-error-stack (2 before, 2 after)
<aside name="minus">
The `- 1` is because the IP is already sitting on the next instruction to be
executed but we want the stack trace to point to the previous failed
instruction.
</aside>
After printing the error message itself, we walk the call stack from <span
name="top">top</span> (the most recently called function) to bottom (the
top-level code). For each frame, we find the line number that corresponds to the
current `ip` inside that frame's function. Then we print that line number along
with the function name.
<aside name="top">
There is some disagreement on which order stack frames should be shown in a
trace. Most put the innermost function as the first line and work their way
towards the bottom of the stack. Python prints them out in the opposite order.
So reading from top to bottom tells you how your program got to where it is, and
the last line is where the error actually occurred.
There's a logic to that style. It ensures you can always see the innermost
function even if the stack trace is too long to fit on one screen. On the other
hand, the "[inverted pyramid][]" from journalism tells us we should put the most
important information *first* in a block of text. In a stack trace, that's the
function where the error actually occurred. Most other language implementations
do that.
[inverted pyramid]: https://en.wikipedia.org/wiki/Inverted_pyramid_(journalism)
</aside>
For example, if you run this broken program:
```lox
fun a() { b(); }
fun b() { c(); }
fun c() {
c("too", "many");
}
a();
```
It prints out:
```text
Expected 0 arguments but got 2.
[line 4] in c()
[line 2] in b()
[line 1] in a()
[line 7] in script
```
That doesn't look too bad, does it?
### Returning from functions
We're getting close. We can call functions, and the VM will execute them. But we
can't *return* from them yet. We've had an `OP_RETURN` instruction for quite
some time, but it's always had some kind of temporary code hanging out in it
just to get us out of the bytecode loop. The time has arrived for a real
implementation.
^code interpret-return (1 before, 1 after)
When a function returns a value, that value will be on top of the stack. We're
about to discard the called function's entire stack window, so we pop that
return value off and hang on to it. Then we discard the CallFrame for the
returning function. If that was the very last CallFrame, it means we've finished
executing the top-level code. The entire program is done, so we pop the main
script function from the stack and then exit the interpreter.
Otherwise, we discard all of the slots the callee was using for its parameters
and local variables. That includes the same slots the caller used to pass the
arguments. Now that the call is done, the caller doesn't need them anymore. This
means the top of the stack ends up right at the beginning of the returning
function's stack window.
We push the return value back onto the stack at that new, lower location. Then
we update the `run()` function's cached pointer to the current frame. Ju
gitextract_s3p1_s2h/
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── asset/
│ ├── index.scss
│ ├── mustache/
│ │ ├── contents-nav.html
│ │ ├── contents-part.html
│ │ ├── contents.html
│ │ ├── footer.html
│ │ ├── header.html
│ │ ├── in_design.html
│ │ ├── index.html
│ │ ├── nav.html
│ │ ├── page.html
│ │ └── prev-next.html
│ ├── sass/
│ │ ├── chapter.scss
│ │ ├── contents.scss
│ │ ├── print.scss
│ │ ├── shared.scss
│ │ └── sign-up.scss
│ └── style.scss
├── book/
│ ├── a-bytecode-virtual-machine.md
│ ├── a-map-of-the-territory.md
│ ├── a-tree-walk-interpreter.md
│ ├── a-virtual-machine.md
│ ├── acknowledgements.md
│ ├── appendix-i.md
│ ├── appendix-ii.md
│ ├── backmatter.md
│ ├── calls-and-functions.md
│ ├── chunks-of-bytecode.md
│ ├── classes-and-instances.md
│ ├── classes.md
│ ├── closures.md
│ ├── compiling-expressions.md
│ ├── contents.md
│ ├── control-flow.md
│ ├── dedication.md
│ ├── evaluating-expressions.md
│ ├── functions.md
│ ├── garbage-collection.md
│ ├── global-variables.md
│ ├── hash-tables.md
│ ├── index.md
│ ├── inheritance.md
│ ├── introduction.md
│ ├── jumping-back-and-forth.md
│ ├── local-variables.md
│ ├── methods-and-initializers.md
│ ├── optimization.md
│ ├── parsing-expressions.md
│ ├── representing-code.md
│ ├── resolving-and-binding.md
│ ├── scanning-on-demand.md
│ ├── scanning.md
│ ├── statements-and-state.md
│ ├── strings.md
│ ├── superclasses.md
│ ├── the-lox-language.md
│ ├── types-of-values.md
│ └── welcome.md
├── c/
│ ├── chunk.c
│ ├── chunk.h
│ ├── clox.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── clox.xcscheme
│ ├── common.h
│ ├── compiler.c
│ ├── compiler.h
│ ├── debug.c
│ ├── debug.h
│ ├── main.c
│ ├── memory.c
│ ├── memory.h
│ ├── object.c
│ ├── object.h
│ ├── scanner.c
│ ├── scanner.h
│ ├── table.c
│ ├── table.h
│ ├── value.c
│ ├── value.h
│ ├── vm.c
│ └── vm.h
├── java/
│ └── com/
│ └── craftinginterpreters/
│ ├── lox/
│ │ ├── AstPrinter.java
│ │ ├── Environment.java
│ │ ├── Expr.java
│ │ ├── Interpreter.java
│ │ ├── Lox.java
│ │ ├── LoxCallable.java
│ │ ├── LoxClass.java
│ │ ├── LoxFunction.java
│ │ ├── LoxInstance.java
│ │ ├── Parser.java
│ │ ├── Resolver.java
│ │ ├── Return.java
│ │ ├── RuntimeError.java
│ │ ├── Scanner.java
│ │ ├── Stmt.java
│ │ ├── Token.java
│ │ └── TokenType.java
│ └── tool/
│ └── GenerateAst.java
├── jlox
├── note/
│ ├── BISAC.txt
│ ├── answers/
│ │ ├── chapter01_introduction/
│ │ │ ├── 1.md
│ │ │ ├── 2/
│ │ │ │ ├── Hello.java
│ │ │ │ └── Makefile
│ │ │ └── 3/
│ │ │ ├── Makefile
│ │ │ ├── linked_list
│ │ │ ├── linked_list.c
│ │ │ └── linked_list.xcodeproj/
│ │ │ ├── project.pbxproj
│ │ │ └── project.xcworkspace/
│ │ │ └── contents.xcworkspacedata
│ │ ├── chapter02_map.md
│ │ ├── chapter03_lox.md
│ │ ├── chapter04_scanning.md
│ │ ├── chapter05_representing.md
│ │ ├── chapter06_parsing.md
│ │ ├── chapter07_evaluating.md
│ │ ├── chapter08_statements.md
│ │ ├── chapter09_control.md
│ │ ├── chapter10_functions.md
│ │ ├── chapter11_resolving/
│ │ │ ├── 4/
│ │ │ │ └── com/
│ │ │ │ └── craftinginterpreters/
│ │ │ │ ├── lox/
│ │ │ │ │ ├── AstPrinter.java
│ │ │ │ │ ├── Environment.java
│ │ │ │ │ ├── Expr.java
│ │ │ │ │ ├── Interpreter.java
│ │ │ │ │ ├── Lox.java
│ │ │ │ │ ├── LoxCallable.java
│ │ │ │ │ ├── LoxFunction.java
│ │ │ │ │ ├── Parser.java
│ │ │ │ │ ├── Resolver.java
│ │ │ │ │ ├── Return.java
│ │ │ │ │ ├── RuntimeError.java
│ │ │ │ │ ├── Scanner.java
│ │ │ │ │ ├── Stmt.java
│ │ │ │ │ ├── Token.java
│ │ │ │ │ └── TokenType.java
│ │ │ │ └── tool/
│ │ │ │ └── GenerateAst.java
│ │ │ └── chapter11_resolving.md
│ │ ├── chapter12_classes.md
│ │ ├── chapter13_inheritance/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ └── 3.md
│ │ ├── chapter14_chunks/
│ │ │ ├── 1.md
│ │ │ └── 2.md
│ │ ├── chapter15_virtual/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ └── 3.md
│ │ ├── chapter16_scanning.md
│ │ ├── chapter17_compiling.md
│ │ ├── chapter18_types.md
│ │ ├── chapter19_strings.md
│ │ ├── chapter20_hash/
│ │ │ └── 1.md
│ │ ├── chapter21_global.md
│ │ ├── chapter23_jumping/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ └── 3.md
│ │ ├── chapter24_calls/
│ │ │ ├── 1.md
│ │ │ └── 2.md
│ │ ├── chapter25_closures/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ └── 3.lox
│ │ ├── chapter26_garbage/
│ │ │ ├── 1.md
│ │ │ └── 2.md
│ │ ├── chapter27_classes/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ ├── 3.md
│ │ │ └── 4.md
│ │ ├── chapter28_methods/
│ │ │ ├── 1.md
│ │ │ ├── 2.md
│ │ │ └── 3.md
│ │ └── chapter29_superclasses/
│ │ ├── 1.md
│ │ ├── 2.md
│ │ ├── 3.diff
│ │ └── 3.md
│ ├── blurb.txt
│ ├── contents.txt
│ ├── design breaks.md
│ ├── images.md
│ ├── indexing.md
│ ├── log.txt
│ ├── names.txt
│ ├── objects.txt
│ ├── outline.md
│ ├── research.txt
│ ├── scope.txt
│ ├── struct sizes.txt
│ ├── style guide.md
│ └── todo.txt
├── site/
│ ├── .htaccess
│ ├── 404.html
│ ├── a-bytecode-virtual-machine.html
│ ├── a-map-of-the-territory.html
│ ├── a-tree-walk-interpreter.html
│ ├── a-virtual-machine.html
│ ├── acknowledgements.html
│ ├── appendix-i.html
│ ├── appendix-ii.html
│ ├── backmatter.html
│ ├── calls-and-functions.html
│ ├── chunks-of-bytecode.html
│ ├── classes-and-instances.html
│ ├── classes.html
│ ├── closures.html
│ ├── compiling-expressions.html
│ ├── contents.html
│ ├── control-flow.html
│ ├── dedication.html
│ ├── evaluating-expressions.html
│ ├── functions.html
│ ├── garbage-collection.html
│ ├── global-variables.html
│ ├── hash-tables.html
│ ├── index.css
│ ├── index.html
│ ├── inheritance.html
│ ├── introduction.html
│ ├── jumping-back-and-forth.html
│ ├── local-variables.html
│ ├── methods-and-initializers.html
│ ├── optimization.html
│ ├── parsing-expressions.html
│ ├── representing-code.html
│ ├── resolving-and-binding.html
│ ├── scanning-on-demand.html
│ ├── scanning.html
│ ├── script.js
│ ├── statements-and-state.html
│ ├── strings.html
│ ├── style.css
│ ├── superclasses.html
│ ├── the-lox-language.html
│ ├── types-of-values.html
│ └── welcome.html
├── test/
│ ├── assignment/
│ │ ├── associativity.lox
│ │ ├── global.lox
│ │ ├── grouping.lox
│ │ ├── infix_operator.lox
│ │ ├── local.lox
│ │ ├── prefix_operator.lox
│ │ ├── syntax.lox
│ │ ├── to_this.lox
│ │ └── undefined.lox
│ ├── benchmark/
│ │ ├── binary_trees.lox
│ │ ├── equality.lox
│ │ ├── fib.lox
│ │ ├── instantiation.lox
│ │ ├── invocation.lox
│ │ ├── method_call.lox
│ │ ├── properties.lox
│ │ ├── string_equality.lox
│ │ ├── trees.lox
│ │ ├── zoo.lox
│ │ └── zoo_batch.lox
│ ├── block/
│ │ ├── empty.lox
│ │ └── scope.lox
│ ├── bool/
│ │ ├── equality.lox
│ │ └── not.lox
│ ├── call/
│ │ ├── bool.lox
│ │ ├── nil.lox
│ │ ├── num.lox
│ │ ├── object.lox
│ │ └── string.lox
│ ├── class/
│ │ ├── empty.lox
│ │ ├── inherit_self.lox
│ │ ├── inherited_method.lox
│ │ ├── local_inherit_other.lox
│ │ ├── local_inherit_self.lox
│ │ ├── local_reference_self.lox
│ │ └── reference_self.lox
│ ├── closure/
│ │ ├── assign_to_closure.lox
│ │ ├── assign_to_shadowed_later.lox
│ │ ├── close_over_function_parameter.lox
│ │ ├── close_over_later_variable.lox
│ │ ├── close_over_method_parameter.lox
│ │ ├── closed_closure_in_function.lox
│ │ ├── nested_closure.lox
│ │ ├── open_closure_in_function.lox
│ │ ├── reference_closure_multiple_times.lox
│ │ ├── reuse_closure_slot.lox
│ │ ├── shadow_closure_with_local.lox
│ │ ├── unused_closure.lox
│ │ └── unused_later_closure.lox
│ ├── comments/
│ │ ├── line_at_eof.lox
│ │ ├── only_line_comment.lox
│ │ ├── only_line_comment_and_line.lox
│ │ └── unicode.lox
│ ├── constructor/
│ │ ├── arguments.lox
│ │ ├── call_init_early_return.lox
│ │ ├── call_init_explicitly.lox
│ │ ├── default.lox
│ │ ├── default_arguments.lox
│ │ ├── early_return.lox
│ │ ├── extra_arguments.lox
│ │ ├── init_not_method.lox
│ │ ├── missing_arguments.lox
│ │ ├── return_in_nested_function.lox
│ │ └── return_value.lox
│ ├── empty_file.lox
│ ├── expressions/
│ │ ├── evaluate.lox
│ │ └── parse.lox
│ ├── field/
│ │ ├── call_function_field.lox
│ │ ├── call_nonfunction_field.lox
│ │ ├── get_and_set_method.lox
│ │ ├── get_on_bool.lox
│ │ ├── get_on_class.lox
│ │ ├── get_on_function.lox
│ │ ├── get_on_nil.lox
│ │ ├── get_on_num.lox
│ │ ├── get_on_string.lox
│ │ ├── many.lox
│ │ ├── method.lox
│ │ ├── method_binds_this.lox
│ │ ├── on_instance.lox
│ │ ├── set_evaluation_order.lox
│ │ ├── set_on_bool.lox
│ │ ├── set_on_class.lox
│ │ ├── set_on_function.lox
│ │ ├── set_on_nil.lox
│ │ ├── set_on_num.lox
│ │ ├── set_on_string.lox
│ │ └── undefined.lox
│ ├── for/
│ │ ├── class_in_body.lox
│ │ ├── closure_in_body.lox
│ │ ├── fun_in_body.lox
│ │ ├── return_closure.lox
│ │ ├── return_inside.lox
│ │ ├── scope.lox
│ │ ├── statement_condition.lox
│ │ ├── statement_increment.lox
│ │ ├── statement_initializer.lox
│ │ ├── syntax.lox
│ │ └── var_in_body.lox
│ ├── function/
│ │ ├── body_must_be_block.lox
│ │ ├── empty_body.lox
│ │ ├── extra_arguments.lox
│ │ ├── local_mutual_recursion.lox
│ │ ├── local_recursion.lox
│ │ ├── missing_arguments.lox
│ │ ├── missing_comma_in_parameters.lox
│ │ ├── mutual_recursion.lox
│ │ ├── nested_call_with_arguments.lox
│ │ ├── parameters.lox
│ │ ├── print.lox
│ │ ├── recursion.lox
│ │ ├── too_many_arguments.lox
│ │ └── too_many_parameters.lox
│ ├── if/
│ │ ├── class_in_else.lox
│ │ ├── class_in_then.lox
│ │ ├── dangling_else.lox
│ │ ├── else.lox
│ │ ├── fun_in_else.lox
│ │ ├── fun_in_then.lox
│ │ ├── if.lox
│ │ ├── truth.lox
│ │ ├── var_in_else.lox
│ │ └── var_in_then.lox
│ ├── inheritance/
│ │ ├── constructor.lox
│ │ ├── inherit_from_function.lox
│ │ ├── inherit_from_nil.lox
│ │ ├── inherit_from_number.lox
│ │ ├── inherit_methods.lox
│ │ ├── parenthesized_superclass.lox
│ │ └── set_fields_from_base_class.lox
│ ├── limit/
│ │ ├── loop_too_large.lox
│ │ ├── no_reuse_constants.lox
│ │ ├── stack_overflow.lox
│ │ ├── too_many_constants.lox
│ │ ├── too_many_locals.lox
│ │ └── too_many_upvalues.lox
│ ├── logical_operator/
│ │ ├── and.lox
│ │ ├── and_truth.lox
│ │ ├── or.lox
│ │ └── or_truth.lox
│ ├── method/
│ │ ├── arity.lox
│ │ ├── empty_block.lox
│ │ ├── extra_arguments.lox
│ │ ├── missing_arguments.lox
│ │ ├── not_found.lox
│ │ ├── print_bound_method.lox
│ │ ├── refer_to_name.lox
│ │ ├── too_many_arguments.lox
│ │ └── too_many_parameters.lox
│ ├── nil/
│ │ └── literal.lox
│ ├── number/
│ │ ├── decimal_point_at_eof.lox
│ │ ├── leading_dot.lox
│ │ ├── literals.lox
│ │ ├── nan_equality.lox
│ │ └── trailing_dot.lox
│ ├── operator/
│ │ ├── add.lox
│ │ ├── add_bool_nil.lox
│ │ ├── add_bool_num.lox
│ │ ├── add_bool_string.lox
│ │ ├── add_nil_nil.lox
│ │ ├── add_num_nil.lox
│ │ ├── add_string_nil.lox
│ │ ├── comparison.lox
│ │ ├── divide.lox
│ │ ├── divide_nonnum_num.lox
│ │ ├── divide_num_nonnum.lox
│ │ ├── equals.lox
│ │ ├── equals_class.lox
│ │ ├── equals_method.lox
│ │ ├── greater_nonnum_num.lox
│ │ ├── greater_num_nonnum.lox
│ │ ├── greater_or_equal_nonnum_num.lox
│ │ ├── greater_or_equal_num_nonnum.lox
│ │ ├── less_nonnum_num.lox
│ │ ├── less_num_nonnum.lox
│ │ ├── less_or_equal_nonnum_num.lox
│ │ ├── less_or_equal_num_nonnum.lox
│ │ ├── multiply.lox
│ │ ├── multiply_nonnum_num.lox
│ │ ├── multiply_num_nonnum.lox
│ │ ├── negate.lox
│ │ ├── negate_nonnum.lox
│ │ ├── not.lox
│ │ ├── not_class.lox
│ │ ├── not_equals.lox
│ │ ├── subtract.lox
│ │ ├── subtract_nonnum_num.lox
│ │ └── subtract_num_nonnum.lox
│ ├── precedence.lox
│ ├── print/
│ │ └── missing_argument.lox
│ ├── regression/
│ │ ├── 394.lox
│ │ └── 40.lox
│ ├── return/
│ │ ├── after_else.lox
│ │ ├── after_if.lox
│ │ ├── after_while.lox
│ │ ├── at_top_level.lox
│ │ ├── in_function.lox
│ │ ├── in_method.lox
│ │ └── return_nil_if_no_value.lox
│ ├── scanning/
│ │ ├── identifiers.lox
│ │ ├── keywords.lox
│ │ ├── numbers.lox
│ │ ├── punctuators.lox
│ │ ├── strings.lox
│ │ └── whitespace.lox
│ ├── string/
│ │ ├── error_after_multiline.lox
│ │ ├── literals.lox
│ │ ├── multiline.lox
│ │ └── unterminated.lox
│ ├── super/
│ │ ├── bound_method.lox
│ │ ├── call_other_method.lox
│ │ ├── call_same_method.lox
│ │ ├── closure.lox
│ │ ├── constructor.lox
│ │ ├── extra_arguments.lox
│ │ ├── indirectly_inherited.lox
│ │ ├── missing_arguments.lox
│ │ ├── no_superclass_bind.lox
│ │ ├── no_superclass_call.lox
│ │ ├── no_superclass_method.lox
│ │ ├── parenthesized.lox
│ │ ├── reassign_superclass.lox
│ │ ├── super_at_top_level.lox
│ │ ├── super_in_closure_in_inherited_method.lox
│ │ ├── super_in_inherited_method.lox
│ │ ├── super_in_top_level_function.lox
│ │ ├── super_without_dot.lox
│ │ ├── super_without_name.lox
│ │ └── this_in_superclass_method.lox
│ ├── this/
│ │ ├── closure.lox
│ │ ├── nested_class.lox
│ │ ├── nested_closure.lox
│ │ ├── this_at_top_level.lox
│ │ ├── this_in_method.lox
│ │ └── this_in_top_level_function.lox
│ ├── unexpected_character.lox
│ ├── variable/
│ │ ├── collide_with_parameter.lox
│ │ ├── duplicate_local.lox
│ │ ├── duplicate_parameter.lox
│ │ ├── early_bound.lox
│ │ ├── in_middle_of_block.lox
│ │ ├── in_nested_block.lox
│ │ ├── local_from_method.lox
│ │ ├── redeclare_global.lox
│ │ ├── redefine_global.lox
│ │ ├── scope_reuse_in_different_blocks.lox
│ │ ├── shadow_and_local.lox
│ │ ├── shadow_global.lox
│ │ ├── shadow_local.lox
│ │ ├── undefined_global.lox
│ │ ├── undefined_local.lox
│ │ ├── uninitialized.lox
│ │ ├── unreached_undefined.lox
│ │ ├── use_false_as_var.lox
│ │ ├── use_global_in_initializer.lox
│ │ ├── use_local_in_initializer.lox
│ │ ├── use_nil_as_var.lox
│ │ └── use_this_as_var.lox
│ └── while/
│ ├── class_in_body.lox
│ ├── closure_in_body.lox
│ ├── fun_in_body.lox
│ ├── return_closure.lox
│ ├── return_inside.lox
│ ├── syntax.lox
│ └── var_in_body.lox
├── tool/
│ ├── analysis_options.yaml
│ ├── bin/
│ │ ├── benchmark.dart
│ │ ├── build.dart
│ │ ├── build_xml.dart
│ │ ├── compile_snippets.dart
│ │ ├── split_chapters.dart
│ │ ├── test.dart
│ │ └── tile_pages.dart
│ ├── lib/
│ │ └── src/
│ │ ├── book.dart
│ │ ├── code_tag.dart
│ │ ├── format.dart
│ │ ├── location.dart
│ │ ├── markdown/
│ │ │ ├── block_syntax.dart
│ │ │ ├── code_syntax.dart
│ │ │ ├── html_renderer.dart
│ │ │ ├── inline_syntax.dart
│ │ │ ├── markdown.dart
│ │ │ └── xml_renderer.dart
│ │ ├── mustache.dart
│ │ ├── page.dart
│ │ ├── page_parser.dart
│ │ ├── snippet.dart
│ │ ├── source_file_parser.dart
│ │ ├── split_chapter.dart
│ │ ├── syntax/
│ │ │ ├── grammar.dart
│ │ │ ├── highlighter.dart
│ │ │ ├── language.dart
│ │ │ └── rule.dart
│ │ ├── term.dart
│ │ └── text.dart
│ └── pubspec.yaml
└── util/
├── c.make
├── intellij/
│ ├── chap04_read.iml
│ ├── chap05_scanning.iml
│ ├── chap06_representing.iml
│ ├── chap07_parsing.iml
│ ├── chap08_evaluating.iml
│ ├── chap09_statements.iml
│ ├── chap10_control.iml
│ ├── chap11_functions.iml
│ ├── chap12_resolving.iml
│ ├── chap13_classes.iml
│ ├── chap14_inheritance.iml
│ ├── intellij.iml
│ ├── jlox.iml
│ ├── section_test.iml
│ └── snippet_test.iml
└── java.make
SYMBOL INDEX (929 symbols across 81 files)
FILE: c/chunk.c
function initChunk (line 12) | void initChunk(Chunk* chunk) {
function freeChunk (line 24) | void freeChunk(Chunk* chunk) {
function writeChunk (line 40) | void writeChunk(Chunk* chunk, uint8_t byte, int line) {
function addConstant (line 61) | int addConstant(Chunk* chunk, Value value) {
FILE: c/chunk.h
type OpCode (line 11) | typedef enum {
type Chunk (line 107) | typedef struct {
FILE: c/compiler.c
type Parser (line 24) | typedef struct {
type Precedence (line 36) | typedef enum {
type ParseRule (line 61) | typedef struct {
type Local (line 69) | typedef struct {
type Upvalue (line 78) | typedef struct {
type FunctionType (line 84) | typedef enum {
type Compiler (line 101) | typedef struct Compiler {
type ClassCompiler (line 119) | typedef struct ClassCompiler {
function Chunk (line 145) | static Chunk* currentChunk() {
function errorAt (line 152) | static void errorAt(Token* token, const char* message) {
function error (line 174) | static void error(const char* message) {
function errorAtCurrent (line 179) | static void errorAtCurrent(const char* message) {
function advance (line 185) | static void advance() {
function consume (line 197) | static void consume(TokenType type, const char* message) {
function check (line 207) | static bool check(TokenType type) {
function match (line 212) | static bool match(TokenType type) {
function emitByte (line 219) | static void emitByte(uint8_t byte) {
function emitBytes (line 224) | static void emitBytes(uint8_t byte1, uint8_t byte2) {
function emitLoop (line 230) | static void emitLoop(int loopStart) {
function emitJump (line 241) | static int emitJump(uint8_t instruction) {
function emitReturn (line 249) | static void emitReturn() {
function makeConstant (line 265) | static uint8_t makeConstant(Value value) {
function emitConstant (line 276) | static void emitConstant(Value value) {
function patchJump (line 281) | static void patchJump(int offset) {
function initCompiler (line 298) | static void initCompiler(Compiler* compiler, FunctionType type) {
function ObjFunction (line 345) | static ObjFunction* endCompiler() {
function beginScope (line 375) | static void beginScope() {
function endScope (line 380) | static void endScope() {
function identifierConstant (line 414) | static uint8_t identifierConstant(Token* name) {
function identifiersEqual (line 420) | static bool identifiersEqual(Token* a, Token* b) {
function resolveLocal (line 426) | static int resolveLocal(Compiler* compiler, Token* name) {
function addUpvalue (line 443) | static int addUpvalue(Compiler* compiler, uint8_t index,
function resolveUpvalue (line 469) | static int resolveUpvalue(Compiler* compiler, Token* name) {
function addLocal (line 491) | static void addLocal(Token name) {
function declareVariable (line 513) | static void declareVariable() {
function parseVariable (line 534) | static uint8_t parseVariable(const char* errorMessage) {
function markInitialized (line 546) | static void markInitialized() {
function defineVariable (line 555) | static void defineVariable(uint8_t global) {
function argumentList (line 569) | static uint8_t argumentList() {
function and_ (line 587) | static void and_(bool canAssign) {
function binary (line 601) | static void binary(bool canAssign) {
function call (line 625) | static void call(bool canAssign) {
function dot (line 631) | static void dot(bool canAssign) {
function literal (line 654) | static void literal(bool canAssign) {
function grouping (line 669) | static void grouping(bool canAssign) {
function number (line 680) | static void number(bool canAssign) {
function or_ (line 692) | static void or_(bool canAssign) {
function string (line 708) | static void string(bool canAssign) {
function namedVariable (line 718) | static void namedVariable(Token name, bool canAssign) {
function variable (line 776) | static void variable(bool canAssign) {
function Token (line 781) | static Token syntheticToken(const char* text) {
function super_ (line 789) | static void super_(bool canAssign) {
function this_ (line 823) | static void this_(bool canAssign) {
function unary (line 839) | static void unary(bool canAssign) {
function parsePrecedence (line 980) | static void parsePrecedence(Precedence precedence) {
function ParseRule (line 1022) | static ParseRule* getRule(TokenType type) {
function expression (line 1027) | static void expression() {
function block (line 1037) | static void block() {
function function (line 1046) | static void function(FunctionType type) {
function method (line 1085) | static void method() {
function classDeclaration (line 1111) | static void classDeclaration() {
function funDeclaration (line 1182) | static void funDeclaration() {
function varDeclaration (line 1190) | static void varDeclaration() {
function expressionStatement (line 1205) | static void expressionStatement() {
function forStatement (line 1212) | static void forStatement() {
function ifStatement (line 1279) | static void ifStatement() {
function printStatement (line 1308) | static void printStatement() {
function returnStatement (line 1315) | static void returnStatement() {
function whileStatement (line 1338) | static void whileStatement() {
function synchronize (line 1358) | static void synchronize() {
function declaration (line 1383) | static void declaration() {
function statement (line 1415) | static void statement() {
function ObjFunction (line 1455) | ObjFunction* compile(const char* source) {
function markCompilerRoots (line 1517) | void markCompilerRoots() {
FILE: c/debug.c
function disassembleChunk (line 12) | void disassembleChunk(Chunk* chunk, const char* name) {
function constantInstruction (line 20) | static int constantInstruction(const char* name, Chunk* chunk,
function invokeInstruction (line 32) | static int invokeInstruction(const char* name, Chunk* chunk,
function simpleInstruction (line 43) | static int simpleInstruction(const char* name, int offset) {
function byteInstruction (line 49) | static int byteInstruction(const char* name, Chunk* chunk,
function jumpInstruction (line 57) | static int jumpInstruction(const char* name, int sign,
function disassembleInstruction (line 67) | int disassembleInstruction(Chunk* chunk, int offset) {
FILE: c/main.c
function repl (line 20) | static void repl() {
function runFile (line 71) | static void runFile(const char* path) {
function main (line 81) | int main(int argc, const char* argv[]) {
FILE: c/memory.c
function markObject (line 53) | void markObject(Obj* object) {
function markValue (line 85) | void markValue(Value value) {
function markArray (line 90) | static void markArray(ValueArray* array) {
function blackenObject (line 97) | static void blackenObject(Obj* object) {
function freeObject (line 163) | static void freeObject(Obj* object) {
function markRoots (line 233) | static void markRoots() {
function traceReferences (line 264) | static void traceReferences() {
function sweep (line 272) | static void sweep() {
function collectGarbage (line 297) | void collectGarbage() {
function freeObjects (line 337) | void freeObjects() {
FILE: c/object.c
function Obj (line 19) | static Obj* allocateObject(size_t size, ObjType type) {
function ObjBoundMethod (line 41) | ObjBoundMethod* newBoundMethod(Value receiver,
function ObjClass (line 51) | ObjClass* newClass(ObjString* name) {
function ObjClosure (line 61) | ObjClosure* newClosure(ObjFunction* function) {
function ObjFunction (line 80) | ObjFunction* newFunction() {
function ObjInstance (line 92) | ObjInstance* newInstance(ObjClass* klass) {
function ObjNative (line 100) | ObjNative* newNative(NativeFn function) {
function ObjString (line 112) | static ObjString* allocateString(char* chars, int length,
function hashString (line 136) | static uint32_t hashString(const char* key, int length) {
function ObjString (line 146) | ObjString* takeString(char* chars, int length) {
function ObjString (line 165) | ObjString* copyString(const char* chars, int length) {
function ObjUpvalue (line 186) | ObjUpvalue* newUpvalue(Value* slot) {
function printFunction (line 199) | static void printFunction(ObjFunction* function) {
function printObject (line 210) | void printObject(Value value) {
FILE: c/object.h
type ObjType (line 65) | typedef enum {
type Obj (line 91) | struct Obj {
type ObjFunction (line 102) | typedef struct {
type Value (line 114) | typedef Value (*NativeFn)(int argCount, Value* args);
type ObjNative (line 116) | typedef struct {
type ObjString (line 123) | struct ObjString {
type ObjUpvalue (line 133) | typedef struct ObjUpvalue {
type ObjClosure (line 145) | typedef struct {
type ObjClass (line 156) | typedef struct {
type ObjInstance (line 166) | typedef struct {
type ObjBoundMethod (line 174) | typedef struct {
function isObjType (line 214) | static inline bool isObjType(Value value, ObjType type) {
FILE: c/scanner.c
type Scanner (line 8) | typedef struct {
function initScanner (line 16) | void initScanner(const char* source) {
function isAlpha (line 23) | static bool isAlpha(char c) {
function isDigit (line 30) | static bool isDigit(char c) {
function isAtEnd (line 35) | static bool isAtEnd() {
function advance (line 40) | static char advance() {
function peek (line 46) | static char peek() {
function peekNext (line 51) | static char peekNext() {
function match (line 57) | static bool match(char expected) {
function Token (line 65) | static Token makeToken(TokenType type) {
function Token (line 75) | static Token errorToken(const char* message) {
function skipWhitespace (line 85) | static void skipWhitespace() {
function TokenType (line 117) | static TokenType checkKeyword(int start, int length,
function TokenType (line 128) | static TokenType identifierType() {
function Token (line 170) | static Token identifier() {
function Token (line 176) | static Token number() {
function Token (line 191) | static Token string() {
function Token (line 205) | Token scanToken() {
FILE: c/scanner.h
type TokenType (line 6) | typedef enum {
type Token (line 30) | typedef struct {
FILE: c/table.c
function initTable (line 14) | void initTable(Table* table) {
function freeTable (line 20) | void freeTable(Table* table) {
function Entry (line 30) | static Entry* findEntry(Entry* entries, int capacity,
function tableGet (line 74) | bool tableGet(Table* table, ObjString* key, Value* value) {
function adjustCapacity (line 85) | static void adjustCapacity(Table* table, int capacity) {
function tableSet (line 117) | bool tableSet(Table* table, ObjString* key, Value value) {
function tableDelete (line 140) | bool tableDelete(Table* table, ObjString* key) {
function tableAddAll (line 154) | void tableAddAll(Table* from, Table* to) {
function ObjString (line 164) | ObjString* tableFindString(Table* table, const char* chars,
function tableRemoveWhite (line 196) | void tableRemoveWhite(Table* table) {
function markTable (line 206) | void markTable(Table* table) {
FILE: c/table.h
type Entry (line 9) | typedef struct {
type Table (line 15) | typedef struct {
FILE: c/value.c
function initValueArray (line 13) | void initValueArray(ValueArray* array) {
function writeValueArray (line 19) | void writeValueArray(ValueArray* array, Value value) {
function freeValueArray (line 32) | void freeValueArray(ValueArray* array) {
function printValue (line 38) | void printValue(Value value) {
function valuesEqual (line 76) | bool valuesEqual(Value a, Value b) {
FILE: c/value.h
type Obj (line 12) | typedef struct Obj Obj;
type ObjString (line 14) | typedef struct ObjString ObjString;
type Value (line 34) | typedef uint64_t Value;
function valueToNum (line 80) | static inline double valueToNum(Value value) {
function Value (line 88) | static inline Value numToValue(double num) {
type ValueType (line 99) | typedef enum {
type Value (line 113) | typedef struct {
type ValueArray (line 156) | typedef struct {
FILE: c/vm.c
function Value (line 30) | static Value clockNative(int argCount, Value* args) {
function resetStack (line 35) | static void resetStack() {
function runtimeError (line 46) | static void runtimeError(const char* format, ...) {
function defineNative (line 89) | static void defineNative(const char* name, NativeFn function) {
function initVM (line 98) | void initVM() {
function freeVM (line 135) | void freeVM() {
function push (line 150) | void push(Value value) {
function Value (line 156) | Value pop() {
function Value (line 162) | static Value peek(int distance) {
function call (line 171) | static bool call(ObjClosure* closure, int argCount) {
function callValue (line 209) | static bool callValue(Value callee, int argCount) {
function invokeFromClass (line 267) | static bool invokeFromClass(ObjClass* klass, ObjString* name,
function invoke (line 278) | static bool invoke(ObjString* name, int argCount) {
function bindMethod (line 302) | static bool bindMethod(ObjClass* klass, ObjString* name) {
function ObjUpvalue (line 317) | static ObjUpvalue* captureUpvalue(Value* local) {
function closeUpvalues (line 346) | static void closeUpvalues(Value* last) {
function defineMethod (line 357) | static void defineMethod(ObjString* name) {
function isFalsey (line 365) | static bool isFalsey(Value value) {
function concatenate (line 370) | static void concatenate() {
function InterpretResult (line 395) | static InterpretResult run() {
function hack (line 866) | void hack(bool b) {
function InterpretResult (line 881) | InterpretResult interpret(const char* source) {
FILE: c/vm.h
type CallFrame (line 29) | typedef struct {
type VM (line 41) | typedef struct {
type InterpretResult (line 85) | typedef enum {
FILE: java/com/craftinginterpreters/lox/AstPrinter.java
class AstPrinter (line 12) | class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
method print (line 14) | String print(Expr expr) {
method print (line 19) | String print(Stmt stmt) {
method visitBlockStmt (line 25) | @Override
method visitClassStmt (line 40) | @Override
method visitExpressionStmt (line 61) | @Override
method visitFunctionStmt (line 68) | @Override
method visitIfStmt (line 90) | @Override
method visitPrintStmt (line 102) | @Override
method visitReturnStmt (line 109) | @Override
method visitVarStmt (line 117) | @Override
method visitWhileStmt (line 128) | @Override
method visitAssignExpr (line 135) | @Override
method visitBinaryExpr (line 141) | @Override
method visitCallExpr (line 148) | @Override
method visitGetExpr (line 155) | @Override
method visitGroupingExpr (line 161) | @Override
method visitLiteralExpr (line 166) | @Override
method visitLogicalExpr (line 173) | @Override
method visitSetExpr (line 180) | @Override
method visitSuperExpr (line 188) | @Override
method visitThisExpr (line 195) | @Override
method visitUnaryExpr (line 201) | @Override
method visitVariableExpr (line 207) | @Override
method parenthesize (line 214) | private String parenthesize(String name, Expr... exprs) {
method parenthesize2 (line 231) | private String parenthesize2(String name, Object... parts) {
method transform (line 241) | private void transform(StringBuilder builder, Object... parts) {
FILE: java/com/craftinginterpreters/lox/Environment.java
class Environment (line 7) | class Environment {
method Environment (line 13) | Environment() {
method Environment (line 17) | Environment(Environment enclosing) {
method get (line 23) | Object get(Token name) {
method assign (line 38) | void assign(Token name, Object value) {
method define (line 56) | void define(String name, Object value) {
method ancestor (line 61) | Environment ancestor(int distance) {
method getAt (line 71) | Object getAt(int distance, String name) {
method assignAt (line 76) | void assignAt(int distance, Token name, Object value) {
method toString (line 81) | @Override
FILE: java/com/craftinginterpreters/lox/Expr.java
class Expr (line 6) | abstract class Expr {
type Visitor (line 7) | interface Visitor<R> {
method visitAssignExpr (line 8) | R visitAssignExpr(Assign expr);
method visitBinaryExpr (line 9) | R visitBinaryExpr(Binary expr);
method visitCallExpr (line 10) | R visitCallExpr(Call expr);
method visitGetExpr (line 11) | R visitGetExpr(Get expr);
method visitGroupingExpr (line 12) | R visitGroupingExpr(Grouping expr);
method visitLiteralExpr (line 13) | R visitLiteralExpr(Literal expr);
method visitLogicalExpr (line 14) | R visitLogicalExpr(Logical expr);
method visitSetExpr (line 15) | R visitSetExpr(Set expr);
method visitSuperExpr (line 16) | R visitSuperExpr(Super expr);
method visitThisExpr (line 17) | R visitThisExpr(This expr);
method visitUnaryExpr (line 18) | R visitUnaryExpr(Unary expr);
method visitVariableExpr (line 19) | R visitVariableExpr(Variable expr);
class Assign (line 24) | static class Assign extends Expr {
method Assign (line 25) | Assign(Token name, Expr value) {
method accept (line 30) | @Override
class Binary (line 40) | static class Binary extends Expr {
method Binary (line 41) | Binary(Expr left, Token operator, Expr right) {
method accept (line 47) | @Override
class Call (line 58) | static class Call extends Expr {
method Call (line 59) | Call(Expr callee, Token paren, List<Expr> arguments) {
method accept (line 65) | @Override
class Get (line 76) | static class Get extends Expr {
method Get (line 77) | Get(Expr object, Token name) {
method accept (line 82) | @Override
class Grouping (line 92) | static class Grouping extends Expr {
method Grouping (line 93) | Grouping(Expr expression) {
method accept (line 97) | @Override
class Literal (line 106) | static class Literal extends Expr {
method Literal (line 107) | Literal(Object value) {
method accept (line 111) | @Override
class Logical (line 120) | static class Logical extends Expr {
method Logical (line 121) | Logical(Expr left, Token operator, Expr right) {
method accept (line 127) | @Override
class Set (line 138) | static class Set extends Expr {
method Set (line 139) | Set(Expr object, Token name, Expr value) {
method accept (line 145) | @Override
class Super (line 156) | static class Super extends Expr {
method Super (line 157) | Super(Token keyword, Token method) {
method accept (line 162) | @Override
class This (line 172) | static class This extends Expr {
method This (line 173) | This(Token keyword) {
method accept (line 177) | @Override
class Unary (line 186) | static class Unary extends Expr {
method Unary (line 187) | Unary(Token operator, Expr right) {
method accept (line 192) | @Override
class Variable (line 202) | static class Variable extends Expr {
method Variable (line 203) | Variable(Token name) {
method accept (line 207) | @Override
method accept (line 216) | abstract <R> R accept(Visitor<R> visitor);
FILE: java/com/craftinginterpreters/lox/Interpreter.java
class Interpreter (line 21) | class Interpreter implements Expr.Visitor<Object>,
method Interpreter (line 38) | Interpreter() {
method interpret (line 66) | void interpret(List<Stmt> statements) {
method evaluate (line 77) | private Object evaluate(Expr expr) {
method execute (line 82) | private void execute(Stmt stmt) {
method resolve (line 87) | void resolve(Expr expr, int depth) {
method executeBlock (line 92) | void executeBlock(List<Stmt> statements,
method visitBlockStmt (line 107) | @Override
method visitClassStmt (line 114) | @Override
method visitExpressionStmt (line 172) | @Override
method visitFunctionStmt (line 179) | @Override
method visitIfStmt (line 196) | @Override
method visitPrintStmt (line 207) | @Override
method visitReturnStmt (line 215) | @Override
method visitVarStmt (line 224) | @Override
method visitWhileStmt (line 236) | @Override
method visitAssignExpr (line 245) | @Override
method visitBinaryExpr (line 265) | @Override
method visitCallExpr (line 337) | @Override
method visitGetExpr (line 366) | @Override
method visitGroupingExpr (line 378) | @Override
method visitLiteralExpr (line 384) | @Override
method visitLogicalExpr (line 390) | @Override
method visitSetExpr (line 404) | @Override
method visitSuperExpr (line 419) | @Override
method visitThisExpr (line 445) | @Override
method visitUnaryExpr (line 451) | @Override
method visitVariableExpr (line 472) | @Override
method lookUpVariable (line 482) | private Object lookUpVariable(Token name, Expr expr) {
method checkNumberOperand (line 493) | private void checkNumberOperand(Token operator, Object operand) {
method checkNumberOperands (line 499) | private void checkNumberOperands(Token operator,
method isTruthy (line 507) | private boolean isTruthy(Object object) {
method isEqual (line 514) | private boolean isEqual(Object a, Object b) {
method stringify (line 522) | private String stringify(Object object) {
FILE: java/com/craftinginterpreters/lox/Lox.java
class Lox (line 12) | public class Lox {
method main (line 23) | public static void main(String[] args) throws IOException {
method runFile (line 34) | private static void runFile(String path) throws IOException {
method runPrompt (line 48) | private static void runPrompt() throws IOException {
method run (line 64) | private static void run(String source) {
method error (line 109) | static void error(int line, String message) {
method report (line 113) | private static void report(int line, String where,
method error (line 121) | static void error(Token token, String message) {
method runtimeError (line 130) | static void runtimeError(RuntimeError error) {
FILE: java/com/craftinginterpreters/lox/LoxCallable.java
type LoxCallable (line 6) | interface LoxCallable {
method arity (line 8) | int arity();
method call (line 10) | Object call(Interpreter interpreter, List<Object> arguments);
FILE: java/com/craftinginterpreters/lox/LoxClass.java
class LoxClass (line 11) | class LoxClass implements LoxCallable {
method LoxClass (line 30) | LoxClass(String name, LoxClass superclass,
method findMethod (line 39) | LoxFunction findMethod(String name) {
method toString (line 54) | @Override
method call (line 59) | @Override
method arity (line 73) | @Override
FILE: java/com/craftinginterpreters/lox/LoxFunction.java
class LoxFunction (line 6) | class LoxFunction implements LoxCallable {
method LoxFunction (line 21) | LoxFunction(Stmt.Function declaration, Environment closure,
method bind (line 31) | LoxFunction bind(LoxInstance instance) {
method toString (line 44) | @Override
method arity (line 50) | @Override
method call (line 56) | @Override
FILE: java/com/craftinginterpreters/lox/LoxInstance.java
class LoxInstance (line 7) | class LoxInstance {
method LoxInstance (line 13) | LoxInstance(LoxClass klass) {
method get (line 18) | Object get(Token name) {
method set (line 38) | void set(Token name, Object value) {
method toString (line 42) | @Override
FILE: java/com/craftinginterpreters/lox/Parser.java
class Parser (line 14) | class Parser {
class ParseError (line 16) | private static class ParseError extends RuntimeException {}
method Parser (line 22) | Parser(List<Token> tokens) {
method parse (line 35) | List<Stmt> parse() {
method expression (line 50) | private Expr expression() {
method declaration (line 60) | private Stmt declaration() {
method classDeclaration (line 78) | private Stmt classDeclaration() {
method statement (line 107) | private Stmt statement() {
method forStatement (line 129) | private Stmt forStatement() {
method ifStatement (line 189) | private Stmt ifStatement() {
method printStatement (line 204) | private Stmt printStatement() {
method returnStatement (line 211) | private Stmt returnStatement() {
method varDeclaration (line 223) | private Stmt varDeclaration() {
method whileStatement (line 236) | private Stmt whileStatement() {
method expressionStatement (line 246) | private Stmt expressionStatement() {
method function (line 253) | private Stmt.Function function(String kind) {
method block (line 279) | private List<Stmt> block() {
method assignment (line 291) | private Expr assignment() {
method or (line 320) | private Expr or() {
method and (line 333) | private Expr and() {
method equality (line 346) | private Expr equality() {
method comparison (line 359) | private Expr comparison() {
method term (line 372) | private Expr term() {
method factor (line 385) | private Expr factor() {
method unary (line 398) | private Expr unary() {
method finishCall (line 414) | private Expr finishCall(Expr callee) {
method call (line 434) | private Expr call() {
method primary (line 455) | private Expr primary() {
method match (line 496) | private boolean match(TokenType... types) {
method consume (line 508) | private Token consume(TokenType type, String message) {
method check (line 515) | private boolean check(TokenType type) {
method advance (line 521) | private Token advance() {
method isAtEnd (line 527) | private boolean isAtEnd() {
method peek (line 531) | private Token peek() {
method previous (line 535) | private Token previous() {
method error (line 540) | private ParseError error(Token token, String message) {
method synchronize (line 546) | private void synchronize() {
FILE: java/com/craftinginterpreters/lox/Resolver.java
class Resolver (line 9) | class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
method Resolver (line 18) | Resolver(Interpreter interpreter) {
type FunctionType (line 22) | private enum FunctionType {
type ClassType (line 38) | private enum ClassType {
method resolve (line 53) | void resolve(List<Stmt> statements) {
method visitBlockStmt (line 60) | @Override
method visitClassStmt (line 69) | @Override
method visitExpressionStmt (line 136) | @Override
method visitFunctionStmt (line 143) | @Override
method visitIfStmt (line 158) | @Override
method visitPrintStmt (line 167) | @Override
method visitReturnStmt (line 174) | @Override
method visitVarStmt (line 197) | @Override
method visitWhileStmt (line 208) | @Override
method visitAssignExpr (line 216) | @Override
method visitBinaryExpr (line 224) | @Override
method visitCallExpr (line 232) | @Override
method visitGetExpr (line 244) | @Override
method visitGroupingExpr (line 251) | @Override
method visitLiteralExpr (line 258) | @Override
method visitLogicalExpr (line 264) | @Override
method visitSetExpr (line 272) | @Override
method visitSuperExpr (line 280) | @Override
method visitThisExpr (line 297) | @Override
method visitUnaryExpr (line 313) | @Override
method visitVariableExpr (line 320) | @Override
method resolve (line 333) | private void resolve(Stmt stmt) {
method resolve (line 338) | private void resolve(Expr expr) {
method resolveFunction (line 347) | private void resolveFunction(
method beginScope (line 366) | private void beginScope() {
method endScope (line 371) | private void endScope() {
method declare (line 376) | private void declare(Token name) {
method define (line 391) | private void define(Token name) {
method resolveLocal (line 397) | private void resolveLocal(Expr expr, Token name) {
FILE: java/com/craftinginterpreters/lox/Return.java
class Return (line 4) | class Return extends RuntimeException {
method Return (line 7) | Return(Object value) {
FILE: java/com/craftinginterpreters/lox/RuntimeError.java
class RuntimeError (line 4) | class RuntimeError extends RuntimeException {
method RuntimeError (line 7) | RuntimeError(Token token, String message) {
FILE: java/com/craftinginterpreters/lox/Scanner.java
class Scanner (line 11) | class Scanner {
method Scanner (line 43) | Scanner(String source) {
method scanTokens (line 47) | List<Token> scanTokens() {
method scanToken (line 59) | private void scanToken() {
method identifier (line 135) | private void identifier() {
method number (line 150) | private void number() {
method string (line 166) | private void string() {
method match (line 186) | private boolean match(char expected) {
method peek (line 195) | private char peek() {
method peekNext (line 201) | private char peekNext() {
method isAlpha (line 207) | private boolean isAlpha(char c) {
method isAlphaNumeric (line 213) | private boolean isAlphaNumeric(char c) {
method isDigit (line 218) | private boolean isDigit(char c) {
method isAtEnd (line 223) | private boolean isAtEnd() {
method advance (line 228) | private char advance() {
method addToken (line 232) | private void addToken(TokenType type) {
method addToken (line 236) | private void addToken(TokenType type, Object literal) {
FILE: java/com/craftinginterpreters/lox/Stmt.java
class Stmt (line 6) | abstract class Stmt {
type Visitor (line 7) | interface Visitor<R> {
method visitBlockStmt (line 8) | R visitBlockStmt(Block stmt);
method visitClassStmt (line 9) | R visitClassStmt(Class stmt);
method visitExpressionStmt (line 10) | R visitExpressionStmt(Expression stmt);
method visitFunctionStmt (line 11) | R visitFunctionStmt(Function stmt);
method visitIfStmt (line 12) | R visitIfStmt(If stmt);
method visitPrintStmt (line 13) | R visitPrintStmt(Print stmt);
method visitReturnStmt (line 14) | R visitReturnStmt(Return stmt);
method visitVarStmt (line 15) | R visitVarStmt(Var stmt);
method visitWhileStmt (line 16) | R visitWhileStmt(While stmt);
class Block (line 21) | static class Block extends Stmt {
method Block (line 22) | Block(List<Stmt> statements) {
method accept (line 26) | @Override
class Class (line 35) | static class Class extends Stmt {
method Class (line 36) | Class(Token name,
method accept (line 44) | @Override
class Expression (line 55) | static class Expression extends Stmt {
method Expression (line 56) | Expression(Expr expression) {
method accept (line 60) | @Override
class Function (line 69) | static class Function extends Stmt {
method Function (line 70) | Function(Token name, List<Token> params, List<Stmt> body) {
method accept (line 76) | @Override
class If (line 87) | static class If extends Stmt {
method If (line 88) | If(Expr condition, Stmt thenBranch, Stmt elseBranch) {
method accept (line 94) | @Override
class Print (line 105) | static class Print extends Stmt {
method Print (line 106) | Print(Expr expression) {
method accept (line 110) | @Override
class Return (line 119) | static class Return extends Stmt {
method Return (line 120) | Return(Token keyword, Expr value) {
method accept (line 125) | @Override
class Var (line 135) | static class Var extends Stmt {
method Var (line 136) | Var(Token name, Expr initializer) {
method accept (line 141) | @Override
class While (line 151) | static class While extends Stmt {
method While (line 152) | While(Expr condition, Stmt body) {
method accept (line 157) | @Override
method accept (line 167) | abstract <R> R accept(Visitor<R> visitor);
FILE: java/com/craftinginterpreters/lox/Token.java
class Token (line 4) | class Token {
method Token (line 10) | Token(TokenType type, String lexeme, Object literal, int line) {
method toString (line 17) | public String toString() {
FILE: java/com/craftinginterpreters/lox/TokenType.java
type TokenType (line 4) | enum TokenType {
FILE: java/com/craftinginterpreters/tool/GenerateAst.java
class GenerateAst (line 9) | public class GenerateAst {
method main (line 10) | public static void main(String[] args) throws IOException {
method defineAst (line 93) | private static void defineAst(
method defineVisitor (line 139) | private static void defineVisitor(
method defineType (line 153) | private static void defineType(
type PastryVisitor (line 210) | interface PastryVisitor {
method visitBeignet (line 211) | void visitBeignet(Beignet beignet);
method visitCruller (line 212) | void visitCruller(Cruller cruller);
class Pastry (line 216) | abstract class Pastry {
method accept (line 218) | abstract void accept(PastryVisitor visitor);
class Beignet (line 222) | class Beignet extends Pastry {
method accept (line 224) | @Override
class Cruller (line 231) | class Cruller extends Pastry {
method accept (line 233) | @Override
FILE: note/answers/chapter01_introduction/2/Hello.java
class Hello (line 1) | public class Hello {
method main (line 2) | public static void main(String[] args) {
FILE: note/answers/chapter01_introduction/3/linked_list.c
type Node (line 5) | typedef struct sNode {
function insert (line 13) | void insert(Node** list, Node* prev, const char* string) {
function Node (line 32) | Node* find(Node* list, const char* string) {
function delete (line 45) | void delete(Node** list, Node* node) {
function dump (line 57) | void dump(Node* list) {
function main (line 65) | int main(int argc, const char* argv[]) {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/AstPrinter.java
class AstPrinter (line 4) | class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
method print (line 5) | String print(Expr expr) {
method print (line 9) | String print(Stmt stmt) {
method visitBlockStmt (line 12) | @Override
method visitExpressionStmt (line 25) | @Override
method visitFunctionStmt (line 30) | @Override
method visitIfStmt (line 50) | @Override
method visitPrintStmt (line 60) | @Override
method visitReturnStmt (line 65) | @Override
method visitVarStmt (line 71) | @Override
method visitWhileStmt (line 80) | @Override
method visitAssignExpr (line 85) | @Override
method visitBinaryExpr (line 90) | @Override
method visitCallExpr (line 95) | @Override
method visitGroupingExpr (line 100) | @Override
method visitLiteralExpr (line 105) | @Override
method visitLogicalExpr (line 111) | @Override
method visitUnaryExpr (line 116) | @Override
method visitVariableExpr (line 121) | @Override
method parenthesize (line 125) | private String parenthesize(String name, Expr... exprs) {
method parenthesize2 (line 140) | private String parenthesize2(String name, Object... parts) {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Environment.java
class Environment (line 6) | class Environment {
method Environment (line 10) | Environment() {
method Environment (line 14) | Environment(Environment enclosing) {
method define (line 18) | void define(Object value) {
method getAt (line 22) | Object getAt(int distance, int slot) {
method assignAt (line 31) | void assignAt(int distance, int slot, Object value) {
method toString (line 39) | @Override
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Expr.java
class Expr (line 5) | abstract class Expr {
type Visitor (line 6) | interface Visitor<R> {
method visitAssignExpr (line 7) | R visitAssignExpr(Assign expr);
method visitBinaryExpr (line 8) | R visitBinaryExpr(Binary expr);
method visitCallExpr (line 9) | R visitCallExpr(Call expr);
method visitGroupingExpr (line 10) | R visitGroupingExpr(Grouping expr);
method visitLiteralExpr (line 11) | R visitLiteralExpr(Literal expr);
method visitLogicalExpr (line 12) | R visitLogicalExpr(Logical expr);
method visitUnaryExpr (line 13) | R visitUnaryExpr(Unary expr);
method visitVariableExpr (line 14) | R visitVariableExpr(Variable expr);
class Assign (line 17) | static class Assign extends Expr {
method Assign (line 18) | Assign(Token name, Expr value) {
method accept (line 23) | <R> R accept(Visitor<R> visitor) {
class Binary (line 31) | static class Binary extends Expr {
method Binary (line 32) | Binary(Expr left, Token operator, Expr right) {
method accept (line 38) | <R> R accept(Visitor<R> visitor) {
class Call (line 47) | static class Call extends Expr {
method Call (line 48) | Call(Expr callee, Token paren, List<Expr> arguments) {
method accept (line 54) | <R> R accept(Visitor<R> visitor) {
class Grouping (line 63) | static class Grouping extends Expr {
method Grouping (line 64) | Grouping(Expr expression) {
method accept (line 68) | <R> R accept(Visitor<R> visitor) {
class Literal (line 75) | static class Literal extends Expr {
method Literal (line 76) | Literal(Object value) {
method accept (line 80) | <R> R accept(Visitor<R> visitor) {
class Logical (line 87) | static class Logical extends Expr {
method Logical (line 88) | Logical(Expr left, Token operator, Expr right) {
method accept (line 94) | <R> R accept(Visitor<R> visitor) {
class Unary (line 103) | static class Unary extends Expr {
method Unary (line 104) | Unary(Token operator, Expr right) {
method accept (line 109) | <R> R accept(Visitor<R> visitor) {
class Variable (line 117) | static class Variable extends Expr {
method Variable (line 118) | Variable(Token name) {
method accept (line 122) | <R> R accept(Visitor<R> visitor) {
method accept (line 129) | abstract <R> R accept(Visitor<R> visitor);
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Interpreter.java
class Interpreter (line 8) | class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
method Interpreter (line 14) | Interpreter() {
method interpret (line 28) | void interpret(List<Stmt> statements) {
method evaluate (line 37) | private Object evaluate(Expr expr) {
method execute (line 40) | private void execute(Stmt stmt) {
method resolve (line 43) | void resolve(Expr expr, int depth, int slot) {
method executeBlock (line 47) | void executeBlock(List<Stmt> statements, Environment environment) {
method visitBlockStmt (line 59) | @Override
method visitExpressionStmt (line 64) | @Override
method visitFunctionStmt (line 69) | @Override
method visitIfStmt (line 75) | @Override
method visitPrintStmt (line 84) | @Override
method visitReturnStmt (line 90) | @Override
method visitVarStmt (line 97) | @Override
method visitWhileStmt (line 107) | @Override
method visitAssignExpr (line 114) | @Override
method visitBinaryExpr (line 132) | @Override
method visitCallExpr (line 177) | @Override
method visitGroupingExpr (line 200) | @Override
method visitLiteralExpr (line 204) | @Override
method visitLogicalExpr (line 208) | @Override
method visitUnaryExpr (line 220) | @Override
method visitVariableExpr (line 235) | @Override
method lookUpVariable (line 239) | private Object lookUpVariable(Token name, Expr expr) {
method checkNumberOperand (line 252) | private void checkNumberOperand(Token operator, Object operand) {
method checkNumberOperands (line 256) | private void checkNumberOperands(Token operator,
method isTruthy (line 262) | private boolean isTruthy(Object object) {
method isEqual (line 267) | private boolean isEqual(Object a, Object b) {
method stringify (line 274) | private String stringify(Object object) {
method define (line 288) | private void define(Token name, Object value) {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Lox.java
class Lox (line 11) | public class Lox {
method main (line 16) | public static void main(String[] args) throws IOException {
method runFile (line 25) | private static void runFile(String path) throws IOException {
method runPrompt (line 33) | private static void runPrompt() throws IOException {
method run (line 43) | private static void run(String source) {
method error (line 60) | static void error(int line, String message) {
method report (line 64) | static private void report(int line, String where, String message) {
method error (line 69) | static void error(Token token, String message) {
method runtimeError (line 76) | static void runtimeError(RuntimeError error) {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/LoxCallable.java
type LoxCallable (line 5) | interface LoxCallable {
method arity (line 6) | int arity();
method call (line 7) | Object call(Interpreter interpreter, List<Object> arguments);
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/LoxFunction.java
class LoxFunction (line 5) | class LoxFunction implements LoxCallable {
method LoxFunction (line 9) | LoxFunction(Stmt.Function declaration, Environment closure) {
method toString (line 13) | @Override
method arity (line 17) | @Override
method call (line 21) | @Override
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Parser.java
class Parser (line 9) | class Parser {
class ParseError (line 10) | private static class ParseError extends RuntimeException {}
method Parser (line 15) | Parser(List<Token> tokens) {
method parse (line 18) | List<Stmt> parse() {
method expression (line 26) | private Expr expression() {
method declaration (line 29) | private Stmt declaration() {
method statement (line 40) | private Stmt statement() {
method forStatement (line 50) | private Stmt forStatement() {
method ifStatement (line 90) | private Stmt ifStatement() {
method printStatement (line 103) | private Stmt printStatement() {
method returnStatement (line 108) | private Stmt returnStatement() {
method varDeclaration (line 118) | private Stmt varDeclaration() {
method whileStatement (line 129) | private Stmt whileStatement() {
method expressionStatement (line 137) | private Stmt expressionStatement() {
method function (line 142) | private Stmt.Function function(String kind) {
method block (line 161) | private List<Stmt> block() {
method assignment (line 171) | private Expr assignment() {
method or (line 188) | private Expr or() {
method and (line 199) | private Expr and() {
method equality (line 210) | private Expr equality() {
method comparison (line 221) | private Expr comparison() {
method addition (line 232) | private Expr addition() {
method multiplication (line 244) | private Expr multiplication() {
method unary (line 255) | private Expr unary() {
method finishCall (line 264) | private Expr finishCall(Expr callee) {
method call (line 279) | private Expr call() {
method primary (line 293) | private Expr primary() {
method match (line 314) | private boolean match(TokenType... types) {
method consume (line 324) | private Token consume(TokenType type, String message) {
method check (line 329) | private boolean check(TokenType tokenType) {
method advance (line 333) | private Token advance() {
method isAtEnd (line 337) | private boolean isAtEnd() {
method peek (line 341) | private Token peek() {
method previous (line 345) | private Token previous() {
method error (line 348) | private ParseError error(Token token, String message) {
method synchronize (line 352) | private void synchronize() {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Resolver.java
class Resolver (line 8) | class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
method Resolver (line 13) | Resolver(Interpreter interpreter) {
class Variable (line 16) | private class Variable {
method Variable (line 20) | private Variable(int slot) {
type FunctionType (line 24) | private enum FunctionType {
method resolve (line 28) | void resolve(List<Stmt> statements) {
method visitBlockStmt (line 33) | @Override
method visitExpressionStmt (line 40) | @Override
method visitFunctionStmt (line 45) | @Override
method visitIfStmt (line 53) | @Override
method visitPrintStmt (line 60) | @Override
method visitReturnStmt (line 65) | @Override
method visitVarStmt (line 77) | @Override
method visitWhileStmt (line 86) | @Override
method visitAssignExpr (line 92) | @Override
method visitBinaryExpr (line 98) | @Override
method visitCallExpr (line 104) | @Override
method visitGroupingExpr (line 114) | @Override
method visitLiteralExpr (line 119) | @Override
method visitLogicalExpr (line 123) | @Override
method visitUnaryExpr (line 129) | @Override
method visitVariableExpr (line 134) | @Override
method resolve (line 146) | private void resolve(Stmt stmt) {
method resolve (line 149) | private void resolve(Expr expr) {
method resolveFunction (line 152) | private void resolveFunction(Stmt.Function function, FunctionType type) {
method beginScope (line 165) | private void beginScope() {
method endScope (line 168) | private void endScope() {
method declare (line 171) | private void declare(Token name) {
method define (line 182) | private void define(Token name) {
method resolveLocal (line 186) | private void resolveLocal(Expr expr, Token name) {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Return.java
class Return (line 3) | class Return extends RuntimeException {
method Return (line 6) | Return(Object value) {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/RuntimeError.java
class RuntimeError (line 3) | class RuntimeError extends RuntimeException {
method RuntimeError (line 6) | RuntimeError(Token token, String message) {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Scanner.java
class Scanner (line 10) | class Scanner {
method Scanner (line 38) | Scanner(String source) {
method scanTokens (line 41) | List<Token> scanTokens() {
method scanToken (line 51) | private void scanToken() {
method identifier (line 100) | private void identifier() {
method number (line 110) | private void number() {
method string (line 124) | private void string() {
method match (line 143) | private boolean match(char expected) {
method peek (line 150) | private char peek() {
method peekNext (line 154) | private char peekNext() {
method isAlpha (line 158) | private boolean isAlpha(char c) {
method isAlphaNumeric (line 164) | private boolean isAlphaNumeric(char c) {
method isDigit (line 167) | private boolean isDigit(char c) {
method isAtEnd (line 170) | private boolean isAtEnd() {
method advance (line 173) | private char advance() {
method addToken (line 178) | private void addToken(TokenType type) {
method addToken (line 182) | private void addToken(TokenType type, Object literal) {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Stmt.java
class Stmt (line 5) | abstract class Stmt {
type Visitor (line 6) | interface Visitor<R> {
method visitBlockStmt (line 7) | R visitBlockStmt(Block stmt);
method visitExpressionStmt (line 8) | R visitExpressionStmt(Expression stmt);
method visitFunctionStmt (line 9) | R visitFunctionStmt(Function stmt);
method visitIfStmt (line 10) | R visitIfStmt(If stmt);
method visitPrintStmt (line 11) | R visitPrintStmt(Print stmt);
method visitReturnStmt (line 12) | R visitReturnStmt(Return stmt);
method visitVarStmt (line 13) | R visitVarStmt(Var stmt);
method visitWhileStmt (line 14) | R visitWhileStmt(While stmt);
class Block (line 17) | static class Block extends Stmt {
method Block (line 18) | Block(List<Stmt> statements) {
method accept (line 22) | <R> R accept(Visitor<R> visitor) {
class Expression (line 29) | static class Expression extends Stmt {
method Expression (line 30) | Expression(Expr expression) {
method accept (line 34) | <R> R accept(Visitor<R> visitor) {
class Function (line 41) | static class Function extends Stmt {
method Function (line 42) | Function(Token name, List<Token> parameters, List<Stmt> body) {
method accept (line 48) | <R> R accept(Visitor<R> visitor) {
class If (line 57) | static class If extends Stmt {
method If (line 58) | If(Expr condition, Stmt thenBranch, Stmt elseBranch) {
method accept (line 64) | <R> R accept(Visitor<R> visitor) {
class Print (line 73) | static class Print extends Stmt {
method Print (line 74) | Print(Expr expression) {
method accept (line 78) | <R> R accept(Visitor<R> visitor) {
class Return (line 85) | static class Return extends Stmt {
method Return (line 86) | Return(Token keyword, Expr value) {
method accept (line 91) | <R> R accept(Visitor<R> visitor) {
class Var (line 99) | static class Var extends Stmt {
method Var (line 100) | Var(Token name, Expr initializer) {
method accept (line 105) | <R> R accept(Visitor<R> visitor) {
class While (line 113) | static class While extends Stmt {
method While (line 114) | While(Expr condition, Stmt body) {
method accept (line 119) | <R> R accept(Visitor<R> visitor) {
method accept (line 127) | abstract <R> R accept(Visitor<R> visitor);
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Token.java
class Token (line 3) | class Token {
method Token (line 9) | Token(TokenType type, String lexeme, Object literal, int line) {
method toString (line 16) | public String toString() {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/TokenType.java
type TokenType (line 3) | enum TokenType {
FILE: note/answers/chapter11_resolving/4/com/craftinginterpreters/tool/GenerateAst.java
class GenerateAst (line 8) | public class GenerateAst {
method main (line 9) | public static void main(String[] args) throws IOException {
method defineAst (line 37) | private static void defineAst(
method defineVisitor (line 65) | private static void defineVisitor(
method defineType (line 77) | private static void defineType(
type PastryVisitor (line 111) | interface PastryVisitor {
method visitBeignet (line 112) | void visitBeignet(Beignet beignet);
method visitCruller (line 113) | void visitCruller(Cruller cruller);
class Pastry (line 115) | abstract class Pastry {
method accept (line 116) | abstract void accept(PastryVisitor visitor);
class Beignet (line 119) | class Beignet extends Pastry {
method accept (line 120) | @Override
class Cruller (line 126) | class Cruller extends Pastry {
method accept (line 127) | @Override
FILE: site/script.js
function refreshAsides (line 37) | function refreshAsides() {
FILE: tool/bin/benchmark.dart
function main (line 6) | void main(List<String> arguments)
function runBenchmark (line 25) | void runBenchmark(String interpreter, String benchmark)
function runTrial (line 40) | double runTrial(String interpreter, String benchmark)
function runComparison (line 52) | void runComparison(List<String> interpreters, String benchmark)
FILE: tool/bin/build.dart
function main (line 33) | Future<void> main(List<String> arguments)
function _buildPages (line 43) | void _buildPages({bool skipUpToDate = false})
function _buildPage (line 73) | List<int> _buildPage(Book book, Mustache mustache, Page page,
function _buildSass (line 138) | void _buildSass({bool skipUpToDate = false})
function _runServer (line 157) | Future<void> _runServer()
function handleRequest (line 158) | Future<shelf.Response> handleRequest(shelf.Request request)
function _isUpToDate (line 190) | bool _isUpToDate(
function _mostRecentlyModified (line 199) | DateTime _mostRecentlyModified(List<String> globs)
FILE: tool/bin/build_xml.dart
function main (line 15) | Future<void> main(List<String> arguments)
function _buildPage (line 35) | void _buildPage(Book book, Mustache mustache, Page page)
FILE: tool/bin/compile_snippets.dart
function main (line 297) | Future<void> main(List<String> arguments)
function _compileChapterTag (line 326) | Future<void> _compileChapterTag(Book book, Page chapter, CodeTag tag)
FILE: tool/bin/split_chapters.dart
function main (line 4) | void main(List<String> arguments)
FILE: tool/bin/test.dart
class Suite (line 34) | class Suite {
function main (line 44) | void main(List<String> arguments)
function _usageError (line 92) | void _usageError(ArgParser parser, String message)
function _runSuites (line 102) | void _runSuites(List<String> names)
function _runSuite (line 112) | bool _runSuite(String name)
function _runTest (line 137) | void _runTest(String path)
class ExpectedOutput (line 178) | class ExpectedOutput {
class Test (line 185) | class Test {
method parse (line 206) | bool parse()
method run (line 295) | List<String> run()
method _validateRuntimeError (line 318) | void _validateRuntimeError(List<String> errorLines)
method _validateCompileErrors (line 348) | void _validateCompileErrors(List<String> error_lines)
method _validateExitCode (line 384) | void _validateExitCode(int exitCode, List<String> errorLines)
method _validateOutput (line 396) | void _validateOutput(List<String> outputLines)
method fail (line 425) | void fail(String message, [List<String> lines])
function _defineTestSuites (line 431) | void _defineTestSuites()
function c (line 432) | void c(String name, Map<String, String> tests)
function java (line 438) | void java(String name, Map<String, String> tests)
FILE: tool/bin/tile_pages.dart
function main (line 11) | Future<void> main(List<String> arguments)
FILE: tool/lib/src/book.dart
class Book (line 62) | class Book {
method findChapter (line 148) | Page findChapter(String title)
method findNumber (line 152) | Page findNumber(String number)
method adjacentPage (line 156) | Page adjacentPage(Page start, int offset)
method findSnippet (line 162) | Snippet findSnippet(CodeTag tag)
method lastSnippet (line 167) | Snippet lastSnippet(Page page)
method findTag (line 180) | CodeTag findTag(Page page, String name)
class SourceFile (line 191) | class SourceFile {
class SourceLine (line 203) | class SourceLine {
method isPresent (line 217) | bool isPresent(CodeTag tag)
method toString (line 227) | String toString()
FILE: tool/lib/src/code_tag.dart
class CodeTag (line 3) | class CodeTag with Ordering<CodeTag> implements Comparable<CodeTag> {
method compareTo (line 40) | int compareTo(CodeTag other)
method toString (line 48) | String toString()
FILE: tool/lib/src/format.dart
type Format (line 2) | enum Format {
FILE: tool/lib/src/location.dart
class Location (line 3) | class Location {
method toString (line 39) | String toString()
method toHtml (line 48) | String toHtml(Location preceding, List<String> removed)
method toXml (line 107) | String toXml(Location preceding, List<String> removed)
method popToDepth (line 180) | Location popToDepth(int depth)
FILE: tool/lib/src/markdown/block_syntax.dart
class BookHeaderSyntax (line 11) | class BookHeaderSyntax extends BlockSyntax {
method parse (line 22) | Node parse(BlockParser parser)
FILE: tool/lib/src/markdown/code_syntax.dart
class HighlightedCodeBlockSyntax (line 12) | class HighlightedCodeBlockSyntax extends BlockSyntax {
method canParse (line 21) | bool canParse(BlockParser parser)
method parseChildLines (line 24) | List<String> parseChildLines(BlockParser parser)
method parse (line 42) | Node parse(BlockParser parser)
class CodeTagBlockSyntax (line 106) | class CodeTagBlockSyntax extends BlockSyntax {
method canParse (line 117) | bool canParse(BlockParser parser)
method parse (line 120) | Node parse(BlockParser parser)
function _buildSnippet (line 136) | String _buildSnippet(Format format, CodeTag tag, Snippet snippet)
function _buildSnippetXml (line 192) | String _buildSnippetXml(CodeTag tag, Snippet snippet)
function _writeContextHtml (line 254) | void _writeContextHtml(Format format, StringBuffer buffer, List<String> ...
function _writeContextXml (line 273) | void _writeContextXml(StringBuffer buffer, List<String> lines, String tag)
FILE: tool/lib/src/markdown/html_renderer.dart
class HtmlRenderer (line 4) | class HtmlRenderer implements NodeVisitor {
method render (line 27) | String render(List<Node> nodes)
method visitText (line 39) | void visitText(Text text)
method visitElementBefore (line 58) | bool visitElementBefore(Element element)
method visitElementAfter (line 84) | void visitElementAfter(Element element)
FILE: tool/lib/src/markdown/inline_syntax.dart
class EllipseSyntax (line 6) | class EllipseSyntax extends InlineSyntax {
method onMatch (line 11) | bool onMatch(InlineParser parser, Match match)
class ApostropheSyntax (line 21) | class ApostropheSyntax extends InlineSyntax {
method onMatch (line 26) | bool onMatch(InlineParser parser, Match match)
method _isRight (line 47) | bool _isRight(int before, int after)
class SmartQuoteSyntax (line 62) | class SmartQuoteSyntax extends InlineSyntax {
method onMatch (line 67) | bool onMatch(InlineParser parser, Match match)
method _isRight (line 89) | bool _isRight(int before, int after)
class EmDashSyntax (line 107) | class EmDashSyntax extends InlineSyntax {
method onMatch (line 112) | bool onMatch(InlineParser parser, Match match)
class NewlineSyntax (line 121) | class NewlineSyntax extends InlineSyntax {
method onMatch (line 124) | bool onMatch(InlineParser parser, Match match)
FILE: tool/lib/src/markdown/markdown.dart
function renderMarkdown (line 12) | String renderMarkdown(Book book, Page page, List<String> lines, Format f...
FILE: tool/lib/src/markdown/xml_renderer.dart
class XmlRenderer (line 12) | class XmlRenderer implements NodeVisitor {
method render (line 32) | String render(List<Node> nodes)
method visitText (line 71) | void visitText(Text node)
method visitElementBefore (line 184) | bool visitElementBefore(Element element)
method visitElementAfter (line 274) | void visitElementAfter(Element element)
method _push (line 322) | void _push(String name)
method _pop (line 327) | void _pop()
method _addText (line 332) | void _addText(String text)
method _addInline (line 345) | void _addInline(_Inline inline)
method _resetParagraph (line 350) | void _resetParagraph()
method _flushParagraph (line 354) | void _flushParagraph()
class _Context (line 361) | class _Context {
method has (line 368) | bool has(String name)
method isIn (line 379) | bool isIn(String name)
method toString (line 462) | String toString()
class _Paragraph (line 469) | class _Paragraph {
method _isNext (line 476) | bool _isNext(String tag, String previousTag)
method prettyPrint (line 499) | String prettyPrint(_Paragraph previous)
class _Inline (line 520) | class _Inline {
method prettyPrint (line 530) | void prettyPrint(StringBuffer buffer, _Context context)
FILE: tool/lib/src/mustache.dart
class Mustache (line 12) | class Mustache {
method render (line 21) | String render(Book book, Page page, String body, {String template})
method _makePartData (line 87) | Map<String, dynamic> _makePartData(Book book, int partIndex)
method _makeChapterList (line 97) | List<Map<String, dynamic>> _makeChapterList(Page part)
method _makeSections (line 109) | List<Map<String, dynamic>> _makeSections(Page page)
method _load (line 125) | Template _load(String name)
FILE: tool/lib/src/page.dart
class Page (line 10) | class Page {
method findCodeTag (line 82) | CodeTag findCodeTag(String name)
method toString (line 93) | String toString()
method _ensureFile (line 96) | PageFile _ensureFile()
class PageFile (line 100) | class PageFile {
class Header (line 115) | class Header {
FILE: tool/lib/src/page_parser.dart
function parsePage (line 14) | PageFile parsePage(Page page)
function _createCodeTag (line 76) | CodeTag _createCodeTag(Page page, int index, String name, String options)
FILE: tool/lib/src/snippet.dart
class Snippet (line 7) | class Snippet {
method addLine (line 32) | void addLine(int lineIndex, SourceLine line)
method removeLine (line 43) | void removeLine(int lineIndex, SourceLine line)
method toString (line 95) | String toString()
method calculateContext (line 98) | void calculateContext()
FILE: tool/lib/src/source_file_parser.dart
class SourceFileParser (line 31) | class SourceFileParser {
method parse (line 48) | SourceFile parse()
method _updateLocationBefore (line 106) | void _updateLocationBefore(String line, int lineIndex)
method _updateLocationAfter (line 172) | void _updateLocationAfter(String line)
method _updateState (line 210) | bool _updateState(String line)
method _push (line 296) | void _push(
method _pop (line 315) | void _pop()
class _ParseState (line 320) | class _ParseState {
method toString (line 326) | String toString()
FILE: tool/lib/src/split_chapter.dart
function splitChapter (line 16) | Future<void> splitChapter(Book book, Page chapter, [CodeTag tag])
function _splitSourceFile (line 26) | Future<void> _splitSourceFile(Book book, Page chapter, String sourcePath,
function _generateSourceFile (line 69) | String _generateSourceFile(
FILE: tool/lib/src/syntax/highlighter.dart
function formatCode (line 15) | String formatCode(String language, List<String> lines, Format format,
function checkLineLength (line 20) | void checkLineLength(String line)
class Highlighter (line 33) | class Highlighter {
method _highlight (line 46) | String _highlight(List<String> lines, String preClass, int indent)
method _scanLine (line 68) | void _scanLine(String line, int indent)
method writeToken (line 107) | void writeToken(String type, [String text])
method writeText (line 124) | void writeText(String string)
method _writeChar (line 130) | void _writeChar(int char)
FILE: tool/lib/src/syntax/language.dart
class Language (line 4) | class Language {
method keywordType (line 9) | keywordType(String wordList, String type)
FILE: tool/lib/src/syntax/rule.dart
class Rule (line 5) | abstract class Rule {
method apply (line 16) | bool apply(Highlighter highlighter)
method applyRule (line 22) | void applyRule(Highlighter highlighter)
class SimpleRule (line 27) | class SimpleRule extends Rule {
method applyRule (line 32) | void applyRule(Highlighter highlighter)
class CaptureRule (line 40) | class CaptureRule extends Rule {
method applyRule (line 45) | void applyRule(Highlighter highlighter)
class StringRule (line 59) | class StringRule extends Rule {
method applyRule (line 64) | void applyRule(Highlighter highlighter)
class IdentifierRule (line 90) | class IdentifierRule extends Rule {
method applyRule (line 93) | void applyRule(Highlighter highlighter)
FILE: tool/lib/src/term.dart
function cyan (line 14) | String cyan(Object message)
function gray (line 15) | String gray(Object message)
function green (line 16) | String green(Object message)
function magenta (line 17) | String magenta(Object message)
function pink (line 18) | String pink(Object message)
function red (line 19) | String red(Object message)
function yellow (line 20) | String yellow(Object message)
function clearLine (line 22) | void clearLine()
function writeLine (line 30) | void writeLine([String line])
function _ansi (line 38) | String _ansi(String special, [String fallback = ''])
FILE: tool/lib/src/text.dart
function toFileName (line 10) | String toFileName(String text)
function longestLine (line 25) | int longestLine(int longest, Iterable<String> lines)
function pluralize (line 32) | String pluralize<T>(Iterable<T> sequence)
function trimTrailingNewline (line 70) | String trimTrailingNewline()
Condensed preview — 548 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,932K chars).
[
{
"path": ".gitignore",
"chars": 286,
"preview": "# Intermediate and built stuff.\n.sass-cache/\n/build/\n/gen/\nclox\n*.class\nexercises/chapter01_introduction/3/linked_list\n."
},
{
"path": "LICENSE",
"chars": 4394,
"preview": "Copyright (c) 2015 Robert Nystrom\n\n---------------------------------- Commentary ----------------------------------\n\nThe"
},
{
"path": "Makefile",
"chars": 11239,
"preview": "BUILD_DIR := build\nTOOL_SOURCES := tool/pubspec.lock $(shell find tool -name '*.dart')\nBUILD_SNAPSHOT := $(BUILD_DIR)/bu"
},
{
"path": "README.md",
"chars": 7687,
"preview": "This is the repo used for the in-progress book \"[Crafting Interpreters][]\". It\ncontains the Markdown text of the book, f"
},
{
"path": "asset/index.scss",
"chars": 3827,
"preview": "@import 'sass/shared';\n@import 'sass/sign-up';\n\nbody, h1, h2, h3, h4, p, blockquote, code, ul, ol, dl, dd, img {\n margi"
},
{
"path": "asset/mustache/contents-nav.html",
"chars": 414,
"preview": "<h2><a href=\"#top\"><small> </small> Table of Contents</a></h2>\n<ul>\n <li><a href=\"#welcome\"><small>I</small>Welcom"
},
{
"path": "asset/mustache/contents-part.html",
"chars": 428,
"preview": "<h2><span class=\"num\">{{ number }}.</span><a href=\"{{ file }}.html\" name=\"{{ file }}\">{{ title }}</a></h2>\n<ul>\n{{# chap"
},
{
"path": "asset/mustache/contents.html",
"chars": 2066,
"preview": "{{> header }}\n\n<nav class=\"wide\">\n <a href=\"/\"><img src=\"image/logotype.png\" title=\"Crafting Interpreters\"></a>\n <div "
},
{
"path": "asset/mustache/footer.html",
"chars": 23,
"preview": "</div>\n</body>\n</html>\n"
},
{
"path": "asset/mustache/header.html",
"chars": 1241,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>{{title}} &mid"
},
{
"path": "asset/mustache/in_design.html",
"chars": 131,
"preview": "<chapter>\n<chapter-number>{{ number }}</chapter-number>\n<title>{{ title }}</title>\n<part>{{ part }}</part>\n{{{ body }}}\n"
},
{
"path": "asset/mustache/index.html",
"chars": 10195,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>Crafting Inter"
},
{
"path": "asset/mustache/nav.html",
"chars": 934,
"preview": "{{# is_chapter }}\n<h3><a href=\"#top\">{{ title }}<small>{{ number }}</small></a></h3>\n\n<ul>\n {{# sections }}\n <li><a "
},
{
"path": "asset/mustache/page.html",
"chars": 1328,
"preview": "{{> header }}\n<nav class=\"wide\">\n <a href=\"/\"><img src=\"image/logotype.png\" title=\"Crafting Interpreters\"></a>\n <div c"
},
{
"path": "asset/mustache/prev-next.html",
"chars": 384,
"preview": "<div class=\"prev-next\">\n {{# has_prev }}\n <a href=\"{{ prev_file }}.html\" title=\"{{ prev }}\" class=\"left\">← "
},
{
"path": "asset/sass/chapter.scss",
"chars": 4117,
"preview": "article.chapter {\n h2 {\n font: 600 30px/24px $serif;\n margin: 69px 0 0 0;\n padding-bottom: 3px;\n\n small {\n "
},
{
"path": "asset/sass/contents.scss",
"chars": 1945,
"preview": "article.contents {\n h2 {\n margin: 22px 0 6px 0;\n font: 600 normal 18px/24px $nav;\n text-transform: uppercase;\n"
},
{
"path": "asset/sass/print.scss",
"chars": 1275,
"preview": "@import 'shared';\n\n@media print {\n // Pure black text.\n body, a, code {\n color: #000 !important;\n background: no"
},
{
"path": "asset/sass/shared.scss",
"chars": 2269,
"preview": "// Font stacks.\n$serif: \"Crimson\", Georgia, serif;\n$mono: \"Source Code Pro\", Menlo, Consolas, Monaco, monospace;\n$n"
},
{
"path": "asset/sass/sign-up.scss",
"chars": 810,
"preview": ".sign-up {\n padding: 12px;\n margin: 24px 0 24px 0;\n background: hsl(40, 80%, 95%);\n color: hsl(40, 50%, 50%);\n bord"
},
{
"path": "asset/style.scss",
"chars": 14152,
"preview": "@import 'sass/shared';\n@import 'sass/chapter';\n@import 'sass/contents';\n@import 'sass/sign-up';\n@import 'sass/print';\n\n/"
},
{
"path": "book/a-bytecode-virtual-machine.md",
"chars": 925,
"preview": "Our Java interpreter, jlox, taught us many of the fundamentals of programming\nlanguages, but we still have much to learn"
},
{
"path": "book/a-map-of-the-territory.md",
"chars": 31351,
"preview": "> You must have a map, no matter how rough. Otherwise you wander all over the\n> place. In *The Lord of the Rings* I neve"
},
{
"path": "book/a-tree-walk-interpreter.md",
"chars": 1188,
"preview": "With this part, we begin jlox, the first of our two interpreters. Programming\nlanguages are a huge topic with piles of c"
},
{
"path": "book/a-virtual-machine.md",
"chars": 37814,
"preview": "> Magicians protect their secrets not because the secrets are large and\n> important, but because they are so small and t"
},
{
"path": "book/acknowledgements.md",
"chars": 1791,
"preview": "When the first copy of \"[Game Programming Patterns][gpp]\" sold, I guess I had\nthe right to call myself an author. But it"
},
{
"path": "book/appendix-i.md",
"chars": 3698,
"preview": "Here is a complete grammar for Lox. The chapters that introduce each part of the\nlanguage include the grammar rules ther"
},
{
"path": "book/appendix-ii.md",
"chars": 3758,
"preview": "For your edification, here is the code produced by [the little script\nwe built][generator] to automate generating the sy"
},
{
"path": "book/backmatter.md",
"chars": 414,
"preview": "You've reached the end of the book! There are two pieces of supplementary\nmaterial you may find helpful:\n\n* **[Appendix "
},
{
"path": "book/calls-and-functions.md",
"chars": 57871,
"preview": "> Any problem in computer science can be solved with another level of\n> indirection. Except for the problem of too many "
},
{
"path": "book/chunks-of-bytecode.md",
"chars": 48346,
"preview": "> If you find that you're spending almost all your time on theory, start turning\n> some attention to practical things; i"
},
{
"path": "book/classes-and-instances.md",
"chars": 23531,
"preview": "> Caring too much for objects can destroy you. Only -- if you care for a thing\n> enough, it takes on a life of its own, "
},
{
"path": "book/classes.md",
"chars": 49403,
"preview": "> One has no right to love or hate anything if one has not acquired a thorough\n> knowledge of its nature. Great love spr"
},
{
"path": "book/closures.md",
"chars": 66759,
"preview": "> As the man said, for every complex problem there's a simple solution, and it's\n> wrong.\n>\n> <cite>Umberto Eco, <em>Fou"
},
{
"path": "book/compiling-expressions.md",
"chars": 40501,
"preview": "> In the middle of the journey of our life I found myself within a dark woods\n> where the straight way was lost.\n>\n> <ci"
},
{
"path": "book/contents.md",
"chars": 76,
"preview": "This text is not used. All of the content is in the contents.html template.\n"
},
{
"path": "book/control-flow.md",
"chars": 29153,
"preview": "> Logic, like whiskey, loses its beneficial effect when taken in too large\n> quantities.\n>\n> <cite>Edward John Moreton D"
},
{
"path": "book/dedication.md",
"chars": 141,
"preview": "<div class=\"dedication\">\n\n<img src=\"image/ginny.png\" alt=\"My beloved dog and her stupid face.\" />\n\nTo Ginny, I miss your"
},
{
"path": "book/evaluating-expressions.md",
"chars": 28718,
"preview": "> You are my creator, but I am your master; Obey!\n>\n> <cite>Mary Shelley, <em>Frankenstein</em></cite>\n\nIf you want to p"
},
{
"path": "book/functions.md",
"chars": 41455,
"preview": "> And that is also the way the human mind works -- by the compounding of old\n> ideas into new structures that become new"
},
{
"path": "book/garbage-collection.md",
"chars": 56473,
"preview": "> I wanna, I wanna,<br />\n> I wanna, I wanna,<br />\n> I wanna be trash.<br />\n>\n> <cite>The Whip, “Trash”</c"
},
{
"path": "book/global-variables.md",
"chars": 30509,
"preview": "> If only there could be an invention that bottled up a memory, like scent. And\n> it never faded, and it never got stale"
},
{
"path": "book/hash-tables.md",
"chars": 50824,
"preview": "> Hash, x. There is no definition for this word -- nobody knows what hash is.\n>\n> <cite>Ambrose Bierce, <em>The Unabridg"
},
{
"path": "book/index.md",
"chars": 73,
"preview": "This text is not used. All of the content is in the index.html template.\n"
},
{
"path": "book/inheritance.md",
"chars": 26707,
"preview": "> Once we were blobs in the sea, and then fishes, and then lizards and rats and\n> then monkeys, and hundreds of things i"
},
{
"path": "book/introduction.md",
"chars": 23579,
"preview": "> Fairy tales are more than true: not because they tell us that dragons exist,\n> but because they tell us that dragons c"
},
{
"path": "book/jumping-back-and-forth.md",
"chars": 38110,
"preview": "> The order that our mind imagines is like a net, or like a ladder, built to\n> attain something. But afterward you must "
},
{
"path": "book/local-variables.md",
"chars": 28729,
"preview": "> And as imagination bodies forth<br />\n> The forms of things unknown, the poet's pen<br />\n> Turns them to shapes and g"
},
{
"path": "book/methods-and-initializers.md",
"chars": 52568,
"preview": "> When you are on the dancefloor, there is nothing to do but dance.\n>\n> <cite>Umberto Eco, <em>The Mysterious Flame of Q"
},
{
"path": "book/optimization.md",
"chars": 55722,
"preview": "> The evening's the best part of the day. You've done your day's work. Now you\n> can put your feet up and enjoy it.\n>\n> "
},
{
"path": "book/parsing-expressions.md",
"chars": 40889,
"preview": "> Grammar, which knows how to control even kings.\n> <cite>Molière</cite>\n\n<span name=\"parse\">This</span> chapter marks t"
},
{
"path": "book/representing-code.md",
"chars": 41418,
"preview": "> To dwellers in a wood, almost every species of tree has its voice as well as\n> its feature.\n> <cite>Thomas Hardy, <em>"
},
{
"path": "book/resolving-and-binding.md",
"chars": 39647,
"preview": "> Once in a while you find yourself in an odd situation. You get into it by\n> degrees and in the most natural way but, w"
},
{
"path": "book/scanning-on-demand.md",
"chars": 33263,
"preview": "> Literature is idiosyncratic arrangements in horizontal lines in only\n> twenty-six phonetic symbols, ten Arabic numbers"
},
{
"path": "book/scanning.md",
"chars": 34690,
"preview": "> Take big bites. Anything worth doing is worth overdoing.\n>\n> <cite>Robert A. Heinlein, <em>Time Enough for Love</em></"
},
{
"path": "book/statements-and-state.md",
"chars": 54551,
"preview": "> All my life, my heart has yearned for a thing I cannot name.\n> <cite>André Breton, <em>Mad Love</em></cite>\n\nTh"
},
{
"path": "book/strings.md",
"chars": 32880,
"preview": "> \"Ah? A small aversion to menial labor?\" The doctor cocked an eyebrow.\n> \"Understandable, but misplaced. One should tre"
},
{
"path": "book/superclasses.md",
"chars": 29924,
"preview": "> You can choose your friends but you sho' can't choose your family, an' they're\n> still kin to you no matter whether yo"
},
{
"path": "book/the-lox-language.md",
"chars": 38648,
"preview": "> What nicer thing can you do for somebody than make them breakfast?\n>\n> <cite>Anthony Bourdain</cite>\n\nWe'll spend the "
},
{
"path": "book/types-of-values.md",
"chars": 28305,
"preview": "> When you are a Bear of Very Little Brain, and you Think of Things, you find\n> sometimes that a Thing which seemed very"
},
{
"path": "book/welcome.md",
"chars": 824,
"preview": "This may be the beginning of a grand adventure. Programming languages encompass\na huge space to explore and play in. Ple"
},
{
"path": "c/chunk.c",
"chars": 1925,
"preview": "//> Chunks of Bytecode chunk-c\n#include <stdlib.h>\n\n#include \"chunk.h\"\n//> chunk-c-include-memory\n#include \"memory.h\"\n//"
},
{
"path": "c/chunk.h",
"chars": 3216,
"preview": "//> Chunks of Bytecode chunk-h\n#ifndef clox_chunk_h\n#define clox_chunk_h\n\n#include \"common.h\"\n//> chunk-h-include-value\n"
},
{
"path": "c/clox.xcodeproj/project.pbxproj",
"chars": 22250,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "c/clox.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 149,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:cvox.xcodeproj\""
},
{
"path": "c/clox.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "c/clox.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
"chars": 226,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "c/clox.xcodeproj/xcshareddata/xcschemes/clox.xcscheme",
"chars": 3110,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1130\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "c/common.h",
"chars": 988,
"preview": "//> Chunks of Bytecode common-h\n#ifndef clox_common_h\n#define clox_common_h\n\n#include <stdbool.h>\n#include <stddef.h>\n#i"
},
{
"path": "c/compiler.c",
"chars": 44675,
"preview": "//> Scanning on Demand compiler-c\n#include <stdio.h>\n//> Compiling Expressions compiler-include-stdlib\n#include <stdlib."
},
{
"path": "c/compiler.h",
"chars": 720,
"preview": "//> Scanning on Demand compiler-h\n#ifndef clox_compiler_h\n#define clox_compiler_h\n\n//> Strings compiler-include-object\n#"
},
{
"path": "c/debug.c",
"chars": 8196,
"preview": "//> Chunks of Bytecode debug-c\n#include <stdio.h>\n\n#include \"debug.h\"\n//> Closures debug-include-object\n#include \"object"
},
{
"path": "c/debug.h",
"chars": 211,
"preview": "//> Chunks of Bytecode debug-h\n#ifndef clox_debug_h\n#define clox_debug_h\n\n#include \"chunk.h\"\n\nvoid disassembleChunk(Chun"
},
{
"path": "c/main.c",
"chars": 3659,
"preview": "//> Chunks of Bytecode main-c\n//> Scanning on Demand main-includes\n#include <stdio.h>\n#include <stdlib.h>\n#include <stri"
},
{
"path": "c/memory.c",
"chars": 8878,
"preview": "//> Chunks of Bytecode memory-c\n#include <stdlib.h>\n\n//> Garbage Collection memory-include-compiler\n#include \"compiler.h"
},
{
"path": "c/memory.h",
"chars": 1247,
"preview": "//> Chunks of Bytecode memory-h\n#ifndef clox_memory_h\n#define clox_memory_h\n\n#include \"common.h\"\n//> Strings memory-incl"
},
{
"path": "c/object.c",
"chars": 7352,
"preview": "//> Strings object-c\n#include <stdio.h>\n#include <string.h>\n\n#include \"memory.h\"\n#include \"object.h\"\n//> Hash Tables obj"
},
{
"path": "c/object.h",
"chars": 6025,
"preview": "//> Strings object-h\n#ifndef clox_object_h\n#define clox_object_h\n\n#include \"common.h\"\n//> Calls and Functions object-inc"
},
{
"path": "c/scanner.c",
"chars": 6151,
"preview": "//> Scanning on Demand scanner-c\n#include <stdio.h>\n#include <string.h>\n\n#include \"common.h\"\n#include \"scanner.h\"\n\ntyped"
},
{
"path": "c/scanner.h",
"chars": 1039,
"preview": "//> Scanning on Demand scanner-h\n#ifndef clox_scanner_h\n#define clox_scanner_h\n//> token-type\n\ntypedef enum {\n // Singl"
},
{
"path": "c/table.c",
"chars": 5744,
"preview": "//> Hash Tables table-c\n#include <stdlib.h>\n#include <string.h>\n\n#include \"memory.h\"\n#include \"object.h\"\n#include \"table"
},
{
"path": "c/table.h",
"chars": 1137,
"preview": "//> Hash Tables table-h\n#ifndef clox_table_h\n#define clox_table_h\n\n#include \"common.h\"\n#include \"value.h\"\n//> entry\n\ntyp"
},
{
"path": "c/value.c",
"chars": 3046,
"preview": "//> Chunks of Bytecode value-c\n#include <stdio.h>\n//> Strings value-include-string\n#include <string.h>\n//< Strings value"
},
{
"path": "c/value.h",
"chars": 4053,
"preview": "//> Chunks of Bytecode value-h\n#ifndef clox_value_h\n#define clox_value_h\n//> Optimization include-string\n\n#include <stri"
},
{
"path": "c/vm.c",
"chars": 27861,
"preview": "//> A Virtual Machine vm-c\n//> Types of Values include-stdarg\n#include <stdarg.h>\n//< Types of Values include-stdarg\n//>"
},
{
"path": "c/vm.h",
"chars": 2547,
"preview": "//> A Virtual Machine vm-h\n#ifndef clox_vm_h\n#define clox_vm_h\n\n/* A Virtual Machine vm-h < Calls and Functions vm-inclu"
},
{
"path": "java/com/craftinginterpreters/lox/AstPrinter.java",
"chars": 6985,
"preview": "//> Representing Code ast-printer\npackage com.craftinginterpreters.lox;\n//> omit\n\nimport java.util.List;\n//< omit\n\n/* Re"
},
{
"path": "java/com/craftinginterpreters/lox/Environment.java",
"chars": 2216,
"preview": "//> Statements and State environment-class\npackage com.craftinginterpreters.lox;\n\nimport java.util.HashMap;\nimport java."
},
{
"path": "java/com/craftinginterpreters/lox/Expr.java",
"chars": 4550,
"preview": "//> Appendix II expr\npackage com.craftinginterpreters.lox;\n\nimport java.util.List;\n\nabstract class Expr {\n interface Vi"
},
{
"path": "java/com/craftinginterpreters/lox/Interpreter.java",
"chars": 15758,
"preview": "//> Evaluating Expressions interpreter-class\npackage com.craftinginterpreters.lox;\n//> Statements and State import-list\n"
},
{
"path": "java/com/craftinginterpreters/lox/Lox.java",
"chars": 4106,
"preview": "//> Scanning lox-class\npackage com.craftinginterpreters.lox;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;"
},
{
"path": "java/com/craftinginterpreters/lox/LoxCallable.java",
"chars": 229,
"preview": "//> Functions callable\npackage com.craftinginterpreters.lox;\n\nimport java.util.List;\n\ninterface LoxCallable {\n//> callab"
},
{
"path": "java/com/craftinginterpreters/lox/LoxClass.java",
"chars": 2147,
"preview": "//> Classes lox-class\npackage com.craftinginterpreters.lox;\n\nimport java.util.List;\nimport java.util.Map;\n\n/* Classes lo"
},
{
"path": "java/com/craftinginterpreters/lox/LoxFunction.java",
"chars": 2655,
"preview": "//> Functions lox-function\npackage com.craftinginterpreters.lox;\n\nimport java.util.List;\n\nclass LoxFunction implements L"
},
{
"path": "java/com/craftinginterpreters/lox/LoxInstance.java",
"chars": 1165,
"preview": "//> Classes lox-instance\npackage com.craftinginterpreters.lox;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nclass L"
},
{
"path": "java/com/craftinginterpreters/lox/Parser.java",
"chars": 14391,
"preview": "//> Parsing Expressions parser\npackage com.craftinginterpreters.lox;\n\n//> Statements and State parser-imports\nimport jav"
},
{
"path": "java/com/craftinginterpreters/lox/Resolver.java",
"chars": 9851,
"preview": "//> Resolving and Binding resolver\npackage com.craftinginterpreters.lox;\n\nimport java.util.HashMap;\nimport java.util.Lis"
},
{
"path": "java/com/craftinginterpreters/lox/Return.java",
"chars": 225,
"preview": "//> Functions return-exception\npackage com.craftinginterpreters.lox;\n\nclass Return extends RuntimeException {\n final Ob"
},
{
"path": "java/com/craftinginterpreters/lox/RuntimeError.java",
"chars": 250,
"preview": "//> Evaluating Expressions runtime-error-class\npackage com.craftinginterpreters.lox;\n\nclass RuntimeError extends Runtime"
},
{
"path": "java/com/craftinginterpreters/lox/Scanner.java",
"chars": 5688,
"preview": "//> Scanning scanner-class\npackage com.craftinginterpreters.lox;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\n"
},
{
"path": "java/com/craftinginterpreters/lox/Stmt.java",
"chars": 3670,
"preview": "//> Appendix II stmt\npackage com.craftinginterpreters.lox;\n\nimport java.util.List;\n\nabstract class Stmt {\n interface Vi"
},
{
"path": "java/com/craftinginterpreters/lox/Token.java",
"chars": 435,
"preview": "//> Scanning token-class\npackage com.craftinginterpreters.lox;\n\nclass Token {\n final TokenType type;\n final String lex"
},
{
"path": "java/com/craftinginterpreters/lox/TokenType.java",
"chars": 505,
"preview": "//> Scanning token-type\npackage com.craftinginterpreters.lox;\n\nenum TokenType {\n // Single-character tokens.\n LEFT_PAR"
},
{
"path": "java/com/craftinginterpreters/tool/GenerateAst.java",
"chars": 6989,
"preview": "//> Representing Code generate-ast\npackage com.craftinginterpreters.tool;\n\nimport java.io.IOException;\nimport java.io.Pr"
},
{
"path": "jlox",
"chars": 118,
"preview": "#!/usr/bin/env bash\n\nscript_dir=$(dirname \"$0\")\njava -cp ${script_dir}/build/java com.craftinginterpreters.lox.Lox $@\n"
},
{
"path": "note/BISAC.txt",
"chars": 122,
"preview": "COMPUTERS / Programming / Compilers\nCOMPUTERS / Languages / General\nCOMPUTERS / Software Development & Engineering / Too"
},
{
"path": "note/answers/chapter01_introduction/1.md",
"chars": 416,
"preview": "Markdown, Jinja2, Makefile, SASS, CSS, HTML. There's also the homegrown little\ntags inserted in the code and Markdown to"
},
{
"path": "note/answers/chapter01_introduction/2/Hello.java",
"chars": 111,
"preview": "public class Hello {\n public static void main(String[] args) {\n System.out.println(\"Hello, world!\");\n }\n}\n"
},
{
"path": "note/answers/chapter01_introduction/2/Makefile",
"chars": 222,
"preview": "# Compile the Java file to a class file.\nHello.class: Hello.java\n\t@ javac Hello.java\n\n# Convenience target to build and "
},
{
"path": "note/answers/chapter01_introduction/3/Makefile",
"chars": 101,
"preview": "# Compile the .c file to an executable.\nlinked_list: linked_list.c\n\tgcc linked_list.c -o linked_list\n"
},
{
"path": "note/answers/chapter01_introduction/3/linked_list.c",
"chars": 1898,
"preview": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\ntypedef struct sNode {\n struct sNode* prev;\n struct sNode*"
},
{
"path": "note/answers/chapter01_introduction/3/linked_list.xcodeproj/project.pbxproj",
"chars": 7376,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "note/answers/chapter01_introduction/3/linked_list.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 156,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:linked_list.xco"
},
{
"path": "note/answers/chapter02_map.md",
"chars": 1058,
"preview": "## 1. Find the various parts in an open source implementation.\n\nTODO\n\n## 2. Why not use a JIT?\n\n1. It's really complex t"
},
{
"path": "note/answers/chapter03_lox.md",
"chars": 1696,
"preview": "1. I've, uh, written plenty. Look in /test/. Here's another:\n ~~~~\n class List {\n init(data, next) {\n "
},
{
"path": "note/answers/chapter04_scanning.md",
"chars": 3111,
"preview": "1. Both of them have significant indentation. To handle that, the scanner\n emits synthetic \"{\" and \"}\" tokens (or \"i"
},
{
"path": "note/answers/chapter05_representing.md",
"chars": 2441,
"preview": "1. There are a few ways to do it. Here is one:\n\n ```text\n expr → expr calls\n expr → IDENTIFIER\n expr → NUMB"
},
{
"path": "note/answers/chapter06_parsing.md",
"chars": 5850,
"preview": "1. The comma operator has the lowest precedence, so it goes between expression\n and equality:\n\n ```ebnf\n expre"
},
{
"path": "note/answers/chapter07_evaluating.md",
"chars": 1571,
"preview": "1. Python 3 allows comparing all of the various number types with each other,\n except for complex numbers. Booleans "
},
{
"path": "note/answers/chapter08_statements.md",
"chars": 5497,
"preview": "1. It can be hard to do this in a clean way since the expression grammar\n overlaps the statement grammar so much (ev"
},
{
"path": "note/answers/chapter09_control.md",
"chars": 7030,
"preview": "1. The basic idea is that the control flow operations become methods that take\n callbacks for the blocks to execute "
},
{
"path": "note/answers/chapter10_functions.md",
"chars": 6576,
"preview": "1. Smalltalk has different call syntax for different arities. To define a\n method that takes multiple arguments, you"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/AstPrinter.java",
"chars": 4231,
"preview": "package com.craftinginterpreters.lox;\n\n// Creates an unambiguous, if ugly, string representation of AST nodes.\nclass Ast"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Environment.java",
"chars": 1009,
"preview": "package com.craftinginterpreters.lox;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nclass Environment {\n final E"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Expr.java",
"chars": 2729,
"preview": "package com.craftinginterpreters.lox;\n\nimport java.util.List;\n\nabstract class Expr {\n interface Visitor<R> {\n R visi"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Interpreter.java",
"chars": 8418,
"preview": "package com.craftinginterpreters.lox;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimpo"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Lox.java",
"chars": 2394,
"preview": "package com.craftinginterpreters.lox;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputSt"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/LoxCallable.java",
"chars": 168,
"preview": "package com.craftinginterpreters.lox;\n\nimport java.util.List;\n\ninterface LoxCallable {\n int arity();\n Object call(Inte"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/LoxFunction.java",
"chars": 918,
"preview": "package com.craftinginterpreters.lox;\n\nimport java.util.List;\n\nclass LoxFunction implements LoxCallable {\n private fina"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Parser.java",
"chars": 9106,
"preview": "package com.craftinginterpreters.lox;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimpo"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Resolver.java",
"chars": 4821,
"preview": "package com.craftinginterpreters.lox;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport jav"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Return.java",
"chars": 194,
"preview": "package com.craftinginterpreters.lox;\n\nclass Return extends RuntimeException {\n final Object value;\n\n Return(Object va"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/RuntimeError.java",
"chars": 203,
"preview": "package com.craftinginterpreters.lox;\n\nclass RuntimeError extends RuntimeException {\n final Token token;\n\n RuntimeErro"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Scanner.java",
"chars": 4848,
"preview": "package com.craftinginterpreters.lox;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimpo"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Stmt.java",
"chars": 2758,
"preview": "package com.craftinginterpreters.lox;\n\nimport java.util.List;\n\nabstract class Stmt {\n interface Visitor<R> {\n R visi"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/Token.java",
"chars": 410,
"preview": "package com.craftinginterpreters.lox;\n\nclass Token {\n final TokenType type;\n final String lexeme;\n final Object liter"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/lox/TokenType.java",
"chars": 481,
"preview": "package com.craftinginterpreters.lox;\n\nenum TokenType {\n // Single-character tokens.\n LEFT_PAREN, RIGHT_PAREN, LEFT_BR"
},
{
"path": "note/answers/chapter11_resolving/4/com/craftinginterpreters/tool/GenerateAst.java",
"chars": 4029,
"preview": "package com.craftinginterpreters.tool;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Arrays;"
},
{
"path": "note/answers/chapter11_resolving/chapter11_resolving.md",
"chars": 5464,
"preview": "1. Consider:\n\n ```lox\n fun foo() {\n if (itsTuesday) foo();\n }\n ```\n\n The function does call itself "
},
{
"path": "note/answers/chapter12_classes.md",
"chars": 11471,
"preview": "1. Metaclasses are so cool, I almost wish the book itself discussed them\n properly, but there are only so many pages"
},
{
"path": "note/answers/chapter13_inheritance/1.md",
"chars": 9360,
"preview": "I'm gonna pick traits, for no particular reason. \"Traits\" means slightly\ndifferent things in the various languages that "
},
{
"path": "note/answers/chapter13_inheritance/2.md",
"chars": 2829,
"preview": "Ideally, we'd make \"inner\" a reserved word, but that means changing the scanner\nand adding a new AST node for it and stu"
},
{
"path": "note/answers/chapter13_inheritance/3.md",
"chars": 4076,
"preview": "There's a bunch of small features I'd add to Lox to make it feel a little more\nuser-friendly. Things like getters, sette"
},
{
"path": "note/answers/chapter14_chunks/1.md",
"chars": 4458,
"preview": "In order to run-length encode the line information, we need a slightly smarter\ndata structure than just a flat array of "
},
{
"path": "note/answers/chapter14_chunks/2.md",
"chars": 3154,
"preview": "There's not too much to this challenge. We add another opcode:\n\n```c\n// chunk.h\ntypedef enum {\n OP_CONSTANT,\n OP_CONST"
},
{
"path": "note/answers/chapter15_virtual/1.md",
"chars": 663,
"preview": "\nA helpful intermediate step is to explicitly parenthesize them so we can see\nthe operator precedence:\n\n (1 * 2) + 3\n"
},
{
"path": "note/answers/chapter15_virtual/2.md",
"chars": 1176,
"preview": "First, let's parenthesize:\n\n 4 - (3 * (- 2))\n\nThat gives:\n\n CONST 4\n CONST 3\n CONST 2\n NEGATE\n MULTIPL"
},
{
"path": "note/answers/chapter15_virtual/3.md",
"chars": 2300,
"preview": "There's nothing super algorithmically interesting about the change. We basically\nturn it into a dynamic array like we've"
},
{
"path": "note/answers/chapter16_scanning.md",
"chars": 4187,
"preview": "## 1\n\nI've implemented this in another language, Wren. You can see the code here:\n\nhttps://github.com/munificent/wren/bl"
},
{
"path": "note/answers/chapter17_compiling.md",
"chars": 2281,
"preview": "##1\n\nIt's:\n\n```\nexpression\n| parsePrecedence(PREC_ASSIGNMENT)\n| | grouping\n| | | expression\n| | | | parsePrecedence(PREC"
},
{
"path": "note/answers/chapter18_types.md",
"chars": 1993,
"preview": "## 1\n\nHaving both `OP_NEGATE` and `OP_SUBTRACT` is redundant. We can replace\nsubtraction with negate-then-add:\n\n```c\n// "
},
{
"path": "note/answers/chapter19_strings.md",
"chars": 6087,
"preview": "## 1\n\nThis change is mostly mechanical and not too difficult. First, in the type\nitself, we change the last field to use"
},
{
"path": "note/answers/chapter20_hash/1.md",
"chars": 9634,
"preview": "There's nothing mind-blowing about this exercise. It's mostly just replacing\n`ObjString*` with `Value` in the places whe"
},
{
"path": "note/answers/chapter21_global.md",
"chars": 6901,
"preview": "## 1\n\nThe optimization is pretty straightforward. When adding a string constant, we\nlook in the constant table to see if"
},
{
"path": "note/answers/chapter23_jumping/1.md",
"chars": 4969,
"preview": "\nAdd `TOKEN_CASE`, `TOKEN_COLON`, `TOKEN_DEFAULT`, and `TOKEN_SWITCH` to\nTokenType and then implement scanning `:`, `cas"
},
{
"path": "note/answers/chapter23_jumping/2.md",
"chars": 2561,
"preview": "Add `TOKEN_CONTINUE` to TokenType and then implement scanning the `continue`\nkeyword. Not shown here because it's not ve"
},
{
"path": "note/answers/chapter23_jumping/3.md",
"chars": 836,
"preview": "Reusing [an old StackOverflow answer of mine][answer]:\n\n[answer]: https://stackoverflow.com/a/4296080/9457\n\nMost languag"
},
{
"path": "note/answers/chapter24_calls/1.md",
"chars": 4303,
"preview": "Since our interpreter is so small, the change is pretty straightforward. First,\nwe declare a local variable for the `ip`"
},
{
"path": "note/answers/chapter24_calls/2.md",
"chars": 2413,
"preview": "There are a few ways you can do this. The interesting part is that the native\nC function needs to have sort of two signa"
},
{
"path": "note/answers/chapter25_closures/1.md",
"chars": 4374,
"preview": "One could spend a lot of time tweaking this and optimizing. Here's a simple\nimplementation. First, in the compiler we ne"
},
{
"path": "note/answers/chapter25_closures/2.md",
"chars": 3394,
"preview": "This took me quite a while to get working, even though the end result is pretty\nsimple. I wandered down a few dead ends "
},
{
"path": "note/answers/chapter25_closures/3.lox",
"chars": 898,
"preview": "// Here is the classic message-based pattern:\nfun vector(x, y) {\n fun object(message) {\n fun add(other) {\n retu"
},
{
"path": "note/answers/chapter26_garbage/1.md",
"chars": 4141,
"preview": "On my 64-bit Mac laptop, it takes 16 bytes or 128 bits. That's quite a lot for a\npointer, a Boolean, and an enum with on"
},
{
"path": "note/answers/chapter26_garbage/2.md",
"chars": 3144,
"preview": "The basic idea is that instead of clearing the mark bit of every live object,\nwe simply redefine their current value to "
},
{
"path": "note/answers/chapter27_classes/1.md",
"chars": 3203,
"preview": "In Ruby, if you access an instance variable that you never defined, you silently\nget `nil` in return. It's as if the obj"
},
{
"path": "note/answers/chapter27_classes/2.md",
"chars": 2673,
"preview": "I am actually iffy on whether a language should allow this, or at least whether\nit should make accessing fields using im"
},
{
"path": "note/answers/chapter27_classes/3.md",
"chars": 2116,
"preview": "Ruby provides a private method, `remove_instance_variable` that an object can\ncall on itself passing in the name of the "
},
{
"path": "note/answers/chapter27_classes/4.md",
"chars": 159,
"preview": "I'll just point you to a resource. Look for the paper \"An Efficient\nImplementation of Self, a Dynamically-Typed Object-O"
},
{
"path": "note/answers/chapter28_methods/1.md",
"chars": 1850,
"preview": "An easy optimization is to cache the initializer directly in the ObjClass to\navoid the hash table lookup:\n\n```c\ntypedef "
},
{
"path": "note/answers/chapter28_methods/2.md",
"chars": 599,
"preview": "The answer here is \"inline caching\". At each callsite, the VM inserts a little\nspace to store a cached reference to a cl"
},
{
"path": "note/answers/chapter28_methods/3.md",
"chars": 976,
"preview": "I'm actually *not* a fan of this choice, though it is certainly a common one.\nI like how Ruby uses a leading `@` to dist"
},
{
"path": "note/answers/chapter29_superclasses/1.md",
"chars": 1099,
"preview": "I created a hobby language named Wren. The clox VM was actually based on Wren's\nimplementation, and the design of Lox bo"
},
{
"path": "note/answers/chapter29_superclasses/2.md",
"chars": 4196,
"preview": "I can think of a few approaches:\n\n## 1. Eagerly rebuild the subclass method tables\n\nWe could keep doing copy-down inheri"
},
{
"path": "note/answers/chapter29_superclasses/3.diff",
"chars": 13207,
"preview": "diff --git a/c/chunk.h b/c/chunk.h\nindex 3fe9250..b035513 100644\n--- a/c/chunk.h\n+++ b/c/chunk.h\n@@ -19,7 +19,6 @@ typed"
},
{
"path": "note/answers/chapter29_superclasses/3.md",
"chars": 3872,
"preview": "I have a solution that implements the right semantics and makes inner calls as\nfast as any other method call. I won't wa"
},
{
"path": "note/blurb.txt",
"chars": 2583,
"preview": "Software engineers use programming languages every day, but few of us understand how those languages are designed and im"
},
{
"path": "note/contents.txt",
"chars": 1734,
"preview": "high-level goal: a *small* book that builds a complete, efficient interpreter.\ninstead of a wide text about programming "
},
{
"path": "note/design breaks.md",
"chars": 3356,
"preview": "- The \"novelty budget\" and choosing which things to keep familiar and which to\n keep new.\n\n- Learnability versus consis"
},
{
"path": "note/images.md",
"chars": 1506,
"preview": "Unscaled source images are scanned at 1200 DPI and stored at around that\nresolution. (We'll want the extra pixels when i"
},
{
"path": "note/indexing.md",
"chars": 2711,
"preview": "## Acronyms\n\nThe expanded form gets most of the locators. The acronym gets a \"See\" cross-ref\nto the expanded form:\n\n "
},
{
"path": "note/log.txt",
"chars": 86653,
"preview": "2021/07/29 - *** launch! ***\n2021/07/28 - work on blog post\n2021/07/27 - work on blog post\n2021/07/26 - responsive index"
},
{
"path": "note/names.txt",
"chars": 1848,
"preview": "music:\n-----\nfuzz\njive\njam\nmojo\nhaze\nquid\nmoxy\npick\nhowl\nfunk\nvox\n\nrocks and minerals:\n------------------\nagate\nberyl\nfl"
},
{
"path": "note/objects.txt",
"chars": 3733,
"preview": "A couple of issues related to working with objects:\n\n* How do we distinguish field access from \"getters\"?\n* How do we di"
},
{
"path": "note/outline.md",
"chars": 6848,
"preview": "**TODO: when can we introduce a print statement/function?**\n\nneeds to happen before statements and flow control otherwis"
},
{
"path": "note/research.txt",
"chars": 203,
"preview": "http://en.wikipedia.org/wiki/PL/0\n\n\"Structure and Interpretation of Efficient Interpreters\" (in dropbox)\n\nhttp://blog.an"
},
{
"path": "note/scope.txt",
"chars": 1846,
"preview": "Mostly following Scheme (R5RS):\n\n- Accessing an undefined name is a runtime error. It is not a compile time\n error.\n\n "
},
{
"path": "note/struct sizes.txt",
"chars": 1132,
"preview": "typedef struct Obj2 {\n ObjType type;\n} Obj2;\n\ntypedef struct ObjString2 {\n Obj2 obj;\n int length;\n char* chars;\n\n} O"
},
{
"path": "note/style guide.md",
"chars": 4490,
"preview": "## Person\n\nFiguring out when to use \"we\" versus \"it\" when talking about the code is hard.\nIt's important to be clear bec"
},
{
"path": "note/todo.txt",
"chars": 878,
"preview": "Print:\n\n- Order proof from IngramSpark.\n\neBook:\n\n- Fix all TODOs in asset/ebook/*.\n- Create wider cover image for non-Ki"
},
{
"path": "site/.htaccess",
"chars": 1202,
"preview": "ErrorDocument 404 /404.html\n\nRedirect /beta http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-"
},
{
"path": "site/404.html",
"chars": 3213,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>404 Page Not F"
},
{
"path": "site/a-bytecode-virtual-machine.html",
"chars": 6994,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>A Bytecode Vir"
},
{
"path": "site/a-map-of-the-territory.html",
"chars": 40677,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>A Map of the T"
},
{
"path": "site/a-tree-walk-interpreter.html",
"chars": 5842,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>A Tree-Walk In"
},
{
"path": "site/a-virtual-machine.html",
"chars": 68886,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>A Virtual Mach"
},
{
"path": "site/acknowledgements.html",
"chars": 4796,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>Acknowledgemen"
},
{
"path": "site/appendix-i.html",
"chars": 12693,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>Appendix I &mi"
},
{
"path": "site/appendix-ii.html",
"chars": 41454,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>Appendix II &m"
},
{
"path": "site/backmatter.html",
"chars": 3657,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>Backmatter &mi"
},
{
"path": "site/calls-and-functions.html",
"chars": 122353,
"preview": "<!DOCTYPE html>\n<html>\n<head>\n<meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n<title>Calls and Func"
}
]
// ... and 348 more files (download for full content)
About this extraction
This page contains the full source code of the munificent/craftinginterpreters GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 548 files (4.5 MB), approximately 1.2M tokens, and a symbol index with 929 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.