Skip to content

Commit

Permalink
Merge pull request #122 from evhub/develop
Browse files Browse the repository at this point in the history
Release v1.1.1
  • Loading branch information
evhub authored Jul 6, 2016
2 parents a6eee92 + 8198730 commit 3ae4c27
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 53 deletions.
33 changes: 21 additions & 12 deletions DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,20 @@ While most of Coconut gets its inspiration simply from trying to make functional

### Installation

Since Coconut is hosted on the [Python Package Index](https://pypi.python.org/pypi/coconut), it can be installed easily using `pip`. Simply install [Python](https://www.python.org/downloads/), open up a command-line prompt, and enter:
Since Coconut is hosted on the [Python Package Index](https://pypi.python.org/pypi/coconut), it can be installed easily using `pip`. Simply install [Python](https://www.python.org/downloads/), open up a command-line prompt, and enter
```
python -m pip install coconut
```
which will install Coconut and its required dependencies. Coconut also has some optional dependencies, which can be installed by entering
```
python -m pip install coconut[all]
```
which will enable the use of Coconut's `--autopep8` and `--watch` flags. To install the optional dependencies only for a particular flag, simply put the flag name in place of `all`.

### Usage

```
coconut [-h] [-v] [source] [dest] [-t version] [-s] [-l] [-p] [-a] [-f] [-d] [-r] [-n] [-m] [-i] [-q] [-c code] [--jupyter ...] [--autopep8 ...] [--recursionlimit limit] [--color color] [--verbose]
coconut [-h] [-v] [source] [dest] [-t version] [-s] [-l] [-p] [-a] [-w] [-f] [-d] [-r] [-n] [-m] [-i] [-q] [-c code] [--jupyter ...] [--autopep8 ...] [--recursionlimit limit] [--color color] [--verbose]
```

#### Positional Arguments
Expand All @@ -118,6 +123,7 @@ dest destination directory for compiled files (defaults to the
-l, --linenumbers add line number comments for ease of debugging
-p, --package compile source as part of a package (defaults to only if source is a directory)
-a, --standalone compile source as standalone files (defaults to only if source is a single file)
-w, --watch watch a directory and recompile on changes (requires watchdog)
-f, --force force overwriting of compiled Python (otherwise only overwrites when source code or compilation parameters change)
-d, --display print compiled Python
-r, --run run compiled Python (often used with --nowrite)
Expand All @@ -127,7 +133,7 @@ dest destination directory for compiled files (defaults to the
-q, --quiet suppress all informational output (combine with --display to write runnable code to stdout)
-c code, --code code run a line of Coconut passed in as a string (can also be passed into stdin)
--jupyter, --ipython run Jupyter/IPython with Coconut as the kernel (remaining args passed to Jupyter)
--autopep8 ... use autopep8 to format compiled code (remaining args passed to autopep8)
--autopep8 ... use autopep8 to format compiled code (remaining args passed to autopep8) (requires autopep8)
--recursionlimit set maximum recursion depth (default is system dependent)
--tutorial open the Coconut tutorial in the default web browser
--documentation open the Coconut documentation in the default web browser
Expand Down Expand Up @@ -400,6 +406,7 @@ Coconut supports Unicode alternatives to many different operator symbols. The Un
↑ (\u2191) => "**"
÷ (\xf7) => "/"
÷/ (\xf7/) => "//"
∘ (\u2218) => ".."
− (\u2212) => "-" (only subtraction)
⁻ (\u207b) => "-" (only negation)
¬ (\xac) => "~"
Expand Down Expand Up @@ -756,11 +763,12 @@ _Can't be done without a complicated iterator comprehension in place of the lazy

Coconut supports a number of different syntactical aliases for common partial application use cases. These are:
```coconut
.name => operator.attrgetter("name")
obj. => getattr$(obj)
func$ => ($)$(func)
seq[] => operator.__getitem__$(seq)
iter$[] => # the equivalent of seq[] for iterators
.attr => operator.attrgetter("attr")
.method(args) => operator.methodcaller("method", args)
obj. => getattr$(obj)
func$ => ($)$(func)
seq[] => operator.__getitem__$(seq)
iter$[] => # the equivalent of seq[] for iterators
```

##### Example
Expand Down Expand Up @@ -1486,13 +1494,14 @@ A `MatchError` is raised when a [destructuring assignment](#destructuring-assign

### Syntax Highlighting

There are currently three options for Coconut syntax highlighting:
The current options for Coconut syntax highlighting are:

1. use [SublimeText](https://www.sublimetext.com/),
2. use an editor that supports [Pygments](http://pygments.org/), or
3. just treat Coconut as Python.
2. use an editor that supports [Pygments](http://pygments.org/),
3. use [this 3rd party Vim highlighter](https://github.com/manicmaniac/coconut.vim) or [this 3rd party Emacs highlighter](https://github.com/NickSeagull/coconut-mode), or
4. just treat Coconut as Python.

Instructions on how to set up syntax highlighting for SublimeText and Pygments are included below. If you don't like SublimeText and your chosen alternative text editor doesn't have pygments support, however, it should be sufficient to set up your editor so it interprets all `.coco` (also `.coc` and `.coconut`, although `.coco` is the preferred extension) files as Python code, as this should highlight most of your code well enough.
Instructions on how to set up syntax highlighting for SublimeText and Pygments are included below. If one of the actual highlighters above doesn't work, however, it should be sufficient to set up your editor so it interprets all `.coco` (also `.coc` and `.coconut`, although `.coco` is the preferred extension) files as Python code, as this should highlight most of your code well enough.

#### SublimeText

Expand Down
5 changes: 5 additions & 0 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<!-- MarkdownTOC -->

1. [Can I use Python modules from Coconut and Coconut modules from Python?](#can-i-use-python-modules-from-coconut-and-coconut-modules-from-python)
1. [What versions of Python does Coconut support?](#what-versions-of-python-does-coconut-support)
1. [If I'm already perfectly happy with Python, why should I learn Coconut?](#if-im-already-perfectly-happy-with-python-why-should-i-learn-coconut)
1. [How will I be able to debug my Python if I'm not the one writing it?](#how-will-i-be-able-to-debug-my-python-if-im-not-the-one-writing-it)
Expand All @@ -16,6 +17,10 @@

<!-- /MarkdownTOC -->

### Can I use Python modules from Coconut and Coconut modules from Python?

Yes and yes! Coconut compiles to Python, so Coconut modules are accessible from Python and Python modules are accessible from Coconut, including the entire Python standard library.

### What versions of Python does Coconut support?

Coconut supports any Python version `>= 2.6` on the `2.x` branch or `>= 3.2` on the `3.x` branch. See [compatible Python versions](http://coconut.readthedocs.io/en/master/DOCS.html#compatible-python-versions) for more information.
Expand Down
3 changes: 2 additions & 1 deletion HELP.md
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,8 @@ plus1..square(3) == 10

Last is implicit partials. Coconut supports a number of different "incomplete" expressions that will evaluate to a function that takes in the part necessary to complete them, that is, an implicit partial application function. The different allowable expressions are:
```coconut
.name
.attr
.method(args)
obj.
func$
seq[]
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ after which the entire world of Coconut will be at your disposal. To help you ge
- Docs_: If you're looking for info about a specific feature, Coconut's Docs provide a **complete documentation** of the language.
- FAQ_: If you have questions about who Coconut is built for and whether or not you should use it, Coconut's frequently asked questions have you covered.
- `Create a New Issue <https://github.com/evhub/coconut/issues/new>`_: If you're having a problem with Coconut, creating a new issue detailing the problem will allow it to be addressed as soon as possible.
- Gitter_: For all general questions, concerns, or comments about anything Coconut-related, ask around at Coconut's Gitter, a GitHub-integrated chat room for Coconut developers.
- Gitter_: For any questions, concerns, or comments about anything Coconut-related, ask around at Coconut's Gitter, a GitHub-integrated chat room for Coconut developers.

*Note: If the above documentation links are not working, try the* |mirror|_ *.*

Expand Down
51 changes: 48 additions & 3 deletions coconut/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#-----------------------------------------------------------------------------------------------------------------------

"""
Author: Evan Hubinger
Authors: Evan Hubinger, Fred Buchanan
License: Apache 2.0
Description: Processes arguments to the Coconut command-line utility.
"""
Expand All @@ -17,9 +17,11 @@
from __future__ import print_function, absolute_import, unicode_literals, division

from .compiler import *
import sys
import os
import os.path
import argparse
import time

#-----------------------------------------------------------------------------------------------------------------------
# CONSTANTS:
Expand Down Expand Up @@ -252,6 +254,7 @@ class cli(object):
commandline.add_argument("-l", "--linenumbers", action="store_const", const=True, default=False, help="add line number comments for ease of debugging")
commandline.add_argument("-p", "--package", action="store_const", const=True, default=False, help="compile source as part of a package (defaults to only if source is a directory)")
commandline.add_argument("-a", "--standalone", action="store_const", const=True, default=False, help="compile source as standalone files (defaults to only if source is a single file)")
commandline.add_argument("-w", "--watch", action="store_const", const=True, default=False, help="watch a directory and recompile on changes (requires watchdog)")
commandline.add_argument("-f", "--force", action="store_const", const=True, default=False, help="force overwriting of compiled Python (otherwise only overwrites when source code or compilation parameters change)")
commandline.add_argument("-d", "--display", action="store_const", const=True, default=False, help="print compiled Python")
commandline.add_argument("-r", "--run", action="store_const", const=True, default=False, help="run compiled Python (often used with --nowrite)")
Expand All @@ -261,7 +264,7 @@ class cli(object):
commandline.add_argument("-q", "--quiet", action="store_const", const=True, default=False, help="suppress all informational output (combine with --display to write runnable code to stdout)")
commandline.add_argument("-c", "--code", metavar="code", type=str, nargs=1, default=None, help="run a line of Coconut passed in as a string (can also be passed into stdin)")
commandline.add_argument("--jupyter", "--ipython", type=str, nargs=argparse.REMAINDER, default=None, help="run Jupyter/IPython with Coconut as the kernel (remaining args passed to Jupyter)")
commandline.add_argument("--autopep8", type=str, nargs=argparse.REMAINDER, default=None, help="use autopep8 to format compiled code (remaining args passed to autopep8)")
commandline.add_argument("--autopep8", type=str, nargs=argparse.REMAINDER, default=None, help="use autopep8 to format compiled code (remaining args passed to autopep8) (requires autopep8)")
commandline.add_argument("--recursionlimit", metavar="limit", type=int, nargs=1, default=[None], help="set maximum recursion depth (defaults to "+str(sys.getrecursionlimit())+")")
commandline.add_argument("--tutorial", action="store_const", const=True, default=False, help="open the Coconut tutorial in the default web browser")
commandline.add_argument("--documentation", action="store_const", const=True, default=False, help="open the Coconut documentation in the default web browser")
Expand Down Expand Up @@ -326,6 +329,8 @@ def cmd(self, args, interact=True):
if args.source is not None:
if args.run and os.path.isdir(args.source):
raise CoconutException("source path must point to file not directory when --run is enabled")
elif args.watch and os.path.isfile(args.source):
raise CoconutException("source path must point to directory not file when --watch is enabled")
if args.dest is None:
if args.nowrite:
dest = None # no dest
Expand All @@ -346,7 +351,12 @@ def cmd(self, args, interact=True):
else:
package = None # auto-decide package
self.compile_path(args.source, dest, package, args.run, args.force)
elif args.run or args.nowrite or args.force or args.package or args.standalone:
elif (args.run
or args.nowrite
or args.force
or args.package
or args.standalone
or args.watch):
raise CoconutException("a source file/folder must be specified when options that depend on the source are enabled")
if args.code is not None:
self.execute(self.proc.parse_block(args.code[0]))
Expand All @@ -362,9 +372,12 @@ def cmd(self, args, interact=True):
or args.code
or args.tutorial
or args.documentation
or args.watch
or args.jupyter is not None
)):
self.start_prompt()
if args.watch:
self.watch(args.source, dest, package, args.run, args.force)
except CoconutException:
self.print_exc()
sys.exit(1)
Expand Down Expand Up @@ -622,3 +635,35 @@ def start_jupyter(self, args):
raise CoconutException('first argument after --jupyter must be either "console" or "notebook"')
self.log_cmd(run_args)
subprocess.call(run_args)

def watch(self, source, write=True, package=None, run=False, force=False):
"""Watches a source and recompiles on change."""
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer

def recompile(path):
if os.path.isfile(path) and os.path.splitext(path)[1] in code_exts:
self.compile_path(path, write, package, run, force)

class watcher(FileSystemEventHandler):
def on_modified(_, event):
recompile(event.src_path)
def on_created(_, event):
recompile(event.src_path)

source = fixpath(source)

self.console.show("Watching "+showpath(source)+" ...")
self.console.print("(press Ctrl-C to end)")

observer = Observer()
observer.schedule(watcher(), source, recursive=True)
observer.start()
try:
while True:
time.sleep(.1)
except KeyboardInterrupt:
pass
finally:
observer.stop()
observer.join()
40 changes: 22 additions & 18 deletions coconut/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
holds = "'\""
tabideal = 4 # worth of tabs in spaces for displaying
tabworth = 8 # worth of tabs in spaces for parsing (8 = Python standard)
reserved_prefix = "_coconut"
decorator_var = "_coconut_decorator"
match_to_var = "_coconut_match_to"
match_check_var = "_coconut_match_check"
Expand Down Expand Up @@ -707,6 +708,8 @@ def attr_handle(tokens):
"""Processes attrgetter literals."""
if len(tokens) == 1:
return '_coconut.operator.attrgetter("'+tokens[0]+'")'
elif len(tokens) == 2:
return '_coconut.operator.methodcaller("'+tokens[0]+'", '+tokens[1]+")"
else:
raise CoconutException("invalid attrgetter literal tokens", tokens)

Expand Down Expand Up @@ -2133,7 +2136,7 @@ def name_handle(self, original, location, tokens):
"""Handles variable names."""
if len(tokens) != 1:
raise CoconutException("invalid name tokens", tokens)
elif tokens[0].startswith("_coconut"):
elif tokens[0].startswith(reserved_prefix):
if self.strict:
raise self.make_err(CoconutStyleError, "found use of a reserved variable", original, location)
else:
Expand Down Expand Up @@ -2291,7 +2294,7 @@ def set_letter_literal_handle(self, tokens):
dubstar = Literal("**")
star = ~dubstar+Literal("*")
at = Literal("@")
arrow = fixto(Literal("->") | Literal("\u2192"), "->")
arrow = Literal("->") | fixto(Literal("\u2192"), "->")
dubcolon = Literal("::")
unsafe_colon = Literal(":")
colon = ~dubcolon+unsafe_colon
Expand All @@ -2310,20 +2313,20 @@ def set_letter_literal_handle(self, tokens):
minus = ~Literal("->")+Literal("-")
dubslash = Literal("//")
slash = ~dubslash+Literal("/")
pipeline = fixto(Literal("|>") | Literal("\u21a6"), "|>")
starpipe = fixto(Literal("|*>") | Literal("*\u21a6"), "|*>")
backpipe = fixto(Literal("<|") | Literal("\u21a4"), "<|")
backstarpipe = fixto(Literal("<*|") | Literal("\u21a4*"), "<*|")
amp = fixto(Literal("&") | Literal("\u2227") | Literal("\u2229"), "&")
caret = fixto(Literal("^") | Literal("\u22bb") | Literal("\u2295"), "^")
bar = fixto(~Literal("|>")+~Literal("|*>")+Literal("|") | Literal("\u2228") | Literal("\u222a"), "|")
pipeline = Literal("|>") | fixto(Literal("\u21a6"), "|>")
starpipe = Literal("|*>") | fixto(Literal("*\u21a6"), "|*>")
backpipe = Literal("<|") | fixto(Literal("\u21a4"), "<|")
backstarpipe = Literal("<*|") | fixto(Literal("\u21a4*"), "<*|")
amp = Literal("&") | fixto(Literal("\u2227") | Literal("\u2229"), "&")
caret = Literal("^") | fixto(Literal("\u22bb") | Literal("\u2295"), "^")
bar = ~Literal("|>")+~Literal("|*>")+Literal("|") | fixto(Literal("\u2228") | Literal("\u222a"), "|")
percent = Literal("%")
dotdot = ~Literal("...")+Literal("..")
dotdot = ~Literal("...")+Literal("..") | fixto(Literal("\u2218"), "..")
dollar = Literal("$")
ellipses = fixto(Literal("...") | Literal("\u2026"), "...")
lshift = fixto(Literal("<<") | Literal("\xab"), "<<")
rshift = fixto(Literal(">>") | Literal("\xbb"), ">>")
tilde = fixto(Literal("~") | ~Literal("\xac=")+Literal("\xac"), "~")
lshift = Literal("<<") | fixto(Literal("\xab"), "<<")
rshift = Literal(">>") | fixto(Literal("\xbb"), ">>")
tilde = Literal("~") | fixto(~Literal("\xac=")+Literal("\xac"), "~")
underscore = Literal("_")
pound = Literal("#")
backtick = Literal("`")
Expand All @@ -2332,17 +2335,17 @@ def set_letter_literal_handle(self, tokens):

lt = ~Literal("<<")+~Literal("<=")+Literal("<")
gt = ~Literal(">>")+~Literal(">=")+Literal(">")
le = fixto(Literal("<=") | Literal("\u2264"), "<=")
ge = fixto(Literal(">=") | Literal("\u2265"), ">=")
ne = fixto(Literal("!=") | Literal("\xac=") | Literal("\u2260"), "!=")
le = Literal("<=") | fixto(Literal("\u2264"), "<=")
ge = Literal(">=") | fixto(Literal("\u2265"), ">=")
ne = Literal("!=") | fixto(Literal("\xac=") | Literal("\u2260"), "!=")

mul_star = fixto(star | Literal("\u22c5"), "*")
exp_dubstar = fixto(dubstar | Literal("\u2191"), "**")
neg_minus = fixto(minus | Literal("\u207b"), "-")
sub_minus = fixto(minus | Literal("\u2212"), "-")
div_slash = fixto(slash | Literal("\xf7")+~slash, "/")
div_dubslash = fixto(dubslash | Combine(Literal("\xf7")+slash), "//")
matrix_at_ref = at | Literal("\xd7")
matrix_at_ref = fixto(at | Literal("\xd7"), "@")
matrix_at = Forward()

name = Forward()
Expand Down Expand Up @@ -2506,7 +2509,8 @@ def set_letter_literal_handle(self, tokens):
keyword_atom |= Keyword(const_vars[x])
string_atom = addspace(OneOrMore(string))
passthrough_atom = addspace(OneOrMore(passthrough))
attr_atom = attach(condense(dot.suppress() + name), attr_handle)
methodcaller_args = itemlist(condense(callarg + default), comma) | op_item
attr_atom = attach(dot.suppress() + name + Optional(lparen.suppress() + methodcaller_args + rparen.suppress()), attr_handle)
set_literal = Forward()
set_letter_literal = Forward()
set_s = fixto(CaselessLiteral("s"), "s")
Expand Down
Loading

0 comments on commit 3ae4c27

Please sign in to comment.