Skip to content

CS1729 Assignment 2

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

Compiling Libraries to JS

The goal of this assignment is to get the built-in libraries of Pyret working with your implementation. This will start to get check mode and other full language features working with your implementation.

Due Thursday, October 29, 11:59pm

Submit by emailing me a Github commit link, as before.

Tests to pass will be announced and finalized early this week.

Namespaces

Runtime now exports a namespace, and the output of pyret-to-js now takes an additional "Namespace" argument. The interface of Namespace is what we wrote on the board in class:

merge :: Namespace -> Namespace
get :: String -> PyretValue
set :: String x PyretValue -> Namespace
hasBinding :: String -> Boolean

You should just use this implementation of Namespace for now; it pays special attention to not screwing up e.g. the "proto" field, if you happen to name a Pyret identifier that.

In order to accommodate the new changes, you need to:

  • Make sure makeRuntime() returns an object with two fields:

    namespace: Containing all the bindings of Pyret values (e.g. nothing, is-number, brander), in a Namespace. This is roughly the non-p:-prefixed exports of runtime.rkt

    runtime: A JavaScript object containing runtime methods to be used by your compiled code and by the test framework. This includes makeFailResult and makeNormalResult (used by the test framework), as well as built-in functionality like "getField". This is roughly the p:-prefixed exports of runtime.rkt, but you can adjust exactly what you export here based on what your compiled code needs

  • Change any uses of RUNTIME.actual-pyret-value needs to change to NAMESPACE.get("actual-pyret-value"). In the sample code I've changed, for example:

    RUNTIME.nothing => NAMESPACE.get("nothing")
    
  • (Mostly done for you in example code): Change your compiled output to pass both the result of the program and the toplevel bindings, as a Namespace, to "makeNormalResult". The skeleton code for the s_program case shows a pattern of how to do this, so you need to read and understand that code, and make any necessary adaptations to make it work with your implementation.

Exceptions

Your runtime should export a PyretException type, and when you throw an exception, it must be a PyretException, and other exceptions will be labelled as failures. The content of the exception no longer matters, as long as you throw a PyretException when the test has a non-empty ".err" file.

The goal here is to label things as test failures when they haven't been explicitly thought of as error cases. You should not change any "Not yet implemented" cases to throw PyretExceptions; this is just lying to the test framework. In the future this will help us find all the places where we can improve error messages, though you should do your best to put interesting values in the "exnVal" field of PyretExceptions that would help a user or environment give good debugging information.

New helper functions

A few new helper functions have been provided to you. The "ast" library now has a function called "free-ids", which given an AST, returns a list of strings that contain all the free identifiers in the program. This function assumes nothing about an initial starting environment, so even things like "is-number" are reported as free. This is useful for figuring out which portion of the Namespace is actually used by a program.

In pyret-to-js.arr, a new helper, called "toplevel-ids", has been added. This function takes a Pyret program and returns all the identifiers on the left-hand side of toplevel binding forms. This works over surface as well as desugared ASTs, so if you give it an AST with graph: or data, it will do the Right Thing. The intended use (already done in the sample code) is to construct an export object out of the top-level identifiers in the program.

Testing

There is now support for writing tests that import all the identifiers from a single library. This is initially set up to read all the files in the "moorings-test" directory, and set up a test script for the client that runs moorings, collects its exports, and uses them to run the second file.

If you want to test with files smaller than all of "moorings.arr", which is highly recommended, follow the pattern at the end of create-tests.arr, which show how to set up a simpler library and create tests over it. All of the files in list-lib-tests are set up to only run against the "just-lib.arr" library in libs/. This might help you incrementally get features of "moorings.arr" working.

builtins

There are a few functions in moorings.arr that are exported on the builtins object that won't work with the restriction on not having computed fields on objects. These are:

equiv
data-to-repr
data-equals

You should implement these in your runtime.js, and export them to all Pyret programs as these names.