Giter Site home page Giter Site logo

brownplt / pyret-lang Goto Github PK

View Code? Open in Web Editor NEW
1.1K 43.0 107.0 476.68 MB

The Pyret language.

License: Other

Makefile 0.07% JavaScript 89.01% Shell 0.01% HTML 0.01% Emacs Lisp 0.46% Vim Script 0.02% Pyret 10.43%
pyret education language compiler

pyret-lang's Introduction

Yarr

Build Status

A scripting language.

To learn about the language, visit pyret.org.

To read an introduction of the language, visit the tour.

To read the documentation, visit pyret.org/docs/.

There are three main ways to use Pyret:

  1. If all you want to do is program in Pyret, there is a web-based environment at code.pyret.org that lets you run and save programs that should be all you need. If you're a student using Pyret, this is probably where you will do your assignments, for example.

  2. If all you want to do is program in Pyret at the command line, you should install pyret-npm from https://www.npmjs.com/package/pyret-npm, using an install command like:

    npm install -g pyret-npm
    

    (If you're new to node and npm, you might find https://nodejs.dev/learn/an-introduction-to-the-npm-package-manager and https://nodejs.dev/learn/npm-global-or-local-packages useful background).

  3. If you want to contribute to Pyret, or try out experimental features, the README starting below is for you.

The use of vocabulary from http://bvipirate.com/piratespeak/index.html is recommended when commenting and reporting issues.

Installing

First, make sure you've installed Node >= 6. Then run:

$ npm install
$ make
$ make test

It'll build the Pyret compiler and run the tests.

Running Pyret

If you just want to run Pyret, visit the online environment and work from there. If you're interested in Pyret development, read on:

The easiest way to run a Pyret program from the command-line is:

$ ./src/scripts/phaseX <path-to-pyret-program-here> [command-line-args...]

Where X is 0, A, B, or C, indicating a phase (described below). For example:

$ ./src/scripts/phaseA src/scripts/show-compilation.arr examples/ahoy-world.arr

Alternatively, you can compile and run a standalone JavaScript file via:

$ node build/phaseX/pyret.jarr \
    --build-runnable <path-to-pyret-program-here> \
    --outfile <path-for-standalone-js> \
    --builtin-js-dir src/js/trove/ \
    --builtin-arr-dir src/arr/trove \
    --require-config src/scripts/standalone-configA.json
$ node <path-for-standalone-js>

Phases

Pyret is a self-hosted compiler, which means that building requires some thought. If you're going to get into the guts of the compiler, a brief overview is worth reading. The build directory is separated into four distinct phases.

  1. Phase 0 is a standalone JavaScript file that contains an entire compiled Pyret compiler and runtime. This large blob gets committed into version control whenever we add a nontrivial feature to the language. It is large and somewhat slow to load, but whatever is in build/phase0/pyret.jarr is currently the canonical new-world implementation of Pyret.

  2. Phase A is set up to be populated with built versions of all the files for the compiler, built by the phase 0 compiler. Phase A is what most of the testing scripts run against, since it is the easiest to create, and after it is built it is your development snapshot of the compiler you're working on. However, just building phase1 is not enough to fully re-boostrap the compiler, because it contains a mix of old-compiler output and any new changes that were made to runtime files.

  3. Phase B is set up to be populated with built versions of all the files for the compiler, built by the phase A compiler. This version does represent a fully-bootstrapped compiler. If you run make phaseB, you get a new standalone compiler in the same format as build/phase0/pyret.js.

  4. Phase C builds from phase B. One major use of phase C is to check the bootstrapped compiler from phase B. Before committing a new standalone in phase 0, build both phaseB and phaseC, and check:

    $ diff build/phaseB/pyret.jarr build/phaseC/pyret.jarr
    

    And it should be empty, which indicates that the bootstrapped compiler is at least correct enough to recompile itself without error.

    To rebuild the compiler and get a new phase0, run

    $ make new-bootstrap
    

    which will build the phaseB and phaseC standalones, check the diff, and copy to phase0 if the diff is empty.

pyret-lang's People

Contributors

awan1 avatar awstlaur avatar ayazhafiz avatar blerner avatar dbp avatar dpcollin avatar ds26gte avatar ejcaruso avatar ericson2314 avatar innpatron avatar jonahkagan avatar jpolitz avatar jswrenn avatar justinpombrio avatar kfisler avatar kmicklas avatar melloc avatar mkolosick avatar peblair avatar puppyofkosh avatar robertdurst avatar rrshaban avatar sarahkf avatar schanzer avatar sdooman avatar shriram avatar sorawee avatar sstrickl avatar thejakeellis avatar zacharyespiritu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyret-lang's Issues

Need a check-exn form

We need a form in checkers like:

check-exn(thunk, pred)

That runs, roughly:

try:
  thunk()
  failure('No exception raised')
except(e):
  ans = pred(e)
  case:
    | ans => success
    | else => failure('Wrong exception raised')
  end
end

Spaces not allowed in functions

We should allow

fun (): stuff end

and

fun f (): stuff end

Which are currently parse errors because we only allow PARENNOSPACE to start the args.

Lazy and and or

We should desugar special keywords and and or to thunked method calls.

Awkward error message when brand-checkers and constructors are mistaken

The following code

data Example:
  | example(a, b, c)
end
fun foo(e :: example): ... end

will give an error when run: Uncaught exception Arity mismatch: expected 3 arguments but got 1. The 1 provided argument(s) are ...

This is absolutely correct, but utterly misleading :) It'd be nice if you could check that the functions used as type assertions are always unary, so that this mistake can't happen quite so easily...

Clean up stack traces

Ben is getting stuff that looks like this, which are a little verbose.

Ben@bsl-asus /cygdrive/c/Users/Ben/Documents/Brown/acquired-taste
$ raco pyret align-trees.arr
[pyret] Runtime error:

C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:805:28: Uncaught exception id was not found

At:
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:805:28
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:784:2
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:792:20
setup.rkt:403:0
setup.rkt:403:0
setup.rkt:403:0
setup.rkt:403:0
setup.rkt:403:0
setup.rkt:403:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:784:2
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:792:20
setup.rkt:403:0
setup.rkt:403:0
setup.rkt:403:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:784:2
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:792:20
setup.rkt:403:0
setup.rkt:403:0
setup.rkt:403:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:784:2
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:824:4
setup.rkt:244:0
setup.rkt:244:0
setup.rkt:244:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:781:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:781:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:781:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:1038:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:1038:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:1038:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:1047:2
setup.rkt:396:0
setup.rkt:396:0
setup.rkt:396:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:1045:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:1045:0
C:\Users\Ben\Documents\Brown\acquired-taste\align-trees.arr:1045:0

Consider ==> instead of => for case answer delimiter

First pyret program I tried to write checked whether a number was within certain ranges. So I had something like

case:
| (100 <= val) and (val <= 500) => "yes"
end

The similarity between => and arithmetic operators looked jarring. Not wedded to my particular proposal, but something more different from a common beginner operator might be wise.

Kathi

builtins.equiv

We should write a builtins.equiv that checks structural equality of objects. It should be the default equality for things like e.g. List when that kicks out to other objects.

NOTE: We may even consider desugaring == to builtins.equiv rather than the equals method, or having == desugar to one and === desugar to the other, etc.

#<undefined> is visible in shadowing bindings

x = "toplevel"
case:
  | else =>
    x = x
    print(x)
end

#==> undefined

I thought letrec* would handle this properly, but some testing suggests that it doesn't. We may need our own binding macro defined in runtime.

Data with blocks sometimes fail to wrap arguments

data D:
    | thing() with: meth(self :: D, id :: Number): id end
end
thing().meth('not-a-num')

This program does not fail with a contract check. There is a missed case for method-wrapping in typecheck.rkt, needs to be found, fixed, and tested.

checkers should take a message parameter

Checkers don't take any information other than the values to check. They should take a message for better error reporting. e.g.

checkers.check-equals("Testing true and false", true, false)
checkers.check-equals("Testing true and false, but again!", true, false)

Would show two different failures with different messages

list.each is the same as list.iter

I'd defined list.iter, list.iter2 ... list.iter4 functions that iterate through a list solely for side effects. The new each method does the same thing, for a single list, and list.each is identical to list.iter. We should clean up the duplication, and pick just one or the other name.

change doc to purpose

Docstrings should be identified by "purpose:" not "doc", to not steal keywords and to make it more apparent what it means

Pyret's initial imports take more than 100ms

These programs are slow and they shouldn't be (this is after raco make):

$ time racket src/lang/tokenizer.rkt

real 0m0.272s
user 0m0.236s
sys 0m0.032s

$ time racket src/lang/grammar.rkt

real 0m0.221s
user 0m0.184s
sys 0m0.028s

$ time racket src/lang/desugar.rkt

real 0m0.442s
user 0m0.392s
sys 0m0.048s

Bare check blocks

We should allow bare check blocks that are not associated with any data or fun definition, since checks don't always only apply to one thing.

Broader tag tests

It's easy to check for number-ness or string-ness, but not for object-ness or function-ness

Cleanup list.arr's duplicate functions

map is both a method on lists and a free-floating function, and the mapping algorithm is written twice. Ditto each. But there is no list.filter corresponding to the filter method...

I think since map2, each3, etc exist, and corresponding filter# might be useful, the methods should possibly delegate to the functions. For efficiency (hah! ;-)) you may not want to do this, but it seems conceptually clearer...

Contracts on builtins

Many builltins, like _divide and substring, are partial, and give contract errors for erroneous inputs. We should turn these errors into meaningful Pyret errors somehow, and avoid paying to much to do so (that's the hard part).

Arity errors in cases

If the wrong number of fields are provided at a case match, the error location reported is at the line number of the constructor for that variant. It should be the line number of the case.

list functions do poor type-testing

Many list functions (e.g. iter and map and friends), don't have annotations and have an else clause that blows up on non-Lists with unfriendly error messages like first not found.

Matrices as a datatype

For graphics (e.g. seam-carving), pagerank-like algorithms, etc, it would be useful to have a matrix or spreadsheet-like datatype.

String method impoverished

Strings need comparison (e.g. string<) and deconstruction (e.g. charAt, string->list), for them to be really useful.

Parse errors not in the main file are not caught properly

In our project, file align-trees.arr includes labelled-tree.arr. If there's a parse error in labelled-tree.arr, and I run raco pyret labelled-tree.arr, the error message is properly trapped and printed. If I run raco pyret align-trees.arr, though, the error isn't trapped:

Ben@bsl-asus /cygdrive/c/Users/Ben/Documents/Brown/acquired-taste
$ raco pyret align-trees.arr
Uncaught Racket-land error that Pyret does not understand yet:
#(struct:exn:fail:parsing Encountered parsing error near token '|)| (")") while parsing #<path:C:\Users\Ben\Documents\Brown\acquired-taste\labelled-tree.arr> [line=198, column=51, offset=5389] #<continuation-mark-set> (#(struct:srcloc C:\Users\Ben\Documents\Brown\acquired-taste\labelled-tree.arr 198 51 5389 1)))((#f . #(struct:srcloc C:\Users\Ben\Documents\Brown\pyret-lang\lib\ragg\ragg\private\internal-support.rkt 16 3 388 442)) (pyret->racket7 . #(struct:srcloc C:\Users\Ben\Documents\Brown\pyret-lang\src\lang\eval.rkt 34 0 587 471)) (my-read-syntax . #(struct:srcloc C:\Users\Ben\Documents\Brown\pyret-lang\src\lang\pyret.rkt 35 0 822 645)) (standard-module-name-resolver . #f) (expand-import . #(struct:srcloc C:\Program Files\Racket\collects\racket\require-transform.rkt 266 2 10989 3465)) (#f . #(struct:srcloc C:\Program Files\Racket\collects\racket\private\reqprov.rkt 520 5 22396 3667)) (expand-import . #(struct:srcloc C:\Program Files\Racket\collects\racket\require-transform.rkt 266 2 10989 3465)) (try-next . #f) (#f . #(struct:srcloc C:\Program Files\Racket\collects\racket\private\reqprov.rkt 242 2 9502 6468)) (#f . #(struct:srcloc C:\Program Files\Racket\collects\racket\private\modbeg.rkt 46 4 1168 5760)))

Please copy/paste this exception in an email to [email protected].

Ben@bsl-asus /cygdrive/c/Users/Ben/Documents/Brown/acquired-taste
$ raco pyret labelled-tree.arr
[pyret] Error in parsing:

Encountered parsing error near token '|)| (")") while parsing #<path:C:\Users\Ben\Documents\Brown\acquired-taste\labelled-tree.arr> [line=198, column=51, offset=5389]

At:
C:\Users\Ben\Documents\Brown\acquired-taste\labelled-tree.arr:198:51

Can't catch contract exceptions

The following code will both print the error message, and still fail with an uncaught exception:

try:
  1.equals(nothing)
except(e):
  print(tostring(e))
  nothing
end

Especially while issue #6 is still open, this means there's no way I can squash errors that aren't fatal...

Desugar binding statements to not return values when at the end of blocks

Right now we have somewhat strange semantics: if a binding statement occurs as the last statement in a block, the RHS is returned as the value of the block. This is strange, because binding statements normally do not evaluate to values - you cannot create a binding with a binding on the RHS.

Proposed desugaring is to convert all binding statements to be the binding followed immediately by "nothing", thus binding statements will never be the last value in a block, and the strange semantics will go away.

Undefined values in check blocks don't produce proper errors

The following code

fun map-concat(f, l):
  fun help(l, acc):
    case:
      | list.is-empty(l) => acc
      | else => help(l.rest, f(l.first).append(acc))
    end
  end
  help(l, [])
check:
#  eq = checkers.check-equals
  eq("[1,2,3] => [3,6,2,4,1,2]", 
    map-concat(fun(x): [x, 2*x] end, [1,2,3]), [3,6,2,4,1,2])
end

neglects to define eq as an alias for checkers.check-equals. This produces the following output:

$ raco pyret --check labelled-tree.arr
eq: undefined;
 cannot reference undefined identifier

Rather than saying something like Total: 1, Passed: 0, Errors in tests: 1

_ doesn't work with try-except

Try-except blocks give exceptions when an _ is used as the exception variable, e.g.

try:
   raise("err")
except(_):
   print("something happened")
end

Gives:

g4142: unbound identifier in module in: g4142

Preserve brands when adding fields

This is something we've thrown around a lot as a good thing to do. I think it has the real potential to bite us with lists.

We present lists as this nice data type, but also point out that they are objects and we can add fields to them. But if we add fields to them, we no longer have lists, which I think could be really confusing.

It's a place where our abstraction breaks down, and the only way to explain it is to explain the desugaring of data and the semantics of brands (or just appeal to authority).

Is this something we should deal with before the fall? It should actually be easy to implement - when updating an object, if none of the fields are already on the object, we don't throw out the brands.

The generalization of this (which is that brands only make positive assertions, and we preserve an ordering of fields and brands, and updating a field only removes the brands that were added later than it) is harder, and would involve different value representation.

Minor To Fix: check => where, multi-line strings, where standalone, is

These are things that are minor, but should be fixed. Moreover, in the language introduction, I'm writing as though they were fixed. So they really need to get fixed.

  • check blocks renamed to where blocks. Identical semantics.
  • add standalone where blocks, not attached to functions or data
  • allow line breaks in strings, so that doc strings can be more useful
  • make the doc string desugaring add function names and headers, and have tostring
    on functions return the doc string.
  • add is syntax sugar for checkers.check-equals
  • ... maybe more small things

Test framework sandbox is borked

With the addition of big-bang to the runtime, the test sandbox now asks for permissions to weird things like racket-prefs.rktd, and sometimes complains about being out of memory.

Pyret hangs when a missing field is referenced in the tostring() method

The following code will hang:

#lang pyret

data Foo:
  | foo(s) with:
      tostring(self): self.not-found end
end

fun f():
  aFoo = foo("x")
  aFoo.not-found
end
f()

If you fix self.not-found to be self.s instead, then tostring() completes successfully and the program halts with an error that not-found is indeed not found. If you fix aFoo.not-found, then the program doesn't cause an error in the first place. But if you leave it as is, then Pyret calls tostring while formatting the error message, which in turn triggers another error, which causes Pyret to call tostring again...

I heard you liked error messages in your error messages, so I put some errors in your error handlers...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.