Skip to content

CS1729 Assignment 1

Joe Politz edited this page Oct 4, 2013 · 19 revisions

Compiling (with Pauses)

Your first assignment has three parts:

  1. Compile a portion of core Pyret to JavaScript,
  2. Implement a portion of the Pyret runtime in JavaScript,
  3. Enable pausing and breaking for the compiled code.

Overview

Administrative Details

You can work in pairs or solo for CS1729, tell me by the end of the day Monday if you're planning on working alone or with a partner.

You should fork the pyret-lang repo on Github and do all your work on your own fork. If we have contributions from one another that we want to share, we'll incorporate them into the main Pyret repo and then distribute them from there.

Source Layout

The Pyret repository has a directory called js/ that contains the files and support code you'll need for this assignment (and CS1729 in general):

  • runtime.js --- Your JavaScript implementation of Pyret's runtime. It corresponds to the file src/lang/runtime.rkt, and will hold your representation of Pyret values, and built-in functions and methods for accessing fields, updating objects, doing primitive arithmetic and string manipulation, etc. It is seeded with a naive representation of numbers, methods, and functions to show one simple approach to the problem.

  • pyret-to-js.arr --- Your Pyret implementation of a Pyret-to-JavaScript compiler. The main entry point is program-to-js(ast :: Program) -> String, which converts a parsed Pyret program to a string of JavaScript code. You will also be completing this implementation, which starts with a naive compilation for numbers, blocks, and application.

    You will need to refer to the definition of the Pyret AST in src/lang/racket-ffi/ast.arr. This is the complete Pyret surface grammar. For now, you only need to support a smaller subset of this (the post-desugaring subset of the language), which is documented below.

  • create-tests.arr --- A script that generates test files to run unit tests on your compiler. It outputs the tests into test-runner/tests.js as a JavaScript program that creates a TESTS datastructure. See the end of the file for example tests. You can run this to re-generate your tests using

      raco pyret --no-checks create-tests.arr
    

    This is probably the most convenient place to add your own tests, but you're free to come up with other ways and extend this framework; it is functional but minimal.

  • test-runner/test-support.js --- This contains JavaScript support for running tests. This is where you can write JavaScript functions to use as predicates on the result of running compiled Pyret programs. Two are defined --- pyretEquals and isNumber --- you will probably want to write more predicates.

  • test-runner/test.html --- You shouldn't need to edit this file, it contains the test runner that uses tests.js and test-support.js to run your unit tests.

The Portion of Pyret You Must Support

Pyret goes through a desugaring phase before reaching core Pyret, which is the language you must compile to JavaScript. As a result, the set of forms you need to handle is much smaller than the entire data definition in ast.arr. You must compile these forms:

  • s_block(l :: Loc, stmts :: List<Expr>) --- A block of expressions as statements that get their own scope
  • s_user_block(l :: Loc, body :: Expr) --- Compiles identically to s_block, indicates that a user used the block: form (rather than an implicit block for a function body, etc.)
  • s_var(l :: Loc, name :: Bind, value :: Expr) --- Note that the desugaring process also checks well-formedness, so you can assume that only variables are used in s_assign expressions.
  • s_let(l :: Loc, name :: Bind, value :: Expr)
  • s_assign(l :: Loc, id :: String, value :: Expr)
  • s_if_else(l :: Loc, branches :: List<IfBranch>, _else :: Expr)
  • s_try(l :: Loc, body :: Expr, id :: Bind, _except :: Expr) --- Pyret's semantics for try/catch is modelled nicely by JavaScript's try/catch.
  • s_lam(l :: Loc, params :: List<String>, args :: List<Bind>, ann :: Ann, doc :: String, body :: Expr, check :: Expr) --- You don't need to worry about anything to do with types/annotations or check blocks. These are completely handled by desugaring and annotation checking before arriving at core Pyret.
  • s_method(l :: Loc, args :: List<Bind>, ann :: Ann, doc :: String, body :: Expr, check :: Expr)
  • s_extend(l :: Loc, super :: Expr, fields :: List<Member>) --- This is the expression form for obj.{field1: val1, ...}
  • s_update(l :: Loc, super :: Expr, fields :: List<Member>) --- This is the expression form for obj!{field1: val1, ...}
  • s_obj(l :: Loc, fields :: List<Member>)
  • s_app(l :: Loc, _fun :: Expr, args :: List<Expr>)
  • s_id(l :: Loc, id :: String) --- You should think carefully about your representation of identifiers that come from your JavaScript implemented runtime.
  • s_num(l :: Loc, n :: Number)
  • s_bool(l :: Loc, b :: Bool)
  • s_str(l :: Loc, s :: String)
  • s_bracket(l :: Loc, obj :: Expr, field :: Expr) --- Important: You can assume for now that field is always an s_str. We'll get to hash tables and computed-string lookup later on.
  • s_colon_bracket(l :: Loc, obj :: Expr, field :: Expr) --- Important: You can assume for now that field is always an s_str. We'll get to hash tables and computed-string lookup later on.
  • s_get_bang(l :: Loc, obj :: Expr, field :: String) --- Corresponds to obj!x expressions
Clone this wiki locally