diff --git a/.hgignore b/.hgignore index c663dc7..e0f3714 100644 --- a/.hgignore +++ b/.hgignore @@ -5,7 +5,6 @@ .vscode docs/.ipynb_checkpoints test/* -gnu-prolog/thun venv build Thun.egg-info diff --git a/docs/VUI-docs/Makefile b/docs/VUI-docs/Makefile deleted file mode 100644 index 69fe55e..0000000 --- a/docs/VUI-docs/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/VUI-docs/build/doctrees/core.doctree b/docs/VUI-docs/build/doctrees/core.doctree deleted file mode 100644 index 555cc59..0000000 Binary files a/docs/VUI-docs/build/doctrees/core.doctree and /dev/null differ diff --git a/docs/VUI-docs/build/doctrees/display.doctree b/docs/VUI-docs/build/doctrees/display.doctree deleted file mode 100644 index 42869cb..0000000 Binary files a/docs/VUI-docs/build/doctrees/display.doctree and /dev/null differ diff --git a/docs/VUI-docs/build/doctrees/environment.pickle b/docs/VUI-docs/build/doctrees/environment.pickle deleted file mode 100644 index ae5e7e7..0000000 Binary files a/docs/VUI-docs/build/doctrees/environment.pickle and /dev/null differ diff --git a/docs/VUI-docs/build/doctrees/index.doctree b/docs/VUI-docs/build/doctrees/index.doctree deleted file mode 100644 index 32d4306..0000000 Binary files a/docs/VUI-docs/build/doctrees/index.doctree and /dev/null differ diff --git a/docs/VUI-docs/build/doctrees/main.doctree b/docs/VUI-docs/build/doctrees/main.doctree deleted file mode 100644 index efb93de..0000000 Binary files a/docs/VUI-docs/build/doctrees/main.doctree and /dev/null differ diff --git a/docs/VUI-docs/build/doctrees/persist_task.doctree b/docs/VUI-docs/build/doctrees/persist_task.doctree deleted file mode 100644 index 9f6ff13..0000000 Binary files a/docs/VUI-docs/build/doctrees/persist_task.doctree and /dev/null differ diff --git a/docs/VUI-docs/build/doctrees/stack_viewer.doctree b/docs/VUI-docs/build/doctrees/stack_viewer.doctree deleted file mode 100644 index c1b5fba..0000000 Binary files a/docs/VUI-docs/build/doctrees/stack_viewer.doctree and /dev/null differ diff --git a/docs/VUI-docs/build/doctrees/text_viewer.doctree b/docs/VUI-docs/build/doctrees/text_viewer.doctree deleted file mode 100644 index 23d65e0..0000000 Binary files a/docs/VUI-docs/build/doctrees/text_viewer.doctree and /dev/null differ diff --git a/docs/VUI-docs/build/doctrees/viewer.doctree b/docs/VUI-docs/build/doctrees/viewer.doctree deleted file mode 100644 index cdd8f21..0000000 Binary files a/docs/VUI-docs/build/doctrees/viewer.doctree and /dev/null differ diff --git a/docs/VUI-docs/build/html/.buildinfo b/docs/VUI-docs/build/html/.buildinfo deleted file mode 100644 index 9ae7c5c..0000000 --- a/docs/VUI-docs/build/html/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 045f1325f6d2a1aed4dff11fe7e98c72 -tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/VUI-docs/build/html/_images/Joy-VUI-screenshot.PNG b/docs/VUI-docs/build/html/_images/Joy-VUI-screenshot.PNG deleted file mode 100644 index 53f7bf1..0000000 Binary files a/docs/VUI-docs/build/html/_images/Joy-VUI-screenshot.PNG and /dev/null differ diff --git a/docs/VUI-docs/build/html/_images/packages_Vui.png b/docs/VUI-docs/build/html/_images/packages_Vui.png deleted file mode 100644 index a1e8936..0000000 Binary files a/docs/VUI-docs/build/html/_images/packages_Vui.png and /dev/null differ diff --git a/docs/VUI-docs/build/html/_modules/index.html b/docs/VUI-docs/build/html/_modules/index.html deleted file mode 100644 index 20e40d1..0000000 --- a/docs/VUI-docs/build/html/_modules/index.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - Overview: module code — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - -
-
- -
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_modules/joy/vui/core.html b/docs/VUI-docs/build/html/_modules/joy/vui/core.html deleted file mode 100644 index 39b8653..0000000 --- a/docs/VUI-docs/build/html/_modules/joy/vui/core.html +++ /dev/null @@ -1,380 +0,0 @@ - - - - - - - - joy.vui.core — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for joy.vui.core

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2019 Simon Forman
-#
-#    This file is part of Thun
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-
-Core
-=====================
-
-The core module defines a bunch of system-wide "constants" (some colors
-and PyGame event groups), the message classes for Oberon-style message
-passing, a "world" class that holds the main context for the system, and
-a mainloop class that manages the, uh, main loop (the PyGame event queue.)
-
-'''
-from sys import stderr
-from traceback import format_exc
-import pygame
-from joy.joy import run
-from joy.utils.stack import stack_to_string
-
-
-COMMITTER = 'Joy <auto-commit@example.com>'
-
-
-BLACK = FOREGROUND = 0, 0, 0
-GREY = 127, 127, 127
-WHITE = BACKGROUND = 255, 255, 255
-BLUE = 100, 100, 255
-GREEN = 70, 200, 70
-
-
-MOUSE_EVENTS = frozenset({
-    pygame.MOUSEMOTION,
-    pygame.MOUSEBUTTONDOWN,
-    pygame.MOUSEBUTTONUP
-    })
-'PyGame mouse events.'
-
-ARROW_KEYS = frozenset({
-    pygame.K_UP,
-    pygame.K_DOWN,
-    pygame.K_LEFT,
-    pygame.K_RIGHT
-    })
-'PyGame arrow key events.'
-
-
-TASK_EVENTS = tuple(range(pygame.USEREVENT, pygame.NUMEVENTS))
-'Keep track of all possible task events.'
-
-AVAILABLE_TASK_EVENTS = set(TASK_EVENTS)
-'Task IDs that have not been assigned to a task.'
-
-ALLOWED_EVENTS = [pygame.QUIT, pygame.KEYUP, pygame.KEYDOWN]
-ALLOWED_EVENTS.extend(MOUSE_EVENTS)
-ALLOWED_EVENTS.extend(TASK_EVENTS)
-'Event "mask" for PyGame event queue, we are only interested in these event types.'
-
-
-ERROR = -1
-PENDING = 0
-SUCCESS = 1
-# 'Message status codes...  dunno if this is a good idea or not...
-
-
-
[docs]class Message(object): - '''Message base class. Contains ``sender`` field.''' - def __init__(self, sender): - self.sender = sender
- - -
[docs]class CommandMessage(Message): - '''For commands, adds ``command`` field.''' - def __init__(self, sender, command): - Message.__init__(self, sender) - self.command = command
- - -
[docs]class ModifyMessage(Message): - ''' - For when resources are modified, adds ``subject`` and ``details`` - fields. - ''' - def __init__(self, sender, subject, **details): - Message.__init__(self, sender) - self.subject = subject - self.details = details
- - -
[docs]class OpenMessage(Message): - ''' - For when resources are modified, adds ``name``, content_id``, - ``status``, and ``traceback`` fields. - ''' - def __init__(self, sender, name): - Message.__init__(self, sender) - self.name = name - self.content_id = self.thing = None - self.status = PENDING - self.traceback = None
- - -
[docs]class PersistMessage(Message): - ''' - For when resources are modified, adds ``content_id`` and ``details`` - fields. - ''' - def __init__(self, sender, content_id, **details): - Message.__init__(self, sender) - self.content_id = content_id - self.details = details
- - -
[docs]class ShutdownMessage(Message): - '''Signals that the system is shutting down.'''
- - -# Joy Interpreter & Context - - -
[docs]class World(object): - ''' - This object contains the system context, the stack, dictionary, a - reference to the display broadcast method, and the log. - ''' - - def __init__(self, stack_id, stack_holder, dictionary, notify, log): - self.stack_holder = stack_holder - self.dictionary = dictionary - self.notify = notify - self.stack_id = stack_id - self.log = log.lines - self.log_id = log.content_id - -
[docs] def handle(self, message): - ''' - Deal with updates to the stack and commands. - ''' - if (isinstance(message, ModifyMessage) - and message.subject is self.stack_holder - ): - self._log_lines('', '%s <-' % self.format_stack()) - if not isinstance(message, CommandMessage): - return - c, s, d = message.command, self.stack_holder[0], self.dictionary - self._log_lines('', '-> %s' % (c,)) - self.stack_holder[0], _, self.dictionary = run(c, s, d) - mm = ModifyMessage(self, self.stack_holder, content_id=self.stack_id) - self.notify(mm)
- - def _log_lines(self, *lines): - self.log.extend(lines) - self.notify(ModifyMessage(self, self.log, content_id=self.log_id)) - - def format_stack(self): - try: - return stack_to_string(self.stack_holder[0]) - except: - print >> stderr, format_exc() - return str(self.stack_holder[0])
- - -
[docs]def push(sender, item, notify, stack_name='stack.pickle'): - ''' - Helper function to push an item onto the system stack with message. - ''' - om = OpenMessage(sender, stack_name) - notify(om) - if om.status == SUCCESS: - om.thing[0] = item, om.thing[0] - notify(ModifyMessage(sender, om.thing, content_id=om.content_id)) - return om.status
- - -
[docs]def open_viewer_on_string(sender, content, notify): - ''' - Helper function to open a text viewer on a string. - Typically used to show tracebacks. - ''' - push(sender, content, notify) - notify(CommandMessage(sender, 'good_viewer_location open_viewer'))
- - -# main loop - - -
[docs]class TheLoop(object): - ''' - The main loop manages tasks and the PyGame event queue - and framerate clock. - ''' - - FRAME_RATE = 24 - - def __init__(self, display, clock): - self.display = display - self.clock = clock - self.tasks = {} - self.running = False - -
[docs] def install_task(self, F, milliseconds): - ''' - Install a task to run every so many milliseconds. - ''' - try: - task_event_id = AVAILABLE_TASK_EVENTS.pop() - except KeyError: - raise RuntimeError('out of task ids') - self.tasks[task_event_id] = F - pygame.time.set_timer(task_event_id, milliseconds) - return task_event_id
- -
[docs] def remove_task(self, task_event_id): - ''' - Remove an installed task. - ''' - assert task_event_id in self.tasks, repr(task_event_id) - pygame.time.set_timer(task_event_id, 0) - del self.tasks[task_event_id] - AVAILABLE_TASK_EVENTS.add(task_event_id)
- - def __del__(self): - # Best effort to cancel all running tasks. - for task_event_id in self.tasks: - pygame.time.set_timer(task_event_id, 0) - -
[docs] def run_task(self, task_event_id): - ''' - Give a task its time to shine. - ''' - task = self.tasks[task_event_id] - try: - task() - except: - traceback = format_exc() - self.remove_task(task_event_id) - print >> stderr, traceback - print >> stderr, 'TASK removed due to ERROR', task - open_viewer_on_string(self, traceback, self.display.broadcast)
- -
[docs] def loop(self): - ''' - The actual main loop machinery. - - Maintain a ``running`` flag, pump the PyGame event queue and - handle the events (dispatching to the display), tick the clock. - - When the loop is exited (by clicking the window close button or - pressing the ``escape`` key) it broadcasts a ``ShutdownMessage``. - ''' - self.running = True - while self.running: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - self.running = False - elif event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: - self.running = False - elif event.type in self.tasks: - self.run_task(event.type) - else: - self.display.dispatch_event(event) - pygame.display.update() - self.clock.tick(self.FRAME_RATE) - self.display.broadcast(ShutdownMessage(self))
-
- -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_modules/joy/vui/display.html b/docs/VUI-docs/build/html/_modules/joy/vui/display.html deleted file mode 100644 index 7ba24d2..0000000 --- a/docs/VUI-docs/build/html/_modules/joy/vui/display.html +++ /dev/null @@ -1,604 +0,0 @@ - - - - - - - - joy.vui.display — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for joy.vui.display

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2019 Simon Forman
-#
-#    This file is part of Thun
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-
-Display
-=================
-
-This module implements a simple visual display system modeled on Oberon.
-
-Refer to Chapter 4 of the Project Oberon book for more information.
-
-There is a Display object that manages a pygame surface and N vertical
-tracks each of which manages zero or more viewers.
-'''
-from copy import copy
-from sys import stderr
-from traceback import format_exc
-import pygame
-from .core import (
-    open_viewer_on_string,
-    GREY,
-    MOUSE_EVENTS,
-    )
-from .viewer import Viewer
-from joy.vui import text_viewer
-
-
-
[docs]class Display(object): - ''' - Manage tracks and viewers on a screen (Pygame surface.) - - The size and number of tracks are defined by passing in at least two - ratios, e.g. Display(screen, 1, 4, 4) would create three tracks, one - small one on the left and two larger ones of the same size, each four - times wider than the left one. - - All tracks take up the whole height of the display screen. Tracks - manage zero or more Viewers. When you "grow" a viewer a new track is - created that overlays or hides one or two existing tracks, and when - the last viewer in an overlay track is closed the track closes too - and reveals the hidden tracks (and their viewers, if any.) - - In order to facilitate command underlining while mouse dragging the - lookup parameter must be a function that accepts a string and returns - a Boolean indicating whether that string is a valid Joy function name. - Typically you pass in the __contains__ method of the Joy dict. This - is a case of breaking "loose coupling" to gain efficiency, as otherwise - we would have to e.g. send some sort of lookup message to the - World context object, going through the whole Display.broadcast() - machinery, etc. Not something you want to do on each MOUSEMOTION - event. - ''' - - def __init__(self, screen, lookup, *track_ratios): - self.screen = screen - self.w, self.h = screen.get_width(), screen.get_height() - self.lookup = lookup - self.focused_viewer = None - self.tracks = [] # (x, track) - self.handlers = [] # Non-viewers that should receive messages. - # Create the tracks. - if not track_ratios: track_ratios = 1, 4 - x, total = 0, sum(track_ratios) - for ratio in track_ratios[:-1]: - track_width = self.w * ratio / total - assert track_width >= 10 # minimum width 10 pixels - self._open_track(x, track_width) - x += track_width - self._open_track(x, self.w - x) - - def _open_track(self, x, w): - '''Helper function to create the pygame surface and Track.''' - track_surface = self.screen.subsurface((x, 0, w, self.h)) - self.tracks.append((x, Track(track_surface))) - -
[docs] def open_viewer(self, x, y, class_): - ''' - Open a viewer of class_ at the x, y location on the display, - return the viewer. - ''' - track = self._track_at(x)[0] - V = track.open_viewer(y, class_) - V.focus(self) - return V
- -
[docs] def close_viewer(self, viewer): - '''Close the viewer.''' - for x, track in self.tracks: - if track.close_viewer(viewer): - if not track.viewers and track.hiding: - i = self.tracks.index((x, track)) - self.tracks[i:i + 1] = track.hiding - assert sorted(self.tracks) == self.tracks - for _, exposed_track in track.hiding: - exposed_track.redraw() - if viewer is self.focused_viewer: - self.focused_viewer = None - break
- -
[docs] def change_viewer(self, viewer, y, relative=False): - ''' - Adjust the top of the viewer to a new y within the boundaries of - its neighbors. - - If relative is False new_y should be in screen coords, else new_y - should be relative to the top of the viewer. - ''' - for _, track in self.tracks: - if track.change_viewer(viewer, y, relative): - break
- -
[docs] def grow_viewer(self, viewer): - ''' - Cause the viewer to take up its whole track or, if it does - already, take up another track, up to the whole screen. - - This is the inverse of closing a viewer. "Growing" a viewer - actually creates a new copy and a new track to hold it. The old - tracks and viewers are retained, and they get restored when the - covering track closes, which happens automatically when the last - viewer in the covering track is closed. - ''' - for x, track in self.tracks: - for _, V in track.viewers: - if V is viewer: - return self._grow_viewer(x, track, viewer)
- - def _grow_viewer(self, x, track, viewer): - '''Helper function to "grow" a viewer.''' - new_viewer = None - - if viewer.h < self.h: - # replace the track with a new track that contains - # a copy of the viewer at full height. - new_track = Track(track.surface) # Reuse it, why not? - new_viewer = copy(viewer) - new_track._grow_by(new_viewer, 0, self.h - viewer.h) - new_track.viewers.append((0, new_viewer)) - new_track.hiding = [(x, track)] - self.tracks[self.tracks.index((x, track))] = x, new_track - - elif viewer.w < self.w: - # replace two tracks - i = self.tracks.index((x, track)) - try: # prefer the one on the right - xx, xtrack = self.tracks[i + 1] - except IndexError: - i -= 1 # okay, the one on the left - xx, xtrack = self.tracks[i] - hiding = [(xx, xtrack), (x, track)] - else: - hiding = [(x, track), (xx, xtrack)] - # We know there has to be at least one other track because it - # there weren't then that implies that the one track takes up - # the whole display screen (the only way you can get just one - # track is by growing a viewer to cover the whole screen.) - # Ergo, viewer.w == self.w, so this branch doesn't run. - new_x = min(x, xx) - new_w = track.w + xtrack.w - r = new_x, 0, new_w, self.h - new_track = Track(self.screen.subsurface(r)) - new_viewer = copy(viewer) - r = 0, 0, new_w, self.h - new_viewer.resurface(new_track.surface.subsurface(r)) - new_track.viewers.append((0, new_viewer)) - new_track.hiding = hiding - self.tracks[i:i + 2] = [(new_x, new_track)] - new_viewer.draw() - - return new_viewer - - def _move_viewer(self, to, rel_y, viewer, _x, y): - ''' - Helper function to move (really copy) a viewer to a new location. - ''' - h = to.split(rel_y) - new_viewer = copy(viewer) - if not isinstance(to, Track): - to = next(T for _, T in self.tracks - for _, V in T.viewers - if V is to) - new_viewer.resurface(to.surface.subsurface((0, y, to.w, h))) - to.viewers.append((y, new_viewer)) - to.viewers.sort() # bisect.insort() would be overkill here. - new_viewer.draw() - self.close_viewer(viewer) - - def _track_at(self, x): - ''' - Return the track at x along with the track-relative x coordinate, - raise ValueError if x is off-screen. - ''' - for track_x, track in self.tracks: - if x < track_x + track.w: - return track, x - track_x - raise ValueError('x outside display: %r' % (x,)) - -
[docs] def at(self, x, y): - ''' - Return the viewer (which can be a Track) at the x, y location, - along with the relative-to-viewer-surface x and y coordinates. - If there is no viewer at the location the Track will be returned - instead. - ''' - track, x = self._track_at(x) - viewer, y = track.viewer_at(y) - return viewer, x, y
- -
[docs] def iter_viewers(self): - ''' - Iterate through all viewers yielding (viewer, x, y) three-tuples. - The x and y coordinates are screen pixels of the top-left corner - of the viewer. - ''' - for x, T in self.tracks: - for y, V in T.viewers: - yield V, x, y
- -
[docs] def done_resizing(self): - ''' - Helper method called directly by ``MenuViewer.mouse_up()`` to (hackily) - update the display when done resizing a viewer. - ''' - for _, track in self.tracks: # This should be done by a Message? - if track.resizing_viewer: - track.resizing_viewer.draw() - track.resizing_viewer = None - break
- -
[docs] def broadcast(self, message): - ''' - Broadcast a message to all viewers (except the sender) and all - registered handlers. - ''' - for _, track in self.tracks: - track.broadcast(message) - for handler in self.handlers: - handler(message)
- -
[docs] def redraw(self): - ''' - Redraw all tracks (which will redraw all viewers.) - ''' - for _, track in self.tracks: - track.redraw()
- -
[docs] def focus(self, viewer): - ''' - Set system focus to a given viewer (or no viewer if a track.) - ''' - if isinstance(viewer, Track): - if self.focused_viewer: self.focused_viewer.unfocus() - self.focused_viewer = None - elif viewer is not self.focused_viewer: - if self.focused_viewer: self.focused_viewer.unfocus() - self.focused_viewer = viewer - viewer.focus(self)
- -
[docs] def dispatch_event(self, event): - ''' - Display event handling. - ''' - try: - if event.type in {pygame.KEYUP, pygame.KEYDOWN}: - self._keyboard_event(event) - elif event.type in MOUSE_EVENTS: - self._mouse_event(event) - else: - print >> stderr, ( - 'received event %s Use pygame.event.set_allowed().' - % pygame.event.event_name(event.type) - ) - # Catch all exceptions and open a viewer. - except: - err = format_exc() - print >> stderr, err # To be safe just print it right away. - open_viewer_on_string(self, err, self.broadcast)
- - def _keyboard_event(self, event): - if event.key == pygame.K_PAUSE and event.type == pygame.KEYUP: - # At least on my keyboard the break/pause key sends K_PAUSE. - # The main use of this is to open a TextViewer if you - # accidentally close all the viewers, so you can recover. - raise KeyboardInterrupt('break') - if not self.focused_viewer: - return - if event.type == pygame.KEYUP: - self.focused_viewer.key_up(self, event.key, event.mod) - elif event.type == pygame.KEYDOWN: - self.focused_viewer.key_down( - self, event.unicode, event.key, event.mod) - - def _mouse_event(self, event): - V, x, y = self.at(*event.pos) - - if event.type == pygame.MOUSEMOTION: - if not isinstance(V, Track): - V.mouse_motion(self, x, y, *(event.rel + event.buttons)) - - elif event.type == pygame.MOUSEBUTTONDOWN: - if event.button == 1: - self.focus(V) - V.mouse_down(self, x, y, event.button) - - else: - assert event.type == pygame.MOUSEBUTTONUP - - # Check for moving viewer. - if (event.button == 2 - and self.focused_viewer - and V is not self.focused_viewer - and V.MINIMUM_HEIGHT < y < V.h - self.focused_viewer.MINIMUM_HEIGHT - ): - self._move_viewer(V, y, self.focused_viewer, *event.pos) - - else: - V.mouse_up(self, x, y, event.button) - -
[docs] def init_text(self, pt, x, y, filename): - ''' - Open and return a ``TextViewer`` on a given file (which must be present - in the ``JOYHOME`` directory.) - ''' - viewer = self.open_viewer(x, y, text_viewer.TextViewer) - viewer.content_id, viewer.lines = pt.open(filename) - viewer.draw() - return viewer
- - -
[docs]class Track(Viewer): - ''' - Manage a vertical strip of the display, and the viewers on it. - ''' - - def __init__(self, surface): - Viewer.__init__(self, surface) - self.viewers = [] # (y, viewer) - self.hiding = None - self.resizing_viewer = None - self.draw() - -
[docs] def split(self, y): - ''' - Split the Track at the y coordinate and return the height - available for a new viewer. Tracks manage a vertical strip of - the display screen so they don't resize their surface when split. - ''' - h = self.viewers[0][0] if self.viewers else self.h - assert h > y - return h - y
- -
[docs] def draw(self, rect=None): - '''Draw the track onto its surface, clearing all content. - - If rect is passed only draw to that area. This supports e.g. - closing a viewer that then exposes part of the track. - ''' - self.surface.fill(GREY, rect=rect)
- -
[docs] def viewer_at(self, y): - ''' - Return the viewer at y along with the viewer-relative y coordinate, - if there's no viewer at y return this track and y. - ''' - for viewer_y, viewer in self.viewers: - if viewer_y < y <= viewer_y + viewer.h: - return viewer, y - viewer_y - return self, y
- -
[docs] def open_viewer(self, y, class_): - '''Open and return a viewer of class at y.''' - # Todo: if y coincides with some other viewer's y replace it. - viewer, viewer_y = self.viewer_at(y) - h = viewer.split(viewer_y) - new_viewer = class_(self.surface.subsurface((0, y, self.w, h))) - new_viewer.draw() - self.viewers.append((y, new_viewer)) - self.viewers.sort() # Could use bisect module but how many - # viewers will you ever have? - return new_viewer
- -
[docs] def close_viewer(self, viewer): - '''Close the viewer, reuse the freed space.''' - for y, V in self.viewers: - if V is viewer: - self._close_viewer(y, V) - return True - return False
- - def _close_viewer(self, y, viewer): - '''Helper function to do the actual closing.''' - i = self.viewers.index((y, viewer)) - del self.viewers[i] - if i: # The previous viewer gets the space. - previous_y, previous_viewer = self.viewers[i - 1] - self._grow_by(previous_viewer, previous_y, viewer.h) - else: # This track gets the space. - self.draw((0, y, self.w, viewer.surface.get_height())) - viewer.close() - - def _grow_by(self, viewer, y, h): - '''Grow a viewer (located at y) by height h. - - This might seem like it should be a method of the viewer, but - the viewer knows nothing of its own y location on the screen nor - the parent track's surface (to make a new subsurface) so it has - to be a method of the track, which has both. - ''' - h = viewer.surface.get_height() + h - try: - surface = self.surface.subsurface((0, y, self.w, h)) - except ValueError: # subsurface rectangle outside surface area - pass - else: - viewer.resurface(surface) - if h <= viewer.last_touch[1]: viewer.last_touch = 0, 0 - viewer.draw() - -
[docs] def change_viewer(self, viewer, new_y, relative=False): - ''' - Adjust the top of the viewer to a new y within the boundaries of - its neighbors. - - If relative is False new_y should be in screen coords, else new_y - should be relative to the top of the viewer. - ''' - for old_y, V in self.viewers: - if V is viewer: - if relative: new_y += old_y - if new_y != old_y: self._change_viewer(new_y, old_y, V) - return True - return False
- - def _change_viewer(self, new_y, old_y, viewer): - new_y = max(0, min(self.h, new_y)) - i = self.viewers.index((old_y, viewer)) - if new_y < old_y: # Enlarge self, shrink upper neighbor. - if i: - previous_y, previous_viewer = self.viewers[i - 1] - if new_y - previous_y < self.MINIMUM_HEIGHT: - return - previous_viewer.resizing = 1 - h = previous_viewer.split(new_y - previous_y) - previous_viewer.resizing = 0 - self.resizing_viewer = previous_viewer - else: - h = old_y - new_y - self._grow_by(viewer, new_y, h) - - else: # Shink self, enlarge upper neighbor. - # Enforce invariant. - try: - h, _ = self.viewers[i + 1] - except IndexError: # No next viewer. - h = self.h - if h - new_y < self.MINIMUM_HEIGHT: - return - - # Change the viewer and adjust the upper viewer or track. - h = new_y - old_y - self._grow_by(viewer, new_y, -h) # grow by negative height! - if i: - previous_y, previous_viewer = self.viewers[i - 1] - previous_viewer.resizing = 1 - self._grow_by(previous_viewer, previous_y, h) - previous_viewer.resizing = 0 - self.resizing_viewer = previous_viewer - else: - self.draw((0, old_y, self.w, h)) - - self.viewers[i] = new_y, viewer - # self.viewers.sort() # Not necessary, invariant holds. - assert sorted(self.viewers) == self.viewers - -
[docs] def broadcast(self, message): - ''' - Broadcast a message to all viewers on this track (except the sender.) - ''' - for _, viewer in self.viewers: - if viewer is not message.sender: - viewer.handle(message)
- -
[docs] def redraw(self): - '''Redraw the track and all of its viewers.''' - self.draw() - for _, viewer in self.viewers: - viewer.draw()
-
- -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_modules/joy/vui/main.html b/docs/VUI-docs/build/html/_modules/joy/vui/main.html deleted file mode 100644 index e98eb67..0000000 --- a/docs/VUI-docs/build/html/_modules/joy/vui/main.html +++ /dev/null @@ -1,274 +0,0 @@ - - - - - - - - joy.vui.main — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for joy.vui.main

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2019 Simon Forman
-#
-#    This file is part of Thun
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-
-Main Module
-======================================
-
-Pulls everything together.
-
-'''
-import os, sys, traceback
-import pygame
-from joy.library import initialize, DefinitionWrapper, SimpleFunctionWrapper
-from joy.vui import core, display, persist_task
-
-
-FULLSCREEN = '-f' in sys.argv
-
-
-JOY_HOME = os.environ.get('JOY_HOME')
-if JOY_HOME is None:
-    JOY_HOME = os.path.expanduser('~/.thun')
-    if not os.path.isabs(JOY_HOME):
-        raise ValueError('what directory?')
-
-
-
[docs]def load_definitions(pt, dictionary): - '''Load definitions from ``definitions.txt``.''' - lines = pt.open('definitions.txt')[1] - for line in lines: - if '==' in line: - DefinitionWrapper.add_def(line, dictionary)
- - -
[docs]def load_primitives(home, name_space): - '''Load primitives from ``library.py``.''' - fn = os.path.join(home, 'library.py') - if os.path.exists(fn): - execfile(fn, name_space)
- - -
[docs]def init(): - ''' - Initialize the system. - - * Init PyGame - * Create main window - * Start the PyGame clock - * Set the event mask - * Create the PersistTask - - ''' - print 'Initializing Pygame...' - pygame.init() - print 'Creating window...' - if FULLSCREEN: - screen = pygame.display.set_mode() - else: - screen = pygame.display.set_mode((1024, 768)) - clock = pygame.time.Clock() - pygame.event.set_allowed(None) - pygame.event.set_allowed(core.ALLOWED_EVENTS) - pt = persist_task.PersistTask(JOY_HOME) - return screen, clock, pt
- - -
[docs]def init_context(screen, clock, pt): - ''' - More initialization - - * Create the Joy dictionary - * Create the Display - * Open the log, menu, and scratch text viewers, and the stack pickle - * Start the main loop - * Create the World object - * Register PersistTask and World message handlers with the Display - * Load user function definitions. - - ''' - D = initialize() - d = display.Display( - screen, - D.__contains__, - *((144 - 89, 144, 89) if FULLSCREEN else (89, 144)) - ) - log = d.init_text(pt, 0, 0, 'log.txt') - tho = d.init_text(pt, 0, d.h / 3, 'menu.txt') - t = d.init_text(pt, d.w / 2, 0, 'scratch.txt') - loop = core.TheLoop(d, clock) - stack_id, stack_holder = pt.open('stack.pickle') - world = core.World(stack_id, stack_holder, D, d.broadcast, log) - loop.install_task(pt.task_run, 10000) # save files every ten seconds - d.handlers.append(pt.handle) - d.handlers.append(world.handle) - load_definitions(pt, D) - return locals()
- - -
[docs]def error_guard(loop, n=10): - ''' - Run a loop function, retry for ``n`` exceptions. - Prints tracebacks on ``sys.stderr``. - ''' - error_count = 0 - while error_count < n: - try: - loop() - break - except: - traceback.print_exc(file=sys.stderr) - error_count += 1
- - -
[docs]class FileFaker(object): - '''Pretends to be a file object but writes to log instead.''' - - def __init__(self, log): - self.log = log - -
[docs] def write(self, text): - '''Write text to log.''' - self.log.append(text)
- - def flush(self): - pass
- - -
[docs]def main(screen, clock, pt): - ''' - Main function. - - * Call ``init_context()`` - * Load primitives - * Create an ``evaluate`` function that lets you just eval some Python code - * Redirect ``stdout`` to the log using a ``FileFaker`` object, and... - * Start the main loop. - ''' - name_space = init_context(screen, clock, pt) - load_primitives(pt.home, name_space.copy()) - - @SimpleFunctionWrapper - def evaluate(stack): - '''Evaluate the Python code text on the top of the stack.''' - code, stack = stack - exec code in name_space.copy() - return stack - - name_space['D']['evaluate'] = evaluate - - - sys.stdout, old_stdout = FileFaker(name_space['log']), sys.stdout - try: - error_guard(name_space['loop'].loop) - finally: - sys.stdout = old_stdout - - return name_space['d']
-
- -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_modules/joy/vui/persist_task.html b/docs/VUI-docs/build/html/_modules/joy/vui/persist_task.html deleted file mode 100644 index cf849e8..0000000 --- a/docs/VUI-docs/build/html/_modules/joy/vui/persist_task.html +++ /dev/null @@ -1,372 +0,0 @@ - - - - - - - - joy.vui.persist_task — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for joy.vui.persist_task

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2019 Simon Forman
-#
-#    This file is part of Thun
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-
-Persist Task
-===========================
-
-This module deals with persisting the "resources" (text files and the
-stack) to the git repo in the ``JOY_HOME`` directory.
-
-'''
-import os, pickle, traceback
-from collections import Counter
-from dulwich.errors import NotGitRepository
-from dulwich.repo import Repo
-from joy.vui import core, init_joy_home
-
-
-
[docs]def open_repo(repo_dir=None, initialize=False): - ''' - Open, or create, and return a Dulwich git repo object for the given - directory. If the dir path doesn't exist it will be created. If it - does exist but isn't a repo the result depends on the ``initialize`` - argument. If it is ``False`` (the default) a ``NotGitRepository`` - exception is raised, otherwise ``git init`` is effected in the dir. - ''' - if not os.path.exists(repo_dir): - os.makedirs(repo_dir, 0700) - return init_repo(repo_dir) - try: - return Repo(repo_dir) - except NotGitRepository: - if initialize: - return init_repo(repo_dir) - raise
- - -
[docs]def init_repo(repo_dir): - ''' - Initialize a git repository in the directory. Stage and commit all - files (toplevel, not those in subdirectories if any) in the dir. - ''' - repo = Repo.init(repo_dir) - init_joy_home.initialize(repo_dir) - repo.stage([ - fn - for fn in os.listdir(repo_dir) - if os.path.isfile(os.path.join(repo_dir, fn)) - ]) - repo.do_commit('Initial commit.', committer=core.COMMITTER) - return repo
- - -
[docs]def make_repo_relative_path_maker(repo): - ''' - Helper function to return a function that returns a path given a path, - that's relative to the repository. - ''' - c = repo.controldir() - def repo_relative_path(path): - return os.path.relpath(path, os.path.commonprefix((c, path))) - return repo_relative_path
- - -
[docs]class Resource(object): - ''' - Handle the content of a text files as a list of lines, deal with - saving it and staging the changes to a repo. - ''' - - def __init__(self, filename, repo_relative_filename, thing=None): - self.filename = filename - self.repo_relative_filename = repo_relative_filename - self.thing = thing or self._from_file(open(filename)) - - def _from_file(self, f): - return f.read().splitlines() - - def _to_file(self, f): - for line in self.thing: - print >> f, line - -
[docs] def persist(self, repo): - ''' - Save the lines to the file and stage the file in the repo. - ''' - with open(self.filename, 'w') as f: - os.chmod(self.filename, 0600) - self._to_file(f) - f.flush() - os.fsync(f.fileno()) - # For goodness's sake, write it to the disk already! - repo.stage([self.repo_relative_filename])
- - -
[docs]class PickledResource(Resource): - ''' - A ``Resource`` subclass that uses ``pickle`` on its file/thing. - ''' - - def _from_file(self, f): - return [pickle.load(f)] - - def _to_file(self, f): - pickle.dump(self.thing[0], f)
- - -
[docs]class PersistTask(object): - ''' - This class deals with saving changes to the git repo. - ''' - - LIMIT = 10 - MAX_SAVE = 10 - - def __init__(self, home): - self.home = home - self.repo = open_repo(home) - self._r = make_repo_relative_path_maker(self.repo) - self.counter = Counter() - self.store = {} - -
[docs] def open(self, name): - ''' - Look up the named file in home and return its content_id and data. - ''' - fn = os.path.join(self.home, name) - content_id = name # hash(fn) - try: - resource = self.store[content_id] - except KeyError: - R = PickledResource if name.endswith('.pickle') else Resource - resource = self.store[content_id] = R(fn, self._r(fn)) - return content_id, resource.thing
- -
[docs] def handle(self, message): - ''' - Handle messages, dispatch to ``handle_FOO()`` methods. - ''' - if isinstance(message, core.OpenMessage): - self.handle_open(message) - elif isinstance(message, core.ModifyMessage): - self.handle_modify(message) - elif isinstance(message, core.PersistMessage): - self.handle_persist(message) - elif isinstance(message, core.ShutdownMessage): - for content_id in self.counter: - self.store[content_id].persist(self.repo) - self.commit('shutdown')
- -
[docs] def handle_open(self, message): - ''' - Foo. - ''' - try: - message.content_id, message.thing = self.open(message.name) - except: - message.traceback = traceback.format_exc() - message.status = core.ERROR - else: - message.status = core.SUCCESS
- -
[docs] def handle_modify(self, message): - ''' - Foo. - ''' - try: - content_id = message.details['content_id'] - except KeyError: - return - if not content_id: - return - self.counter[content_id] += 1 - if self.counter[content_id] > self.LIMIT: - self.persist(content_id) - self.commit('due to activity')
- -
[docs] def handle_persist(self, message): - ''' - Foo. - ''' - try: - resource = self.store[message.content_id] - except KeyError: - resource = self.handle_persist_new(message) - resource.persist(self.repo) - self.commit('by request from %r' % (message.sender,))
- -
[docs] def handle_persist_new(self, message): - ''' - Foo. - ''' - name = message.content_id - check_filename(name) - fn = os.path.join(self.home, name) - thing = message.details['thing'] - R = PickledResource if name.endswith('.pickle') else Resource # !!! refactor! - resource = self.store[name] = R(fn, self._r(fn), thing) - return resource
- -
[docs] def persist(self, content_id): - ''' - Persist a resource. - ''' - del self.counter[content_id] - self.store[content_id].persist(self.repo)
- -
[docs] def task_run(self): - ''' - Stage any outstanding changes. - ''' - if not self.counter: - return - for content_id, _ in self.counter.most_common(self.MAX_SAVE): - self.persist(content_id) - self.commit()
- -
[docs] def commit(self, message='auto-commit'): - ''' - Commit. - ''' - return self.repo.do_commit(message, committer=core.COMMITTER)
- -
[docs] def scan(self): - ''' - Return a sorted list of all the files in the home dir. - ''' - return sorted([ - fn - for fn in os.listdir(self.home) - if os.path.isfile(os.path.join(self.home, fn)) - ])
- - -
[docs]def check_filename(name): - ''' - Sanity checks for filename. - ''' - # TODO: improve this... - if len(name) > 64: - raise ValueError('bad name %r' % (name,)) - left, dot, right = name.partition('.') - if not left.isalnum() or dot and not right.isalnum(): - raise ValueError('bad name %r' % (name,))
- - -if __name__ == '__main__': - JOY_HOME = os.path.expanduser('~/.thun') - pt = PersistTask(JOY_HOME) - content_id, thing = pt.open('stack.pickle') - pt.persist(content_id) - print pt.counter - mm = core.ModifyMessage(None, None, content_id=content_id) - pt.handle(mm) - print pt.counter -
- -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_modules/joy/vui/stack_viewer.html b/docs/VUI-docs/build/html/_modules/joy/vui/stack_viewer.html deleted file mode 100644 index a36039d..0000000 --- a/docs/VUI-docs/build/html/_modules/joy/vui/stack_viewer.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - joy.vui.stack_viewer — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for joy.vui.stack_viewer

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2019 Simon Forman
-#
-#    This file is part of Thun
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-
-Stack Viewer
-=================
-
-'''
-from joy.utils.stack import expression_to_string, iter_stack
-from joy.vui import core, text_viewer
-
-
-MAX_WIDTH = 64
-
-
-
[docs]def fsi(item): - '''Format Stack Item''' - if isinstance(item, tuple): - res = '[%s]' % expression_to_string(item) - elif isinstance(item, str): - res = '"%s"' % item - else: - assert not isinstance(item, unicode), repr(item) - res = str(item) - if len(res) > MAX_WIDTH: - return res[:MAX_WIDTH - 3] + '...' - return res
- - -
[docs]class StackViewer(text_viewer.TextViewer): - - def __init__(self, surface): - super(StackViewer, self).__init__(surface) - self.stack_holder = None - self.content_id = 'stack viewer' - - def _attach(self, display): - if self.stack_holder: - return - om = core.OpenMessage(self, 'stack.pickle') - display.broadcast(om) - if om.status != core.SUCCESS: - raise RuntimeError('stack unavailable') - self.stack_holder = om.thing - - def _update(self): - self.lines[:] = map(fsi, iter_stack(self.stack_holder[0])) or [''] - - def focus(self, display): - self._attach(display) - super(StackViewer, self).focus(display) - - def handle(self, message): - if (isinstance(message, core.ModifyMessage) - and message.subject is self.stack_holder - ): - self._update() - self.draw_body()
-
- -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_modules/joy/vui/text_viewer.html b/docs/VUI-docs/build/html/_modules/joy/vui/text_viewer.html deleted file mode 100644 index 132f2d8..0000000 --- a/docs/VUI-docs/build/html/_modules/joy/vui/text_viewer.html +++ /dev/null @@ -1,799 +0,0 @@ - - - - - - - - joy.vui.text_viewer — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for joy.vui.text_viewer

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2019 Simon Forman
-#
-#    This file is part of Thun
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-
-Text Viewer
-=================
-
-'''
-import string
-import pygame
-from joy.utils.stack import expression_to_string
-from joy.vui.core import (
-    ARROW_KEYS,
-    BACKGROUND as BG,
-    FOREGROUND as FG,
-    CommandMessage,
-    ModifyMessage,
-    OpenMessage,
-    SUCCESS,
-    push,
-    )
-from joy.vui import viewer, font_data
-#reload(viewer)
-
-
-MenuViewer = viewer.MenuViewer
-
-
-SELECTION_COLOR = 235, 255, 0, 32
-SELECTION_KEYS = {
-    pygame.K_F1,
-    pygame.K_F2,
-    pygame.K_F3,
-    pygame.K_F4,
-    }
-STACK_CHATTER_KEYS = {
-    pygame.K_F5,
-    pygame.K_F6,
-    pygame.K_F7,
-    pygame.K_F8,
-    }
-
-
-def _is_command(display, word):
-    return display.lookup(word) or word.isdigit() or all(
-        not s or s.isdigit() for s in word.split('.', 1)
-        ) and len(word) > 1
-
-
-def format_stack_item(content):
-    if isinstance(content, tuple):
-        return '[%s]' % expression_to_string(content)
-    return str(content)
-
-
-class Font(object):
-
-    IMAGE = pygame.image.load(font_data.data, 'Iosevka12.BMP')
-    LOOKUP = (string.ascii_letters +
-              string.digits +
-              '''@#$&_~|`'"%^=-+*/\\<>[]{}(),.;:!?''')
-
-    def __init__(self, char_w=8, char_h=19, line_h=19):
-        self.char_w = char_w
-        self.char_h = char_h
-        self.line_h = line_h
-
-    def size(self, text):
-        return self.char_w * len(text), self.line_h
-
-    def render(self, text):
-        surface = pygame.Surface(self.size(text))
-        surface.fill(BG)
-        x = 0
-        for ch in text:
-            if not ch.isspace():
-                try:
-                    i = self.LOOKUP.index(ch)
-                except ValueError:
-                    # render a lil box...
-                    r = (x + 1, self.line_h / 2 - 3,
-                         self.char_w - 2, self.line_h / 2)
-                    pygame.draw.rect(surface, FG, r, 1)
-                else:
-                    iy, ix = divmod(i, 26)
-                    ix *= self.char_w
-                    iy *= self.char_h
-                    area = ix, iy, self.char_w, self.char_h
-                    surface.blit(self.IMAGE, (x, 0), area)
-            x += self.char_w
-        return surface
-
-    def __contains__(self, char):
-        assert len(char) == 1, repr(char)
-        return char in self.LOOKUP
-
-
-FONT = Font()
-
-
-
[docs]class TextViewer(MenuViewer): - - MINIMUM_HEIGHT = FONT.line_h + 3 - CLOSE_TEXT = FONT.render('close') - GROW_TEXT = FONT.render('grow') - - class Cursor(object): - - def __init__(self, viewer): - self.v = viewer - self.x = self.y = 0 - self.w, self.h = 2, FONT.line_h - self.mem = pygame.Surface((self.w, self.h)) - self.can_fade = False - - def set_to(self, x, y): - self.fade() - self.x, self.y = x, y - self.draw() - - def draw(self): - r = self.x * FONT.char_w, self.screen_y(), self.w, self.h - self.mem.blit(self.v.body_surface, (0, 0), r) - self.v.body_surface.fill(FG, r) - self.can_fade = True - - def fade(self): - if self.can_fade: - dest = self.x * FONT.char_w, self.screen_y() - self.v.body_surface.blit(self.mem, dest) - self.can_fade = False - - def screen_y(self, row=None): - if row is None: row = self.y - return (row - self.v.at_line) * FONT.line_h - - def up(self, _mod): - if self.y: - self.fade() - self.y -= 1 - self.x = min(self.x, len(self.v.lines[self.y])) - self.draw() - - def down(self, _mod): - if self.y < len(self.v.lines) - 1: - self.fade() - self.y += 1 - self.x = min(self.x, len(self.v.lines[self.y])) - self.draw() - self._check_scroll() - - def left(self, _mod): - if self.x: - self.fade() - self.x -= 1 - self.draw() - elif self.y: - self.fade() - self.y -= 1 - self.x = len(self.v.lines[self.y]) - self.draw() - self._check_scroll() - - def right(self, _mod): - if self.x < len(self.v.lines[self.y]): - self.fade() - self.x += 1 - self.draw() - elif self.y < len(self.v.lines) - 1: - self.fade() - self.y += 1 - self.x = 0 - self.draw() - self._check_scroll() - - def _check_scroll(self): - if self.y < self.v.at_line: - self.v.scroll_down() - elif self.y > self.v.at_line + self.v.h_in_lines: - self.v.scroll_up() - - def __init__(self, surface): - self.cursor = self.Cursor(self) - MenuViewer.__init__(self, surface) - self.lines = [''] - self.content_id = None - self.at_line = 0 - self.bg = BG - self.command = self.command_rect = None - self._sel_start = self._sel_end = None - - def resurface(self, surface): - self.cursor.fade() - MenuViewer.resurface(self, surface) - - w, h = self.CLOSE_TEXT.get_size() - self.close_rect = pygame.rect.Rect(self.w - 2 - w, 1, w, h) - w, h = self.GROW_TEXT.get_size() - self.grow_rect = pygame.rect.Rect(1, 1, w, h) - - self.body_surface = surface.subsurface(self.body_rect) - self.line_w = self.body_rect.w / FONT.char_w + 1 - self.h_in_lines = self.body_rect.h / FONT.line_h - 1 - self.command_rect = self.command = None - self._sel_start = self._sel_end = None - - def handle(self, message): - if super(TextViewer, self).handle(message): - return - if (isinstance(message, ModifyMessage) - and message.subject is self.lines - ): - # TODO: check self.at_line - self.draw_body() - - # Drawing - - def draw_menu(self): - #MenuViewer.draw_menu(self) - self.surface.blit(self.GROW_TEXT, (1, 1)) - self.surface.blit(self.CLOSE_TEXT, - (self.w - 2 - self.close_rect.w, 1)) - if self.content_id: - self.surface.blit(FONT.render('| ' + self.content_id), - (self.grow_rect.w + FONT.char_w + 3, 1)) - self.surface.fill( # light grey background - (196, 196, 196), - (0, 0, self.w - 1, self.MINIMUM_HEIGHT), - pygame.BLEND_MULT - ) - - def draw_body(self): - MenuViewer.draw_body(self) - ys = xrange(0, self.body_rect.height, FONT.line_h) - ls = self.lines[self.at_line:self.at_line + self.h_in_lines + 2] - for y, line in zip(ys, ls): - self.draw_line(y, line) - - def draw_line(self, y, line): - surface = FONT.render(line[:self.line_w]) - self.body_surface.blit(surface, (0, y)) - - def _redraw_line(self, row): - try: line = self.lines[row] - except IndexError: line = ' ' * self.line_w - else: - n = self.line_w - len(line) - if n > 0: line = line + ' ' * n - self.draw_line(self.cursor.screen_y(row), line) - - # General Functionality - - def focus(self, display): - self.cursor.v = self - self.cursor.draw() - - def unfocus(self): - self.cursor.fade() - - def scroll_up(self): - if self.at_line < len(self.lines) - 1: - self._fade_command() - self._deselect() - self._sel_start = self._sel_end = None - self.at_line += 1 - self.body_surface.scroll(0, -FONT.line_h) - row = self.h_in_lines + self.at_line - self._redraw_line(row) - self._redraw_line(row + 1) - self.cursor.draw() - - def scroll_down(self): - if self.at_line: - self._fade_command() - self._deselect() - self._sel_start = self._sel_end = None - self.at_line -= 1 - self.body_surface.scroll(0, FONT.line_h) - self._redraw_line(self.at_line) - self.cursor.draw() - - def command_down(self, display, x, y): - if self.command_rect and self.command_rect.collidepoint(x, y): - return - self._fade_command() - line, column, _row = self.at(x, y) - word_start = line.rfind(' ', 0, column) + 1 - word_end = line.find(' ', column) - if word_end == -1: word_end = len(line) - word = line[word_start:word_end] - if not _is_command(display, word): - return - r = self.command_rect = pygame.Rect( - word_start * FONT.char_w, # x - y / FONT.line_h * FONT.line_h, # y - len(word) * FONT.char_w, # w - FONT.line_h # h - ) - pygame.draw.line(self.body_surface, FG, r.bottomleft, r.bottomright) - self.command = word - - def command_up(self, display): - if self.command: - command = self.command - self._fade_command() - display.broadcast(CommandMessage(self, command)) - - def _fade_command(self): - self.command = None - r, self.command_rect = self.command_rect, None - if r: - pygame.draw.line(self.body_surface, BG, r.bottomleft, r.bottomright) - -
[docs] def at(self, x, y): - ''' - Given screen coordinates return the line, row, and column of the - character there. - ''' - row = self.at_line + y / FONT.line_h - try: - line = self.lines[row] - except IndexError: - row = len(self.lines) - 1 - line = self.lines[row] - column = len(line) - else: - column = min(x / FONT.char_w, len(line)) - return line, column, row
- - # Event Processing - - def body_click(self, display, x, y, button): - if button == 1: - _line, column, row = self.at(x, y) - self.cursor.set_to(column, row) - elif button == 2: - if pygame.KMOD_SHIFT & pygame.key.get_mods(): - self.scroll_up() - else: - self.scroll_down() - elif button == 3: - self.command_down(display, x, y) - elif button == 4: self.scroll_down() - elif button == 5: self.scroll_up() - - def menu_click(self, display, x, y, button): - if MenuViewer.menu_click(self, display, x, y, button): - return True - - def mouse_up(self, display, x, y, button): - if MenuViewer.mouse_up(self, display, x, y, button): - return True - elif button == 3 and self.body_rect.collidepoint(x, y): - self.command_up(display) - - def mouse_motion(self, display, x, y, rel_x, rel_y, button0, button1, button2): - if MenuViewer.mouse_motion(self, display, x, y, rel_x, rel_y, - button0, button1, button2): - return True - if (button0 - and display.focused_viewer is self - and self.body_rect.collidepoint(x, y) - ): - bx, by = self.body_rect.topleft - _line, column, row = self.at(x - bx, y - by) - self.cursor.set_to(column, row) - elif button2 and self.body_rect.collidepoint(x, y): - bx, by = self.body_rect.topleft - self.command_down(display, x - bx, y - by) - -
[docs] def close(self): - self._sel_start = self._sel_end = None
- - def key_down(self, display, uch, key, mod): - - if key in SELECTION_KEYS: - self._selection_key(display, key, mod) - return - if key in STACK_CHATTER_KEYS: - self._stack_chatter_key(display, key, mod) - return - if key in ARROW_KEYS: - self._arrow_key(key, mod) - return - - line, i = self.lines[self.cursor.y], self.cursor.x - modified = () - if key == pygame.K_RETURN: - self._return_key(mod, line, i) - modified = True - elif key == pygame.K_BACKSPACE: - modified = self._backspace_key(mod, line, i) - elif key == pygame.K_DELETE: - modified = self._delete_key(mod, line, i) - elif key == pygame.K_INSERT: - modified = self._insert_key(display, mod, line, i) - elif uch and uch in FONT or uch == ' ': - self._printable_key(uch, mod, line, i) - modified = True - else: - print '%r %i %s' % (uch, key, bin(mod)) - - if modified: - # The selection is fragile. - self._deselect() - self._sel_start = self._sel_end = None - message = ModifyMessage( - self, self.lines, content_id=self.content_id) - display.broadcast(message) - - def _stack_chatter_key(self, display, key, mod): - if key == pygame.K_F5: - if mod & pygame.KMOD_SHIFT: - command = 'roll<' - else: - command = 'swap' - elif key == pygame.K_F6: - if mod & pygame.KMOD_SHIFT: - command = 'roll>' - else: - command = 'dup' - elif key == pygame.K_F7: - if mod & pygame.KMOD_SHIFT: - command = 'tuck' - else: - command = 'over' -## elif key == pygame.K_F8: -## if mod & pygame.KMOD_SHIFT: -## command = '' -## else: -## command = '' - else: - return - display.broadcast(CommandMessage(self, command)) - - # Selection Handling - - def _selection_key(self, display, key, mod): - self.cursor.fade() - self._deselect() - if key == pygame.K_F1: # set sel start - self._sel_start = self.cursor.y, self.cursor.x - self._update_selection() - elif key == pygame.K_F2: # set sel end - self._sel_end = self.cursor.y, self.cursor.x - self._update_selection() - elif key == pygame.K_F3: # copy - if mod & pygame.KMOD_SHIFT: - self._parse_selection(display) - else: - self._copy_selection(display) - self._update_selection() - elif key == pygame.K_F4: # cut or delete - if mod & pygame.KMOD_SHIFT: - self._delete_selection(display) - else: - self._cut_selection(display) - self.cursor.draw() - - def _deselect(self): - if self._has_selection(): - srow, erow = self._sel_start[0], self._sel_end[0] - # Just erase the whole selection. - for r in range(min(srow, erow), max(srow, erow) + 1): - self._redraw_line(r) - - def _copy_selection(self, display): - if push(self, self._get_selection(), display.broadcast) == SUCCESS: - return True -## om = OpenMessage(self, 'stack.pickle') -## display.broadcast(om) -## if om.status == SUCCESS: -## selection = self._get_selection() -## om.thing[0] = selection, om.thing[0] -## display.broadcast(ModifyMessage( -## self, om.thing, content_id=om.content_id)) - - def _parse_selection(self, display): - if self._has_selection(): - if self._copy_selection(display): - display.broadcast(CommandMessage(self, 'parse')) - - def _cut_selection(self, display): - if self._has_selection(): - if self._copy_selection(display): - self._delete_selection(display) - - def _delete_selection(self, display): - if not self._has_selection(): - return - self.cursor.fade() - srow, scolumn, erow, ecolumn = self._selection_coords() - if srow == erow: - line = self.lines[srow] - self.lines[srow] = line[:scolumn] + line[ecolumn:] - else: - left = self.lines[srow][:scolumn] - right = self.lines[erow][ecolumn:] - self.lines[srow:erow + 1] = [left + right] - self.draw_body() - self.cursor.set_to(srow, scolumn) - display.broadcast(ModifyMessage( - self, self.lines, content_id=self.content_id)) - - def _has_selection(self): - return (self._sel_start - and self._sel_end - and self._sel_start != self._sel_end) - - def _get_selection(self): - '''Return the current selection if any as a single string.''' - if not self._has_selection(): - return '' - srow, scolumn, erow, ecolumn = self._selection_coords() - if srow == erow: - return str(self.lines[srow][scolumn:ecolumn]) - lines = [] - assert srow < erow - while srow <= erow: - line = self.lines[srow] - e = ecolumn if srow == erow else len(line) - lines.append(line[scolumn:e]) - scolumn = 0 - srow += 1 - return str('\n'.join(lines)) - - def _selection_coords(self): - (srow, scolumn), (erow, ecolumn) = ( - min(self._sel_start, self._sel_end), - max(self._sel_start, self._sel_end) - ) - return srow, scolumn, erow, ecolumn - - def _update_selection(self): - if self._sel_start is None and self._sel_end: - self._sel_start = self._sel_end - elif self._sel_end is None and self._sel_start: - self._sel_end = self._sel_start - assert self._sel_start and self._sel_end - if self._sel_start != self._sel_end: - for rect in self._iter_selection_rectangles(): - self.body_surface.fill( - SELECTION_COLOR, - rect, - pygame.BLEND_RGBA_MULT - ) - - def _iter_selection_rectangles(self, ): - srow, scolumn, erow, ecolumn = self._selection_coords() - if srow == erow: - yield ( - scolumn * FONT.char_w, - self.cursor.screen_y(srow), - (ecolumn - scolumn) * FONT.char_w, - FONT.line_h - ) - return - lines = self.lines[srow:erow + 1] - assert len(lines) >= 2 - first_line = lines[0] - yield ( - scolumn * FONT.char_w, - self.cursor.screen_y(srow), - (len(first_line) - scolumn) * FONT.char_w, - FONT.line_h - ) - yield ( - 0, - self.cursor.screen_y(erow), - ecolumn * FONT.char_w, - FONT.line_h - ) - if len(lines) > 2: - for line in lines[1:-1]: - srow += 1 - yield ( - 0, - self.cursor.screen_y(srow), - len(line) * FONT.char_w, - FONT.line_h - ) - - # Key Handlers - - def _printable_key(self, uch, _mod, line, i): - line = line[:i] + uch + line[i:] - self.lines[self.cursor.y] = line - self.cursor.fade() - self.cursor.x += 1 - self.draw_line(self.cursor.screen_y(), line) - self.cursor.draw() - - def _backspace_key(self, _mod, line, i): - res = False - if i: - line = line[:i - 1] + line[i:] - self.lines[self.cursor.y] = line - self.cursor.fade() - self.cursor.x -= 1 - self.draw_line(self.cursor.screen_y(), line + ' ') - self.cursor.draw() - res = True - elif self.cursor.y: - y = self.cursor.y - left, right = self.lines[y - 1:y + 1] - self.lines[y - 1:y + 1] = [left + right] - self.cursor.x = len(left) - self.cursor.y -= 1 - self.draw_body() - self.cursor.draw() - res = True - return res - - def _delete_key(self, _mod, line, i): - res = False - if i < len(line): - line = line[:i] + line[i + 1:] - self.lines[self.cursor.y] = line - self.cursor.fade() - self.draw_line(self.cursor.screen_y(), line + ' ') - self.cursor.draw() - res = True - elif self.cursor.y < len(self.lines) - 1: - y = self.cursor.y - left, right = self.lines[y:y + 2] - self.lines[y:y + 2] = [left + right] - self.draw_body() - self.cursor.draw() - res = True - return res - - def _arrow_key(self, key, mod): - if key == pygame.K_UP: self.cursor.up(mod) - elif key == pygame.K_DOWN: self.cursor.down(mod) - elif key == pygame.K_LEFT: self.cursor.left(mod) - elif key == pygame.K_RIGHT: self.cursor.right(mod) - - def _return_key(self, _mod, line, i): - self.cursor.fade() - # Ignore the mods for now. - n = self.cursor.y - self.lines[n:n + 1] = [line[:i], line[i:]] - self.cursor.y += 1 - self.cursor.x = 0 - if self.cursor.y > self.at_line + self.h_in_lines: - self.scroll_up() - else: - self.draw_body() - self.cursor.draw() - - def _insert_key(self, display, mod, _line, _i): - om = OpenMessage(self, 'stack.pickle') - display.broadcast(om) - if om.status != SUCCESS: - return - stack = om.thing[0] - if stack: - content = format_stack_item(stack[0]) - if self.insert(content): - if mod & pygame.KMOD_SHIFT: - display.broadcast(CommandMessage(self, 'pop')) - return True - - def insert(self, content): - assert isinstance(content, basestring), repr(content) - if content: - self.cursor.fade() - row, column = self.cursor.y, self.cursor.x - line = self.lines[row] - lines = (line[:column] + content + line[column:]).splitlines() - self.lines[row:row + 1] = lines - self.draw_body() - self.cursor.y = row + len(lines) - 1 - self.cursor.x = len(lines[-1]) - len(line) + column - self.cursor.draw() - return True - - def append(self, content): - self.cursor.fade() - self.cursor.y = len(self.lines) - 1 - self.cursor.x = len(self.lines[self.cursor.y]) - self.insert(content)
-
- -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_modules/joy/vui/viewer.html b/docs/VUI-docs/build/html/_modules/joy/vui/viewer.html deleted file mode 100644 index f874d64..0000000 --- a/docs/VUI-docs/build/html/_modules/joy/vui/viewer.html +++ /dev/null @@ -1,345 +0,0 @@ - - - - - - - - joy.vui.viewer — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for joy.vui.viewer

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2019 Simon Forman
-#
-#    This file is part of joy.py
-#
-#    joy.py is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    joy.py is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with joy.py.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-
-Viewer
-=================
-
-'''
-import pygame
-from joy.vui.core import BACKGROUND, FOREGROUND
-
-
-
[docs]class Viewer(object): - ''' - Base Viewer class - ''' - - MINIMUM_HEIGHT = 11 - - def __init__(self, surface): - self.resurface(surface) - self.last_touch = 0, 0 - - def resurface(self, surface): - self.w, self.h = surface.get_width(), surface.get_height() - self.surface = surface - -
[docs] def split(self, y): - ''' - Split the viewer at the y coordinate (which is relative to the - viewer's surface and must be inside it somewhere) and return the - remaining height. The upper part of the viewer remains (and gets - redrawn on a new surface) and the lower space is now available - for e.g. a new viewer. - ''' - assert y >= self.MINIMUM_HEIGHT - new_viewer_h = self.h - y - self.resurface(self.surface.subsurface((0, 0, self.w, y))) - if y <= self.last_touch[1]: self.last_touch = 0, 0 - self.draw() - return new_viewer_h
- - def handle(self, message): - assert self is not message.sender - pass - -
[docs] def draw(self): - '''Draw the viewer onto its surface.''' - self.surface.fill(BACKGROUND) - x, y, h = self.w - 1, self.MINIMUM_HEIGHT, self.h - 1 - # Right-hand side. - pygame.draw.line(self.surface, FOREGROUND, (x, 0), (x, h)) - # Between header and body. - pygame.draw.line(self.surface, FOREGROUND, (0, y), (x, y)) - # Bottom. - pygame.draw.line(self.surface, FOREGROUND, (0, h), (x, h))
- -
[docs] def close(self): - '''Close the viewer and release any resources, etc...'''
- - def focus(self, display): - pass - - def unfocus(self): - pass - - # Event handling. - - def mouse_down(self, display, x, y, button): - self.last_touch = x, y - - def mouse_up(self, display, x, y, button): - pass - - def mouse_motion(self, display, x, y, dx, dy, button0, button1, button2): - pass - - def key_up(self, display, key, mod): - if key == pygame.K_q and mod & pygame.KMOD_CTRL: # Ctrl-q - display.close_viewer(self) - return True - if key == pygame.K_g and mod & pygame.KMOD_CTRL: # Ctrl-g - display.grow_viewer(self) - return True - - def key_down(self, display, uch, key, mod): - pass
- - - - - -
[docs]class SomeViewer(MenuViewer): - - def __init__(self, surface): - MenuViewer.__init__(self, surface) - - def resurface(self, surface): - MenuViewer.resurface(self, surface) - - def draw_menu(self): - MenuViewer.draw_menu(self) - - def draw_body(self): - pass - - def body_click(self, display, x, y, button): - pass - - def menu_click(self, display, x, y, button): - if MenuViewer.menu_click(self, display, x, y, button): - return True - - def mouse_up(self, display, x, y, button): - if MenuViewer.mouse_up(self, display, x, y, button): - return True - - def mouse_motion(self, display, x, y, rel_x, rel_y, button0, button1, button2): - if MenuViewer.mouse_motion(self, display, x, y, rel_x, rel_y, - button0, button1, button2): - return True - - def key_down(self, display, uch, key, mod): - try: - print chr(key), - except ValueError: - pass
- - -# Note that Oberon book says that if you split at the exact top of a viewer -# it should close, and I think this implies the new viewer gets the old -# viewer's whole height. I haven't implemented that yet, so the edge-case -# in the code is broken by "intent" for now.. - - -def draw_a(surface, color=FOREGROUND, blend=False): - w, h = surface.get_width() - 2, surface.get_height() - 2 - pygame.draw.aalines(surface, color, False, ( - (1, h), (w / 2, 1), (w, h), (1, h / 2) - ), blend) -
- -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_sources/core.rst.txt b/docs/VUI-docs/build/html/_sources/core.rst.txt deleted file mode 100644 index 06bc602..0000000 --- a/docs/VUI-docs/build/html/_sources/core.rst.txt +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.core - :members: diff --git a/docs/VUI-docs/build/html/_sources/display.rst.txt b/docs/VUI-docs/build/html/_sources/display.rst.txt deleted file mode 100644 index 6083403..0000000 --- a/docs/VUI-docs/build/html/_sources/display.rst.txt +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.display - :members: diff --git a/docs/VUI-docs/build/html/_sources/index.rst.txt b/docs/VUI-docs/build/html/_sources/index.rst.txt deleted file mode 100644 index 528549c..0000000 --- a/docs/VUI-docs/build/html/_sources/index.rst.txt +++ /dev/null @@ -1,175 +0,0 @@ -.. Joy VUI documentation master file, created by - sphinx-quickstart on Mon May 06 19:41:42 2019. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to Joy VUI's documentation! -=================================== - -A simple Graphical User Interface for the Joy programming language, -written using Pygame to bypass X11 et. al., modeled on the Oberon OS, and -intended to be just functional enough to support bootstrapping further Joy -development. - -Screenshot ------------------------------ -.. image:: _static/Joy-VUI-screenshot.PNG - - -Quick Start ------------------------------ - -If you have PyGame and Dulwich installed you should be able to start the -VUI with the following command: - -:: - - python -m joy.vui - -This will create a ``~/.thun`` directory in your home dir to store your -data. - -How it works now. ------------------------------ - -The VUI is more-or-less a crude text editor along with -a simple Joy runtime (interpreter, stack, and dictionary.) It auto-saves -any named files (in a versioned home directory) and you can write new Joy -primitives in Python and Joy definitions and immediately install and use -them, as well as recording them for reuse (after restarts.) - -The only dependencies are Pygame and Dulwich (a Python Git library.) - -When the main.py script starts it checks for an environment var "JOY_HOME" -which should point to a directory where you want the system to store the -files ("resources") it will edit and save, this directory defaults to -``~/.thun``. The first time you run it, it will create some default files -as content. Right click on see_resources to open a viewer with the list -of resources (files), copy a name to the stack and right click on -open_resource_at_good_location to open a viewer on that resource. - -Right now the screen size defaults to windowed 1024x768, but if you pass -the ``-f`` option to the main.py script the UI will take up the full screen -at the highest available resolution. The window is divided into two (or -three in fullscreen) vertical "tracks", and the number and width of the -tracks are fixed at start up. (Feel free to edit the values in main.py to -play around with different track configurations.) Each track gets divided -horizontally into zero or more "viewers" (like windows in a windowed GUI, -cf. Chapter 4 of "Project Oberon") for a kind of tiled layout. - -Currently, there are only two kinds of (interesting) viewers: TextViewers -and StackViewer. The TextViewers are crude text editors. They provide -just enough functionality to let the user write text and code (Python and -Joy) and execute Joy functions. One important thing they do is -automatically save their content after changes. No more lost work. - -The StackViewer is a specialized TextViewer that shows the contents of the -Joy stack one line per stack item. It's a very handy visual aid to keep -track of what's going on. There's also a log.txt file that gets written -to when commands are executed, and so records the log of user actions and -system events. It tends to fill up quickly so there's a reset_log command -that clears it out. - -Viewers have "grow" and "close" in their menu bars. These are buttons. -When you right-click on grow a viewer a copy is created that covers that -viewer's entire track. If you grow a viewer that already takes up its -whole track then a copy is created that takes up an additional track, up -to the whole screen. Closing a viewer just deletes that viewer, and when -a track has no more viewers, it is deleted and that exposes any previous -tracks and viewers that were hidden. - -(Note: if you ever close all the viewers and are sitting at a blank screen -with nowhere to type and execute commands, press the Pause/Break key. -This will open a new "trap" viewer which you can then use to recover.) - -Copies of a viewer all share the same model and update their display as it -changes. (If you have two viewers open on the same named resource and edit -one you'll see the other update as you type.) - -UI Guide ------------------------------ - -left mouse sets cursor in text, in menu bar resizes viewer interactively -(this is a little buggy in that you can move the mouse quickly and get -outside the menu, leaving the viewer in the "resizing" state. Until I fix -this, the workaround is to just grab the menu bar again and wiggle it a -few pixels and let go. This will reset the machinery.) - -Right mouse executes Joy command (functions), and you can drag with the -right button to highlight (well, underline) commands. Words that aren't -names of Joy commands won't be underlined. Release the button to execute -the command. - -The middle mouse button (usually a wheel these days) scrolls the text but -you can also click and drag any viewer with it to move that viewer to -another track or to a different location in the same track. There's no -direct visual feedback for this (yet) but that dosen't seem to impair its -usefulness. - -F1, F2 - set selection begin and end markers (crude but usable.) - -F3 - copy selected text to the top of the stack. - -Shift-F3 - as copy then run "parse" command on the string. - -F4 - cut selected text to the top of the stack. - -Shift-F4 - as cut then run "pop" (delete selection.) - -Joy ----------------------------- - -Pretty much all of the rest of the functionality of the system is provided -by executing Joy commands (aka functions, aka "words" in Forth) by right- -clicking on their names in any text. - -To get help on a Joy function select the name of the function in a -TextViewer using F1 and F2, then press shift-F3 to parse the selection. -The function (really its Symbol) will appear on the stack in brackets (a -"quoted program" such as "[pop]".) Then right-click on the word help in -any TextViewer (if it's not already there, just type it in somewhere.) -This will print the docstring or definition of the word (function) to -stdout. At some point I'll write a thing to send that to the log.txt file -instead, but for now look for output in the terminal. - - -Modules ------------------------------ - -.. image:: _static/packages_Vui.png - - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - core - main - display - viewer - text_viewer - stack_viewer - persist_task - - -Start Up Sequence ------------------------------- - -PersistTask is the first (non-PyGame-specific) object created. - -The ``screen``, ``clock``, and ``pt`` are created in ``init()`` and passed -into ``main()``, which calls ``init_context()`` and then starts -the main loop. - -During ``init_context()`` a few text viewers are opened on files -in the home dir with the help of the ``pt``. Then the main loop -is started and the ``pt`` task is installed and ``pt`` and ``world`` -handlers are registered. - - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/VUI-docs/build/html/_sources/main.rst.txt b/docs/VUI-docs/build/html/_sources/main.rst.txt deleted file mode 100644 index f5b6b08..0000000 --- a/docs/VUI-docs/build/html/_sources/main.rst.txt +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.main - :members: diff --git a/docs/VUI-docs/build/html/_sources/persist_task.rst.txt b/docs/VUI-docs/build/html/_sources/persist_task.rst.txt deleted file mode 100644 index ef05e2c..0000000 --- a/docs/VUI-docs/build/html/_sources/persist_task.rst.txt +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.persist_task - :members: diff --git a/docs/VUI-docs/build/html/_sources/stack_viewer.rst.txt b/docs/VUI-docs/build/html/_sources/stack_viewer.rst.txt deleted file mode 100644 index 60f3458..0000000 --- a/docs/VUI-docs/build/html/_sources/stack_viewer.rst.txt +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.stack_viewer - :members: diff --git a/docs/VUI-docs/build/html/_sources/text_viewer.rst.txt b/docs/VUI-docs/build/html/_sources/text_viewer.rst.txt deleted file mode 100644 index 7918dbc..0000000 --- a/docs/VUI-docs/build/html/_sources/text_viewer.rst.txt +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.text_viewer - :members: diff --git a/docs/VUI-docs/build/html/_sources/viewer.rst.txt b/docs/VUI-docs/build/html/_sources/viewer.rst.txt deleted file mode 100644 index 6864c84..0000000 --- a/docs/VUI-docs/build/html/_sources/viewer.rst.txt +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.viewer - :members: diff --git a/docs/VUI-docs/build/html/_static/Joy-VUI-screenshot.PNG b/docs/VUI-docs/build/html/_static/Joy-VUI-screenshot.PNG deleted file mode 100644 index 53f7bf1..0000000 Binary files a/docs/VUI-docs/build/html/_static/Joy-VUI-screenshot.PNG and /dev/null differ diff --git a/docs/VUI-docs/build/html/_static/ajax-loader.gif b/docs/VUI-docs/build/html/_static/ajax-loader.gif deleted file mode 100644 index 61faf8c..0000000 Binary files a/docs/VUI-docs/build/html/_static/ajax-loader.gif and /dev/null differ diff --git a/docs/VUI-docs/build/html/_static/alabaster.css b/docs/VUI-docs/build/html/_static/alabaster.css deleted file mode 100644 index a88ce29..0000000 --- a/docs/VUI-docs/build/html/_static/alabaster.css +++ /dev/null @@ -1,693 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro', serif; - font-size: 17px; - background-color: #fff; - color: #000; - margin: 0; - padding: 0; -} - - -div.document { - width: 940px; - margin: 30px auto 0 auto; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 220px; -} - -div.sphinxsidebar { - width: 220px; - font-size: 14px; - line-height: 1.5; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #fff; - color: #3E4349; - padding: 0 30px 0 30px; -} - -div.body > .section { - text-align: left; -} - -div.footer { - width: 940px; - margin: 20px auto 30px auto; - font-size: 14px; - color: #888; - text-align: right; -} - -div.footer a { - color: #888; -} - -p.caption { - font-family: inherit; - font-size: inherit; -} - - -div.relations { - display: none; -} - - -div.sphinxsidebar a { - color: #444; - text-decoration: none; - border-bottom: 1px dotted #999; -} - -div.sphinxsidebar a:hover { - border-bottom: 1px solid #999; -} - -div.sphinxsidebarwrapper { - padding: 18px 10px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 0; - margin: -10px 0 0 0px; - text-align: center; -} - -div.sphinxsidebarwrapper h1.logo { - margin-top: -10px; - text-align: center; - margin-bottom: 5px; - text-align: left; -} - -div.sphinxsidebarwrapper h1.logo-name { - margin-top: 0px; -} - -div.sphinxsidebarwrapper p.blurb { - margin-top: 0; - font-style: normal; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: 'Garamond', 'Georgia', serif; - color: #444; - font-size: 24px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 20px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p.logo a, -div.sphinxsidebar h3 a, -div.sphinxsidebar p.logo a:hover, -div.sphinxsidebar h3 a:hover { - border: none; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar ul li.toctree-l1 > a { - font-size: 120%; -} - -div.sphinxsidebar ul li.toctree-l2 > a { - font-size: 110%; -} - -div.sphinxsidebar input { - border: 1px solid #CCC; - font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro', serif; - font-size: 1em; -} - -div.sphinxsidebar hr { - border: none; - height: 1px; - color: #AAA; - background: #AAA; - - text-align: left; - margin-left: 0; - width: 50%; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #DDD; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #EAEAEA; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - margin: 20px 0px; - padding: 10px 30px; - background-color: #EEE; - border: 1px solid #CCC; -} - -div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { - background-color: ; - border-bottom: 1px solid #fafafa; -} - -dd div.admonition { - margin-left: -60px; - padding-left: 60px; -} - -div.admonition p.admonition-title { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight { - background-color: #fff; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.warning { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.danger { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.error { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.caution { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.attention { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.important { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.note { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.tip { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.hint { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.seealso { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.topic { - background-color: #EEE; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt, code { - font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.9em; -} - -.hll { - background-color: #FFC; - margin: 0 -12px; - padding: 0 12px; - display: block; -} - -img.screenshot { -} - -tt.descname, tt.descclassname, code.descname, code.descclassname { - font-size: 0.95em; -} - -tt.descname, code.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #EEE; - background: #FDFDFD; - font-size: 0.9em; -} - -table.footnote + table.footnote { - margin-top: -15px; - border-top: none; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.field-list p { - margin-bottom: 0.8em; -} - -table.footnote td.label { - width: .1px; - padding: 0.3em 0 0.3em 0.5em; -} - -table.footnote td { - padding: 0.3em 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -blockquote { - margin: 0 0 0 30px; - padding: 0; -} - -ul, ol { - /* Matches the 30px from the narrow-screen "li > ul" selector below */ - margin: 10px 0 10px 30px; - padding: 0; -} - -pre { - background: #EEE; - padding: 7px 30px; - margin: 15px 0px; - line-height: 1.3em; -} - -div.viewcode-block:target { - background: #ffd; -} - -dl pre, blockquote pre, li pre { - margin-left: 0; - padding-left: 30px; -} - -dl dl pre { - margin-left: -90px; - padding-left: 90px; -} - -tt, code { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, code.xref, a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fff; -} - -a.reference { - text-decoration: none; - border-bottom: 1px dotted #004B6B; -} - -/* Don't put an underline on images */ -a.image-reference, a.image-reference:hover { - border-bottom: none; -} - -a.reference:hover { - border-bottom: 1px solid #6D4100; -} - -a.footnote-reference { - text-decoration: none; - font-size: 0.7em; - vertical-align: top; - border-bottom: 1px dotted #004B6B; -} - -a.footnote-reference:hover { - border-bottom: 1px solid #6D4100; -} - -a:hover tt, a:hover code { - background: #EEE; -} - - -@media screen and (max-width: 870px) { - - div.sphinxsidebar { - display: none; - } - - div.document { - width: 100%; - - } - - div.documentwrapper { - margin-left: 0; - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - } - - div.bodywrapper { - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - margin-left: 0; - } - - ul { - margin-left: 0; - } - - li > ul { - /* Matches the 30px from the "ul, ol" selector above */ - margin-left: 30px; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .bodywrapper { - margin: 0; - } - - .footer { - width: auto; - } - - .github { - display: none; - } - - - -} - - - -@media screen and (max-width: 875px) { - - body { - margin: 0; - padding: 20px 30px; - } - - div.documentwrapper { - float: none; - background: #fff; - } - - div.sphinxsidebar { - display: block; - float: none; - width: 102.5%; - margin: 50px -30px -20px -30px; - padding: 10px 20px; - background: #333; - color: #FFF; - } - - div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, - div.sphinxsidebar h3 a { - color: #fff; - } - - div.sphinxsidebar a { - color: #AAA; - } - - div.sphinxsidebar p.logo { - display: none; - } - - div.document { - width: 100%; - margin: 0; - } - - div.footer { - display: none; - } - - div.bodywrapper { - margin: 0; - } - - div.body { - min-height: 0; - padding: 0; - } - - .rtd_doc_footer { - display: none; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .footer { - width: auto; - } - - .github { - display: none; - } -} - - -/* misc. */ - -.revsys-inline { - display: none!important; -} - -/* Make nested-list/multi-paragraph items look better in Releases changelog - * pages. Without this, docutils' magical list fuckery causes inconsistent - * formatting between different release sub-lists. - */ -div#changelog > div.section > ul > li > p:only-child { - margin-bottom: 0; -} - -/* Hide fugly table cell borders in ..bibliography:: directive output */ -table.docutils.citation, table.docutils.citation td, table.docutils.citation th { - border: none; - /* Below needed in some edge cases; if not applied, bottom shadows appear */ - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_static/basic.css b/docs/VUI-docs/build/html/_static/basic.css deleted file mode 100644 index 0807176..0000000 --- a/docs/VUI-docs/build/html/_static/basic.css +++ /dev/null @@ -1,676 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 450px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px 7px 0 7px; - background-color: #ffe; - width: 40%; - float: right; -} - -p.sidebar-title { - font-weight: bold; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px 7px 0 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -div.admonition dl { - margin-bottom: 0; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist td { - vertical-align: top; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -dl { - margin-bottom: 15px; -} - -dd p { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; -} - -td.linenos pre { - padding: 5px 0px; - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - margin-left: 0.5em; -} - -table.highlighttable td { - padding: 0 0.5em 0 0.5em; -} - -div.code-block-caption { - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -div.code-block-caption + div > div.highlight > pre { - margin-top: 0; -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - padding: 1em 1em 0; -} - -div.literal-block-wrapper div.highlight { - margin: 0; -} - -code.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -code.descclassname { - background-color: transparent; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: relative; - left: 0px; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_static/comment-bright.png b/docs/VUI-docs/build/html/_static/comment-bright.png deleted file mode 100644 index 15e27ed..0000000 Binary files a/docs/VUI-docs/build/html/_static/comment-bright.png and /dev/null differ diff --git a/docs/VUI-docs/build/html/_static/comment-close.png b/docs/VUI-docs/build/html/_static/comment-close.png deleted file mode 100644 index 4d91bcf..0000000 Binary files a/docs/VUI-docs/build/html/_static/comment-close.png and /dev/null differ diff --git a/docs/VUI-docs/build/html/_static/comment.png b/docs/VUI-docs/build/html/_static/comment.png deleted file mode 100644 index dfbc0cb..0000000 Binary files a/docs/VUI-docs/build/html/_static/comment.png and /dev/null differ diff --git a/docs/VUI-docs/build/html/_static/custom.css b/docs/VUI-docs/build/html/_static/custom.css deleted file mode 100644 index 2a924f1..0000000 --- a/docs/VUI-docs/build/html/_static/custom.css +++ /dev/null @@ -1 +0,0 @@ -/* This file intentionally left blank. */ diff --git a/docs/VUI-docs/build/html/_static/doctools.js b/docs/VUI-docs/build/html/_static/doctools.js deleted file mode 100644 index 344db17..0000000 --- a/docs/VUI-docs/build/html/_static/doctools.js +++ /dev/null @@ -1,315 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for all documentation. - * - * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - -/** - * make the code below compatible with browsers without - * an installed firebug like debugger -if (!window.console || !console.firebug) { - var names = ["log", "debug", "info", "warn", "error", "assert", "dir", - "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", - "profile", "profileEnd"]; - window.console = {}; - for (var i = 0; i < names.length; ++i) - window.console[names[i]] = function() {}; -} - */ - -/** - * small helper function to urldecode strings - */ -jQuery.urldecode = function(x) { - return decodeURIComponent(x).replace(/\+/g, ' '); -}; - -/** - * small helper function to urlencode strings - */ -jQuery.urlencode = encodeURIComponent; - -/** - * This function returns the parsed url parameters of the - * current request. Multiple values per key are supported, - * it will always return arrays of strings for the value parts. - */ -jQuery.getQueryParameters = function(s) { - if (typeof s === 'undefined') - s = document.location.search; - var parts = s.substr(s.indexOf('?') + 1).split('&'); - var result = {}; - for (var i = 0; i < parts.length; i++) { - var tmp = parts[i].split('=', 2); - var key = jQuery.urldecode(tmp[0]); - var value = jQuery.urldecode(tmp[1]); - if (key in result) - result[key].push(value); - else - result[key] = [value]; - } - return result; -}; - -/** - * highlight a given string on a jquery object by wrapping it in - * span elements with the given class name. - */ -jQuery.fn.highlightText = function(text, className) { - function highlight(node, addItems) { - if (node.nodeType === 3) { - var val = node.nodeValue; - var pos = val.toLowerCase().indexOf(text); - if (pos >= 0 && - !jQuery(node.parentNode).hasClass(className) && - !jQuery(node.parentNode).hasClass("nohighlight")) { - var span; - var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.className = className; - } - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - if (isInSVG) { - var bbox = span.getBBox(); - var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute('class', className); - var parentOfText = node.parentNode.parentNode; - addItems.push({ - "parent": node.parentNode, - "target": rect}); - } - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this, addItems); - }); - } - } - var addItems = []; - var result = this.each(function() { - highlight(this, addItems); - }); - for (var i = 0; i < addItems.length; ++i) { - jQuery(addItems[i].parent).before(addItems[i].target); - } - return result; -}; - -/* - * backward compatibility for jQuery.browser - * This will be supported until firefox bug is fixed. - */ -if (!jQuery.browser) { - jQuery.uaMatch = function(ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - jQuery.browser = {}; - jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; -} - -/** - * Small JavaScript module for the documentation. - */ -var Documentation = { - - init : function() { - this.fixFirefoxAnchorBug(); - this.highlightSearchWords(); - this.initIndexTable(); - if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { - this.initOnKeyListeners(); - } - }, - - /** - * i18n support - */ - TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, - LOCALE : 'unknown', - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext : function(string) { - var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated === 'undefined') - return string; - return (typeof translated === 'string') ? translated : translated[0]; - }, - - ngettext : function(singular, plural, n) { - var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated === 'undefined') - return (n == 1) ? singular : plural; - return translated[Documentation.PLURALEXPR(n)]; - }, - - addTranslations : function(catalog) { - for (var key in catalog.messages) - this.TRANSLATIONS[key] = catalog.messages[key]; - this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); - this.LOCALE = catalog.locale; - }, - - /** - * add context elements like header anchor links - */ - addContextElements : function() { - $('div[id] > :header:first').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this definition')). - appendTo(this); - }); - }, - - /** - * workaround a firefox stupidity - * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 - */ - fixFirefoxAnchorBug : function() { - if (document.location.hash && $.browser.mozilla) - window.setTimeout(function() { - document.location.href += ''; - }, 10); - }, - - /** - * highlight the search words provided in the url in the text - */ - highlightSearchWords : function() { - var params = $.getQueryParameters(); - var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; - if (terms.length) { - var body = $('div.body'); - if (!body.length) { - body = $('body'); - } - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) === 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, - - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this === '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); - }, - - initOnKeyListeners: function() { - $(document).keyup(function(event) { - var activeElementType = document.activeElement.tagName; - // don't navigate when in search box or textarea - if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { - switch (event.keyCode) { - case 37: // left - var prevHref = $('link[rel="prev"]').prop('href'); - if (prevHref) { - window.location.href = prevHref; - return false; - } - case 39: // right - var nextHref = $('link[rel="next"]').prop('href'); - if (nextHref) { - window.location.href = nextHref; - return false; - } - } - } - }); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); diff --git a/docs/VUI-docs/build/html/_static/documentation_options.js b/docs/VUI-docs/build/html/_static/documentation_options.js deleted file mode 100644 index bee34fe..0000000 --- a/docs/VUI-docs/build/html/_static/documentation_options.js +++ /dev/null @@ -1,10 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '0.1', - LANGUAGE: 'None', - COLLAPSE_INDEX: false, - FILE_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false, -}; \ No newline at end of file diff --git a/docs/VUI-docs/build/html/_static/down-pressed.png b/docs/VUI-docs/build/html/_static/down-pressed.png deleted file mode 100644 index 5756c8c..0000000 Binary files a/docs/VUI-docs/build/html/_static/down-pressed.png and /dev/null differ diff --git a/docs/VUI-docs/build/html/_static/down.png b/docs/VUI-docs/build/html/_static/down.png deleted file mode 100644 index 1b3bdad..0000000 Binary files a/docs/VUI-docs/build/html/_static/down.png and /dev/null differ diff --git a/docs/VUI-docs/build/html/_static/file.png b/docs/VUI-docs/build/html/_static/file.png deleted file mode 100644 index a858a41..0000000 Binary files a/docs/VUI-docs/build/html/_static/file.png and /dev/null differ diff --git a/docs/VUI-docs/build/html/_static/jquery-3.2.1.js b/docs/VUI-docs/build/html/_static/jquery-3.2.1.js deleted file mode 100644 index d2d8ca4..0000000 --- a/docs/VUI-docs/build/html/_static/jquery-3.2.1.js +++ /dev/null @@ -1,10253 +0,0 @@ -/*! - * jQuery JavaScript Library v3.2.1 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2017-03-20T18:59Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var document = window.document; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var concat = arr.concat; - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - - - - function DOMEval( code, doc ) { - doc = doc || document; - - var script = doc.createElement( "script" ); - - script.text = code; - doc.head.appendChild( script ).parentNode.removeChild( script ); - } -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.2.1", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android <=4.0 only - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - - if ( copyIsArray ) { - copyIsArray = false; - clone = src && Array.isArray( src ) ? src : []; - - } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isFunction: function( obj ) { - return jQuery.type( obj ) === "function"; - }, - - isWindow: function( obj ) { - return obj != null && obj === obj.window; - }, - - isNumeric: function( obj ) { - - // As of jQuery 3.0, isNumeric is limited to - // strings and numbers (primitives or objects) - // that can be coerced to finite numbers (gh-2662) - var type = jQuery.type( obj ); - return ( type === "number" || type === "string" ) && - - // parseFloat NaNs numeric-cast false positives ("") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - !isNaN( obj - parseFloat( obj ) ); - }, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - - /* eslint-disable no-unused-vars */ - // See https://github.com/eslint/eslint/issues/6125 - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; - }, - - // Evaluates a script in a global context - globalEval: function( code ) { - DOMEval( code ); - }, - - // Convert dashed to camelCase; used by the css and data modules - // Support: IE <=9 - 11, Edge 12 - 13 - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // Support: Android <=4.0 only - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: Date.now, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = jQuery.type( obj ); - - if ( type === "function" || jQuery.isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.3 - * https://sizzlejs.com/ - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2016-08-08 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - disabledAncestor = addCombinator( - function( elem ) { - return elem.disabled === true && ("form" in elem || "label" in elem); - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { - - // ID selector - if ( (m = match[1]) ) { - - // Document context - if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; - - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 - // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { - - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", (nid = expando) ); - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[i] = "#" + nid + " " + toSelector( groups[i] ); - } - newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement("fieldset"); - - try { - return !!fn( el ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - disabledAncestor( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9-11, Edge - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( preferredDoc !== document && - (subWindow = document.defaultView) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert(function( el ) { - el.className = "i"; - return !el.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( el ) { - el.appendChild( document.createComment("") ); - return !el.getElementsByTagName("*").length; - }); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); - - // ID filter and find - if ( support.getById ) { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( (elem = elems[i++]) ) { - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( el ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll("[msallowcapture^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); - } - }); - - assert(function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll("[name=d]").length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll(":enabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll(":disabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( el ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { - return -1; - } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - if ( support.matchesSelector && documentIsHTML && - !compilerCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch (e) {} - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null; -}; - -Sizzle.escape = function( sel ) { - return (sel + "").replace( rcssescape, fcssescape ); -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[6] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - // Use previously-cached element index if available - if ( useCache ) { - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - // Don't keep the element (issue #299) - input[0] = null; - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( (tokens = []) ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { - elem = elem[ dir ] || elem; - } else if ( (oldCache = uniqueCache[ key ]) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); - } else { - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), - len = elems.length; - - if ( outermost ) { - outermostContext = context === document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - if ( !context && elem.ownerDocument !== document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( el ) { - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( el ) { - return el.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - null; - } - }); -} - -return Sizzle; - -})( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; - - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -}; -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -var risSimple = /^.[^:#\[\.,]*$/; - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Simple selector that can be filtered directly, removing non-Elements - if ( risSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - // Complex selector, compare the two sets, removing non-Elements - qualifier = jQuery.filter( qualifier, elements ); - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; - } ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( nodeName( elem, "iframe" ) ) { - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( jQuery.isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.stackTrace ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the stack, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the master Deferred - master = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || - jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return master.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); - } - - return master.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -jQuery.Deferred.exceptionHook = function( error, stack ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ jQuery.camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ jQuery.camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( jQuery.camelCase ); - } else { - key = jQuery.camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - jQuery.contains( elem.ownerDocument, elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - -var swap = function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, - scale = 1, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - do { - - // If previous iteration zeroed out, double until we get *something*. - // Use string for doubling so we don't accidentally see scale as unchanged below - scale = scale || ".5"; - - // Adjust and apply - initialInUnit = initialInUnit / scale; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Update scale, tolerating zero or NaN from tween.cur() - // Break the loop if scale is unchanged or perfect, or if we've just had enough. - } while ( - scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations - ); - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); - -var rscriptType = ( /^$|\/(?:java|ecma)script/i ); - - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // Support: IE <=9 only - option: [ 1, "" ], - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
" ], - col: [ 2, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - _default: [ 0, "", "" ] -}; - -// Support: IE <=9 only -wrapMap.optgroup = wrapMap.option; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, contains, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (#12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); -var documentElement = document.documentElement; - - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 only -// See #13393 for more info -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = {}; - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - // Make a writable jQuery.Event from the native event object - var event = jQuery.event.fix( nativeEvent ); - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or 2) have namespace(s) - // a subset or equal to those in the bound event (both can have no namespace). - if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: jQuery.isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - focus: { - - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - this.focus(); - return false; - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - click: { - - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { - this.click(); - return false; - } - }, - - // For cross-browser consistency, don't fire native .click() on links - _default: function( event ) { - return nodeName( event.target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } -}, jQuery.event.addProp ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - /* eslint-disable max-len */ - - // See https://github.com/eslint/eslint/issues/3229 - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, - - /* eslint-enable */ - - // Support: IE <=10 - 11, Edge 12 - 13 - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( ">tbody", elem )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - - if ( match ) { - elem.type = match[ 1 ]; - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.access( src ); - pdataCur = dataPriv.set( dest, pdataOld ); - events = pdataOld.events; - - if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = concat.apply( [], args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( isFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = jQuery.contains( elem.ownerDocument, elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rmargin = ( /^margin/ ); - -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - div.style.cssText = - "box-sizing:border-box;" + - "position:relative;display:block;" + - "margin:auto;border:1px;padding:1px;" + - "top:1%;width:50%"; - div.innerHTML = ""; - documentElement.appendChild( container ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = divStyle.marginLeft === "2px"; - boxSizingReliableVal = divStyle.width === "4px"; - - // Support: Android 4.0 - 4.3 only - // Some styles come back with percentage values, even though they shouldn't - div.style.marginRight = "50%"; - pixelMarginRightVal = divStyle.marginRight === "4px"; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + - "padding:0;margin-top:1px;position:absolute"; - container.appendChild( div ); - - jQuery.extend( support, { - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelMarginRight: function() { - computeStyleTests(); - return pixelMarginRightVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) - if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }, - - cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style; - -// Return a css property mapped to a potentially vendor prefixed property -function vendorPropName( name ) { - - // Shortcut for names that are not vendor prefixed - if ( name in emptyStyle ) { - return name; - } - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a property mapped along what jQuery.cssProps suggests or to -// a vendor prefixed property. -function finalPropName( name ) { - var ret = jQuery.cssProps[ name ]; - if ( !ret ) { - ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; - } - return ret; -} - -function setPositiveNumber( elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { - var i, - val = 0; - - // If we already have the right measurement, avoid augmentation - if ( extra === ( isBorderBox ? "border" : "content" ) ) { - i = 4; - - // Otherwise initialize for horizontal or vertical properties - } else { - i = name === "width" ? 1 : 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); - } - - if ( isBorderBox ) { - - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // At this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } else { - - // At this point, extra isn't content, so add padding - val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // At this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with computed style - var valueIsBorderBox, - styles = getStyles( elem ), - val = curCSS( elem, name, styles ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test( val ) ) { - return val; - } - - // Check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && - ( support.boxSizingReliable() || val === elem.style[ name ] ); - - // Fall back to offsetWidth/Height when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - if ( val === "auto" ) { - val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; - } - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - - // Use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - "float": "cssFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (#7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug #9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (#7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - if ( type === "number" ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = jQuery.camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - } ) : - getWidthOrHeight( elem, name, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = extra && getStyles( elem ), - subtract = extra && augmentWidthOrHeight( - elem, - name, - extra, - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - styles - ); - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ name ] = value; - value = jQuery.css( elem, name ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && - ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || - jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = jQuery.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 13 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( jQuery.isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - jQuery.proxy( result.stop, result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = jQuery.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( jQuery.isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; - - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( jQuery.isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; - - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value; - - if ( typeof stateVal === "boolean" && type === "string" ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( jQuery.isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - return this.each( function() { - var className, i, self, classNames; - - if ( type === "string" ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = value.match( rnothtmlwhite ) || []; - - while ( ( className = classNames[ i++ ] ) ) { - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, isFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup contextmenu" ).split( " " ), - function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; -} ); - -jQuery.fn.extend( { - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -} ); - - - - -support.focusin = "onfocusin" in window; - - -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = jQuery.now(); - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } - - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; -}; - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = jQuery.isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( jQuery.isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match == null ? null : match; - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (#10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket #12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 13 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available, append data to url - if ( s.data ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - - -jQuery._evalUrl = function( url ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (#11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - "throws": true - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( jQuery.isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // #1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // #14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( " - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Core

-

The core module defines a bunch of system-wide “constants” (some colors -and PyGame event groups), the message classes for Oberon-style message -passing, a “world” class that holds the main context for the system, and -a mainloop class that manages the, uh, main loop (the PyGame event queue.)

-
-
-joy.vui.core.ARROW_KEYS = frozenset([273, 274, 275, 276])
-

PyGame arrow key events.

-
- -
-
-joy.vui.core.AVAILABLE_TASK_EVENTS = set([24, 25, 26, 27, 28, 29, 30, 31])
-

Task IDs that have not been assigned to a task.

-
- -
-
-class joy.vui.core.CommandMessage(sender, command)[source]
-

For commands, adds command field.

-
- -
-
-joy.vui.core.MOUSE_EVENTS = frozenset([4, 5, 6])
-

PyGame mouse events.

-
- -
-
-class joy.vui.core.Message(sender)[source]
-

Message base class. Contains sender field.

-
- -
-
-class joy.vui.core.ModifyMessage(sender, subject, **details)[source]
-

For when resources are modified, adds subject and details -fields.

-
- -
-
-class joy.vui.core.OpenMessage(sender, name)[source]
-

For when resources are modified, adds name, content_id``, -status, and traceback fields.

-
- -
-
-class joy.vui.core.PersistMessage(sender, content_id, **details)[source]
-

For when resources are modified, adds content_id and details -fields.

-
- -
-
-class joy.vui.core.ShutdownMessage(sender)[source]
-

Signals that the system is shutting down.

-
- -
-
-joy.vui.core.TASK_EVENTS = (24, 25, 26, 27, 28, 29, 30, 31)
-

Keep track of all possible task events.

-
- -
-
-class joy.vui.core.TheLoop(display, clock)[source]
-

The main loop manages tasks and the PyGame event queue -and framerate clock.

-
-
-install_task(F, milliseconds)[source]
-

Install a task to run every so many milliseconds.

-
- -
-
-loop()[source]
-

The actual main loop machinery.

-

Maintain a running flag, pump the PyGame event queue and -handle the events (dispatching to the display), tick the clock.

-

When the loop is exited (by clicking the window close button or -pressing the escape key) it broadcasts a ShutdownMessage.

-
- -
-
-remove_task(task_event_id)[source]
-

Remove an installed task.

-
- -
-
-run_task(task_event_id)[source]
-

Give a task its time to shine.

-
- -
- -
-
-class joy.vui.core.World(stack_id, stack_holder, dictionary, notify, log)[source]
-

This object contains the system context, the stack, dictionary, a -reference to the display broadcast method, and the log.

-
-
-handle(message)[source]
-

Deal with updates to the stack and commands.

-
- -
- -
-
-joy.vui.core.open_viewer_on_string(sender, content, notify)[source]
-

Helper function to open a text viewer on a string. -Typically used to show tracebacks.

-
- -
-
-joy.vui.core.push(sender, item, notify, stack_name='stack.pickle')[source]
-

Helper function to push an item onto the system stack with message.

-
- -
- - -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/display.html b/docs/VUI-docs/build/html/display.html deleted file mode 100644 index 226efd4..0000000 --- a/docs/VUI-docs/build/html/display.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - - - Display — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Display

-

This module implements a simple visual display system modeled on Oberon.

-

Refer to Chapter 4 of the Project Oberon book for more information.

-

There is a Display object that manages a pygame surface and N vertical -tracks each of which manages zero or more viewers.

-
-
-class joy.vui.display.Display(screen, lookup, *track_ratios)[source]
-

Manage tracks and viewers on a screen (Pygame surface.)

-

The size and number of tracks are defined by passing in at least two -ratios, e.g. Display(screen, 1, 4, 4) would create three tracks, one -small one on the left and two larger ones of the same size, each four -times wider than the left one.

-

All tracks take up the whole height of the display screen. Tracks -manage zero or more Viewers. When you “grow” a viewer a new track is -created that overlays or hides one or two existing tracks, and when -the last viewer in an overlay track is closed the track closes too -and reveals the hidden tracks (and their viewers, if any.)

-

In order to facilitate command underlining while mouse dragging the -lookup parameter must be a function that accepts a string and returns -a Boolean indicating whether that string is a valid Joy function name. -Typically you pass in the __contains__ method of the Joy dict. This -is a case of breaking “loose coupling” to gain efficiency, as otherwise -we would have to e.g. send some sort of lookup message to the -World context object, going through the whole Display.broadcast() -machinery, etc. Not something you want to do on each MOUSEMOTION -event.

-
-
-at(x, y)[source]
-

Return the viewer (which can be a Track) at the x, y location, -along with the relative-to-viewer-surface x and y coordinates. -If there is no viewer at the location the Track will be returned -instead.

-
- -
-
-broadcast(message)[source]
-

Broadcast a message to all viewers (except the sender) and all -registered handlers.

-
- -
-
-change_viewer(viewer, y, relative=False)[source]
-

Adjust the top of the viewer to a new y within the boundaries of -its neighbors.

-

If relative is False new_y should be in screen coords, else new_y -should be relative to the top of the viewer.

-
- -
-
-close_viewer(viewer)[source]
-

Close the viewer.

-
- -
-
-dispatch_event(event)[source]
-

Display event handling.

-
- -
-
-done_resizing()[source]
-

Helper method called directly by MenuViewer.mouse_up() to (hackily) -update the display when done resizing a viewer.

-
- -
-
-focus(viewer)[source]
-

Set system focus to a given viewer (or no viewer if a track.)

-
- -
-
-grow_viewer(viewer)[source]
-

Cause the viewer to take up its whole track or, if it does -already, take up another track, up to the whole screen.

-

This is the inverse of closing a viewer. “Growing” a viewer -actually creates a new copy and a new track to hold it. The old -tracks and viewers are retained, and they get restored when the -covering track closes, which happens automatically when the last -viewer in the covering track is closed.

-
- -
-
-init_text(pt, x, y, filename)[source]
-

Open and return a TextViewer on a given file (which must be present -in the JOYHOME directory.)

-
- -
-
-iter_viewers()[source]
-

Iterate through all viewers yielding (viewer, x, y) three-tuples. -The x and y coordinates are screen pixels of the top-left corner -of the viewer.

-
- -
-
-open_viewer(x, y, class_)[source]
-

Open a viewer of class_ at the x, y location on the display, -return the viewer.

-
- -
-
-redraw()[source]
-

Redraw all tracks (which will redraw all viewers.)

-
- -
- -
-
-class joy.vui.display.Track(surface)[source]
-

Manage a vertical strip of the display, and the viewers on it.

-
-
-broadcast(message)[source]
-

Broadcast a message to all viewers on this track (except the sender.)

-
- -
-
-change_viewer(viewer, new_y, relative=False)[source]
-

Adjust the top of the viewer to a new y within the boundaries of -its neighbors.

-

If relative is False new_y should be in screen coords, else new_y -should be relative to the top of the viewer.

-
- -
-
-close_viewer(viewer)[source]
-

Close the viewer, reuse the freed space.

-
- -
-
-draw(rect=None)[source]
-

Draw the track onto its surface, clearing all content.

-

If rect is passed only draw to that area. This supports e.g. -closing a viewer that then exposes part of the track.

-
- -
-
-open_viewer(y, class_)[source]
-

Open and return a viewer of class at y.

-
- -
-
-redraw()[source]
-

Redraw the track and all of its viewers.

-
- -
-
-split(y)[source]
-

Split the Track at the y coordinate and return the height -available for a new viewer. Tracks manage a vertical strip of -the display screen so they don’t resize their surface when split.

-
- -
-
-viewer_at(y)[source]
-

Return the viewer at y along with the viewer-relative y coordinate, -if there’s no viewer at y return this track and y.

-
- -
- -
- - -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/genindex.html b/docs/VUI-docs/build/html/genindex.html deleted file mode 100644 index 4268408..0000000 --- a/docs/VUI-docs/build/html/genindex.html +++ /dev/null @@ -1,463 +0,0 @@ - - - - - - - - - Index — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- - -

Index

- -
- A - | B - | C - | D - | E - | F - | G - | H - | I - | J - | L - | M - | O - | P - | R - | S - | T - | V - | W - -
-

A

- - - -
- -

B

- - -
- -

C

- - - -
- -

D

- - - -
- -

E

- - -
- -

F

- - - -
- -

G

- - -
- -

H

- - - -
- -

I

- - - -
- -

J

- - - -
- -

L

- - - -
- -

M

- - - -
- -

O

- - - -
- -

P

- - - -
- -

R

- - - -
- -

S

- - - -
- -

T

- - - -
- -

V

- - - -
- -

W

- - - -
- - - -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/index.html b/docs/VUI-docs/build/html/index.html deleted file mode 100644 index 6017857..0000000 --- a/docs/VUI-docs/build/html/index.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - - - Welcome to Joy VUI’s documentation! — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Welcome to Joy VUI’s documentation!

-

A simple Graphical User Interface for the Joy programming language, -written using Pygame to bypass X11 et. al., modeled on the Oberon OS, and -intended to be just functional enough to support bootstrapping further Joy -development.

-
-

Screenshot

-_images/Joy-VUI-screenshot.PNG -
-
-

Quick Start

-

If you have PyGame and Dulwich installed you should be able to start the -VUI with the following command:

-
python -m joy.vui
-
-
-

This will create a ~/.thun directory in your home dir to store your -data.

-
-
-

How it works now.

-

The VUI is more-or-less a crude text editor along with -a simple Joy runtime (interpreter, stack, and dictionary.) It auto-saves -any named files (in a versioned home directory) and you can write new Joy -primitives in Python and Joy definitions and immediately install and use -them, as well as recording them for reuse (after restarts.)

-

The only dependencies are Pygame and Dulwich (a Python Git library.)

-

When the main.py script starts it checks for an environment var “JOY_HOME” -which should point to a directory where you want the system to store the -files (“resources”) it will edit and save, this directory defaults to -~/.thun. The first time you run it, it will create some default files -as content. Right click on see_resources to open a viewer with the list -of resources (files), copy a name to the stack and right click on -open_resource_at_good_location to open a viewer on that resource.

-

Right now the screen size defaults to windowed 1024x768, but if you pass -the -f option to the main.py script the UI will take up the full screen -at the highest available resolution. The window is divided into two (or -three in fullscreen) vertical “tracks”, and the number and width of the -tracks are fixed at start up. (Feel free to edit the values in main.py to -play around with different track configurations.) Each track gets divided -horizontally into zero or more “viewers” (like windows in a windowed GUI, -cf. Chapter 4 of “Project Oberon”) for a kind of tiled layout.

-

Currently, there are only two kinds of (interesting) viewers: TextViewers -and StackViewer. The TextViewers are crude text editors. They provide -just enough functionality to let the user write text and code (Python and -Joy) and execute Joy functions. One important thing they do is -automatically save their content after changes. No more lost work.

-

The StackViewer is a specialized TextViewer that shows the contents of the -Joy stack one line per stack item. It’s a very handy visual aid to keep -track of what’s going on. There’s also a log.txt file that gets written -to when commands are executed, and so records the log of user actions and -system events. It tends to fill up quickly so there’s a reset_log command -that clears it out.

-

Viewers have “grow” and “close” in their menu bars. These are buttons. -When you right-click on grow a viewer a copy is created that covers that -viewer’s entire track. If you grow a viewer that already takes up its -whole track then a copy is created that takes up an additional track, up -to the whole screen. Closing a viewer just deletes that viewer, and when -a track has no more viewers, it is deleted and that exposes any previous -tracks and viewers that were hidden.

-

(Note: if you ever close all the viewers and are sitting at a blank screen -with nowhere to type and execute commands, press the Pause/Break key. -This will open a new “trap” viewer which you can then use to recover.)

-

Copies of a viewer all share the same model and update their display as it -changes. (If you have two viewers open on the same named resource and edit -one you’ll see the other update as you type.)

-
-
-

UI Guide

-

left mouse sets cursor in text, in menu bar resizes viewer interactively -(this is a little buggy in that you can move the mouse quickly and get -outside the menu, leaving the viewer in the “resizing” state. Until I fix -this, the workaround is to just grab the menu bar again and wiggle it a -few pixels and let go. This will reset the machinery.)

-

Right mouse executes Joy command (functions), and you can drag with the -right button to highlight (well, underline) commands. Words that aren’t -names of Joy commands won’t be underlined. Release the button to execute -the command.

-

The middle mouse button (usually a wheel these days) scrolls the text but -you can also click and drag any viewer with it to move that viewer to -another track or to a different location in the same track. There’s no -direct visual feedback for this (yet) but that dosen’t seem to impair its -usefulness.

-

F1, F2 - set selection begin and end markers (crude but usable.)

-

F3 - copy selected text to the top of the stack.

-

Shift-F3 - as copy then run “parse” command on the string.

-

F4 - cut selected text to the top of the stack.

-

Shift-F4 - as cut then run “pop” (delete selection.)

-
-
-

Joy

-

Pretty much all of the rest of the functionality of the system is provided -by executing Joy commands (aka functions, aka “words” in Forth) by right- -clicking on their names in any text.

-

To get help on a Joy function select the name of the function in a -TextViewer using F1 and F2, then press shift-F3 to parse the selection. -The function (really its Symbol) will appear on the stack in brackets (a -“quoted program” such as “[pop]”.) Then right-click on the word help in -any TextViewer (if it’s not already there, just type it in somewhere.) -This will print the docstring or definition of the word (function) to -stdout. At some point I’ll write a thing to send that to the log.txt file -instead, but for now look for output in the terminal.

-
-
-

Modules

-_images/packages_Vui.png - -
-
-

Start Up Sequence

-

PersistTask is the first (non-PyGame-specific) object created.

-

The screen, clock, and pt are created in init() and passed -into main(), which calls init_context() and then starts -the main loop.

-

During init_context() a few text viewers are opened on files -in the home dir with the help of the pt. Then the main loop -is started and the pt task is installed and pt and world -handlers are registered.

-
-
-

Indices and tables

- -
-
- - -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/main.html b/docs/VUI-docs/build/html/main.html deleted file mode 100644 index 851ee81..0000000 --- a/docs/VUI-docs/build/html/main.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - Main Module — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Main Module

-

Pulls everything together.

-
-
-class joy.vui.main.FileFaker(log)[source]
-

Pretends to be a file object but writes to log instead.

-
-
-write(text)[source]
-

Write text to log.

-
- -
- -
-
-joy.vui.main.error_guard(loop, n=10)[source]
-

Run a loop function, retry for n exceptions. -Prints tracebacks on sys.stderr.

-
- -
-
-joy.vui.main.init()[source]
-

Initialize the system.

-
    -
  • Init PyGame
  • -
  • Create main window
  • -
  • Start the PyGame clock
  • -
  • Set the event mask
  • -
  • Create the PersistTask
  • -
-
- -
-
-joy.vui.main.init_context(screen, clock, pt)[source]
-

More initialization

-
    -
  • Create the Joy dictionary
  • -
  • Create the Display
  • -
  • Open the log, menu, and scratch text viewers, and the stack pickle
  • -
  • Start the main loop
  • -
  • Create the World object
  • -
  • Register PersistTask and World message handlers with the Display
  • -
  • Load user function definitions.
  • -
-
- -
-
-joy.vui.main.load_definitions(pt, dictionary)[source]
-

Load definitions from definitions.txt.

-
- -
-
-joy.vui.main.load_primitives(home, name_space)[source]
-

Load primitives from library.py.

-
- -
-
-joy.vui.main.main(screen, clock, pt)[source]
-

Main function.

-
    -
  • Call init_context()
  • -
  • Load primitives
  • -
  • Create an evaluate function that lets you just eval some Python code
  • -
  • Redirect stdout to the log using a FileFaker object, and…
  • -
  • Start the main loop.
  • -
-
- -
- - -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/objects.inv b/docs/VUI-docs/build/html/objects.inv deleted file mode 100644 index 75ce1a5..0000000 Binary files a/docs/VUI-docs/build/html/objects.inv and /dev/null differ diff --git a/docs/VUI-docs/build/html/persist_task.html b/docs/VUI-docs/build/html/persist_task.html deleted file mode 100644 index 7238f53..0000000 --- a/docs/VUI-docs/build/html/persist_task.html +++ /dev/null @@ -1,222 +0,0 @@ - - - - - - - - Persist Task — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Persist Task

-

This module deals with persisting the “resources” (text files and the -stack) to the git repo in the JOY_HOME directory.

-
-
-class joy.vui.persist_task.PersistTask(home)[source]
-

This class deals with saving changes to the git repo.

-
-
-commit(message='auto-commit')[source]
-

Commit.

-
- -
-
-handle(message)[source]
-

Handle messages, dispatch to handle_FOO() methods.

-
- -
-
-handle_modify(message)[source]
-

Foo.

-
- -
-
-handle_open(message)[source]
-

Foo.

-
- -
-
-handle_persist(message)[source]
-

Foo.

-
- -
-
-handle_persist_new(message)[source]
-

Foo.

-
- -
-
-open(name)[source]
-

Look up the named file in home and return its content_id and data.

-
- -
-
-persist(content_id)[source]
-

Persist a resource.

-
- -
-
-scan()[source]
-

Return a sorted list of all the files in the home dir.

-
- -
-
-task_run()[source]
-

Stage any outstanding changes.

-
- -
- -
-
-class joy.vui.persist_task.PickledResource(filename, repo_relative_filename, thing=None)[source]
-

A Resource subclass that uses pickle on its file/thing.

-
- -
-
-class joy.vui.persist_task.Resource(filename, repo_relative_filename, thing=None)[source]
-

Handle the content of a text files as a list of lines, deal with -saving it and staging the changes to a repo.

-
-
-persist(repo)[source]
-

Save the lines to the file and stage the file in the repo.

-
- -
- -
-
-joy.vui.persist_task.check_filename(name)[source]
-

Sanity checks for filename.

-
- -
-
-joy.vui.persist_task.init_repo(repo_dir)[source]
-

Initialize a git repository in the directory. Stage and commit all -files (toplevel, not those in subdirectories if any) in the dir.

-
- -
-
-joy.vui.persist_task.make_repo_relative_path_maker(repo)[source]
-

Helper function to return a function that returns a path given a path, -that’s relative to the repository.

-
- -
-
-joy.vui.persist_task.open_repo(repo_dir=None, initialize=False)[source]
-

Open, or create, and return a Dulwich git repo object for the given -directory. If the dir path doesn’t exist it will be created. If it -does exist but isn’t a repo the result depends on the initialize -argument. If it is False (the default) a NotGitRepository -exception is raised, otherwise git init is effected in the dir.

-
- -
- - -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/py-modindex.html b/docs/VUI-docs/build/html/py-modindex.html deleted file mode 100644 index 04ca694..0000000 --- a/docs/VUI-docs/build/html/py-modindex.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - Python Module Index — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - -

Python Module Index

- -
- j -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
- j
- joy -
    - joy.vui.core -
    - joy.vui.display -
    - joy.vui.main -
    - joy.vui.persist_task -
    - joy.vui.stack_viewer -
    - joy.vui.text_viewer -
    - joy.vui.viewer -
- - -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/search.html b/docs/VUI-docs/build/html/search.html deleted file mode 100644 index 13bb00d..0000000 --- a/docs/VUI-docs/build/html/search.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - Search — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Search

-
- -

- Please activate JavaScript to enable the search - functionality. -

-
-

- From here you can search these documents. Enter your search - words into the box below and click "search". Note that the search - function will automatically search for all of the words. Pages - containing fewer words won't appear in the result list. -

-
- - - -
- -
- -
- -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/searchindex.js b/docs/VUI-docs/build/html/searchindex.js deleted file mode 100644 index 68cd713..0000000 --- a/docs/VUI-docs/build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({docnames:["core","display","index","main","persist_task","stack_viewer","text_viewer","viewer"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.viewcode":1,sphinx:54},filenames:["core.rst","display.rst","index.rst","main.rst","persist_task.rst","stack_viewer.rst","text_viewer.rst","viewer.rst"],objects:{"joy.vui":{core:[0,0,0,"-"],display:[1,0,0,"-"],main:[3,0,0,"-"],persist_task:[4,0,0,"-"],stack_viewer:[5,0,0,"-"],text_viewer:[6,0,0,"-"],viewer:[7,0,0,"-"]},"joy.vui.core":{ARROW_KEYS:[0,1,1,""],AVAILABLE_TASK_EVENTS:[0,1,1,""],CommandMessage:[0,2,1,""],MOUSE_EVENTS:[0,1,1,""],Message:[0,2,1,""],ModifyMessage:[0,2,1,""],OpenMessage:[0,2,1,""],PersistMessage:[0,2,1,""],ShutdownMessage:[0,2,1,""],TASK_EVENTS:[0,1,1,""],TheLoop:[0,2,1,""],World:[0,2,1,""],open_viewer_on_string:[0,4,1,""],push:[0,4,1,""]},"joy.vui.core.TheLoop":{install_task:[0,3,1,""],loop:[0,3,1,""],remove_task:[0,3,1,""],run_task:[0,3,1,""]},"joy.vui.core.World":{handle:[0,3,1,""]},"joy.vui.display":{Display:[1,2,1,""],Track:[1,2,1,""]},"joy.vui.display.Display":{at:[1,3,1,""],broadcast:[1,3,1,""],change_viewer:[1,3,1,""],close_viewer:[1,3,1,""],dispatch_event:[1,3,1,""],done_resizing:[1,3,1,""],focus:[1,3,1,""],grow_viewer:[1,3,1,""],init_text:[1,3,1,""],iter_viewers:[1,3,1,""],open_viewer:[1,3,1,""],redraw:[1,3,1,""]},"joy.vui.display.Track":{broadcast:[1,3,1,""],change_viewer:[1,3,1,""],close_viewer:[1,3,1,""],draw:[1,3,1,""],open_viewer:[1,3,1,""],redraw:[1,3,1,""],split:[1,3,1,""],viewer_at:[1,3,1,""]},"joy.vui.main":{FileFaker:[3,2,1,""],error_guard:[3,4,1,""],init:[3,4,1,""],init_context:[3,4,1,""],load_definitions:[3,4,1,""],load_primitives:[3,4,1,""],main:[3,4,1,""]},"joy.vui.main.FileFaker":{write:[3,3,1,""]},"joy.vui.persist_task":{PersistTask:[4,2,1,""],PickledResource:[4,2,1,""],Resource:[4,2,1,""],check_filename:[4,4,1,""],init_repo:[4,4,1,""],make_repo_relative_path_maker:[4,4,1,""],open_repo:[4,4,1,""]},"joy.vui.persist_task.PersistTask":{commit:[4,3,1,""],handle:[4,3,1,""],handle_modify:[4,3,1,""],handle_open:[4,3,1,""],handle_persist:[4,3,1,""],handle_persist_new:[4,3,1,""],open:[4,3,1,""],persist:[4,3,1,""],scan:[4,3,1,""],task_run:[4,3,1,""]},"joy.vui.persist_task.Resource":{persist:[4,3,1,""]},"joy.vui.stack_viewer":{StackViewer:[5,2,1,""],fsi:[5,4,1,""]},"joy.vui.text_viewer":{TextViewer:[6,2,1,""]},"joy.vui.text_viewer.TextViewer":{at:[6,3,1,""],close:[6,3,1,""]},"joy.vui.viewer":{MenuViewer:[7,2,1,""],SomeViewer:[7,2,1,""],Viewer:[7,2,1,""]},"joy.vui.viewer.MenuViewer":{draw:[7,3,1,""]},"joy.vui.viewer.Viewer":{close:[7,3,1,""],draw:[7,3,1,""],split:[7,3,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","data","Python data"],"2":["py","class","Python class"],"3":["py","method","Python method"],"4":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:data","2":"py:class","3":"py:method","4":"py:function"},terms:{"1024x768":2,"boolean":1,"break":[1,2],"case":1,"class":[0,1,3,4,5,6,7],"default":[2,4],"function":[0,1,2,3,4],"import":2,"new":[1,2,7],"return":[1,4,6,7],"var":2,"while":1,For:0,IDs:0,Not:1,One:2,The:[0,1,2,7],Then:2,There:[1,2],These:2,__contains__:1,abl:2,accept:1,action:2,actual:[0,1],add:0,addit:2,adjust:1,after:2,again:2,aid:2,aka:2,all:[0,1,2,4],along:[1,2],alreadi:[1,2],also:2,ani:[1,2,4,6,7],anoth:[1,2],appear:2,area:1,aren:2,argument:4,around:2,arrow:0,arrow_kei:0,assign:0,auto:[2,4],automat:[1,2],avail:[1,2,7],available_task_ev:0,bar:2,base:[0,7],been:0,begin:2,blank:2,book:1,bootstrap:2,boundari:1,bracket:2,broadcast:[0,1],buggi:2,bunch:0,button:[0,2],bypass:2,call:[1,2,3],can:[1,2],caus:1,chang:[2,4],change_view:1,chapter:[1,2],charact:6,check:[2,4],check_filenam:4,class_:1,clear:[1,2],click:[0,2],clock:[0,2,3],close:[0,1,2,6,7],close_view:1,code:[2,3],color:0,column:6,command:[0,1,2],commandmessag:0,commit:4,configur:2,constant:0,contain:0,content:[0,1,2,4],content_id:[0,4],context:[0,1],coord:1,coordin:[1,6,7],copi:[1,2],core:2,corner:1,coupl:1,cover:[1,2],creat:[1,2,3,4],crude:2,current:2,cursor:2,cut:2,dai:2,data:[2,4],deal:[0,4],defin:[0,1],definit:[2,3],delet:2,depend:[2,4],detail:0,develop:2,dict:1,dictionari:[0,2,3],differ:2,dir:[2,4],direct:2,directli:1,directori:[1,2,4],dispatch:[0,4],dispatch_ev:1,displai:[0,2,3],divid:2,docsi:[],docstr:2,doe:[1,4],doesn:4,don:1,done:1,done_res:1,dosen:2,down:0,drag:[1,2],draw:[1,7],dulwich:[2,4],dunno:[],dure:2,each:[1,2],edit:2,editor:2,effect:4,effici:1,els:1,end:2,enough:2,entir:2,environ:2,error_guard:3,escap:0,etc:[1,6,7],eval:3,evalu:3,event:[0,1,2,3],ever:2,everi:0,everyth:3,except:[1,3,4],execut:2,exist:[1,4],exit:0,expos:[1,2],facilit:1,fals:[1,4],feedback:2,feel:2,few:2,field:0,file:[1,2,3,4],filefak:3,filenam:[1,4],fill:2,first:2,fix:2,flag:0,focu:1,follow:2,foo:4,format:5,forth:2,four:1,framer:0,free:2,freed:1,from:3,frozenset:0,fsi:5,full:2,fullscreen:2,further:2,gain:1,get:[1,2,7],git:[2,4],give:0,given:[1,4,6],going:[1,2],good:[],grab:2,graphic:2,group:0,grow:[1,2],grow_view:1,gui:2,guid:[],hackili:1,handi:2,handl:[0,1,4],handle_foo:4,handle_modifi:4,handle_open:4,handle_persist:4,handle_persist_new:4,handler:[1,2,3],happen:1,has:2,have:[0,1,2],height:[1,7],help:2,helper:[0,1,4],hidden:[1,2],hide:1,highest:2,highlight:2,hold:[0,1],home:[2,3,4],horizont:2,how:[],idea:[],immedi:2,impair:2,implement:1,index:2,indic:1,inform:1,init:[2,3,4],init_context:[2,3],init_repo:4,init_text:1,initi:[3,4],insid:7,instal:[0,2],install_task:0,instead:[1,2,3],intend:2,interact:2,interest:2,interfac:2,interpret:2,invers:1,isn:4,item:[0,2,5],iter:1,iter_view:1,its:[0,1,2,4,7],joi:[0,1,3,4,5,6,7],joy_hom:[2,4],joyhom:1,joypi:[],just:[2,3],keep:[0,2],kei:[0,2],kind:2,languag:2,larger:1,last:1,layout:2,least:1,leav:2,left:[1,2],less:2,let:[2,3],librari:[2,3],like:2,line:[2,4,6],list:[2,4],littl:2,load:3,load_definit:3,load_primit:3,locat:[1,2],log:[0,2,3],look:[2,4],lookup:1,loop:[0,2,3],loos:1,lost:2,lower:7,machineri:[0,1,2],main:[0,2],mainloop:0,maintain:0,make_repo_relative_path_mak:4,manag:[0,1],mani:0,marker:2,mask:3,menu:[2,3],menuview:[1,7],messag:[0,1,3,4],method:[0,1,4],middl:2,millisecond:0,model:[1,2],modifi:0,modifymessag:0,modul:[0,1,4],more:[1,2,3],mous:[0,1,2],mouse_ev:0,mouse_up:1,mousemot:1,move:2,much:2,must:[1,7],name:[0,1,2,4],name_spac:3,neighbor:1,new_i:1,non:2,none:[1,4],note:2,notgitrepositori:4,notifi:0,now:7,nowher:2,number:[1,2],oberon:[0,1,2],object:[0,1,2,3,4],old:1,one:[1,2],ones:1,onli:[1,2],onto:[0,1,7],open:[0,1,2,3,4],open_repo:4,open_resource_at_good_loc:2,open_view:1,open_viewer_on_str:0,openmessag:0,option:2,order:1,other:2,otherwis:[1,4],out:2,output:2,outsid:2,outstand:4,overlai:1,page:2,paramet:1,pars:2,part:[1,7],pass:[0,1,2],path:4,paus:2,per:2,persist:2,persist_task:4,persistmessag:0,persisttask:[2,3,4],pickl:[0,3,4],pickledresourc:4,pixel:[1,2],plai:2,point:2,pop:2,possibl:0,present:1,press:[0,2],pretend:3,pretti:2,previou:2,primit:[2,3],print:[2,3],program:2,project:[1,2],provid:2,pull:3,pump:0,push:0,pygam:[0,1,2,3],python:[2,3],queue:0,quickli:2,quot:2,rais:4,ratio:1,realli:2,record:2,recov:2,rect:1,redirect:3,redraw:1,redrawn:7,refer:[0,1],regist:[1,2,3],rel:[1,4,7],releas:[2,6,7],remain:7,remov:0,remove_task:0,repo:4,repo_dir:4,repo_relative_filenam:4,repositori:4,reset:2,reset_log:2,resiz:[1,2],resolut:2,resourc:[0,2,4,6,7],rest:2,restart:2,restor:1,result:4,retain:1,retri:3,reus:[1,2],reveal:1,right:2,row:6,run:[0,2,3],run_task:0,runtim:2,same:[1,2],saniti:4,save:[2,4],scan:4,scratch:3,screen:[1,2,3,6],script:2,scroll:2,search:2,see:2,see_resourc:2,seem:2,select:2,send:[1,2],sender:[0,1],set:[0,1,2,3],share:2,shift:2,shine:0,should:[1,2],show:[0,2],shut:0,shutdownmessag:0,signal:0,simpl:[1,2],sit:2,size:[1,2],small:1,some:[0,1,2,3],someth:1,someview:7,somewher:[2,7],sort:[1,4],sourc:[0,1,3,4,5,6,7],space:[1,7],special:2,specif:2,split:[1,7],stack:[0,2,3,4],stack_hold:0,stack_id:0,stack_nam:0,stack_view:5,stackview:[2,5],stage:4,start:3,state:2,statu:0,stderr:3,stdout:[2,3],store:2,string:[0,1,2],strip:1,style:0,subclass:4,subdirectori:4,subject:0,success:[],support:[1,2],surfac:[1,5,6,7],symbol:2,sys:3,system:[0,1,2,3],take:[1,2],task:[0,2],task_ev:0,task_event_id:0,task_run:4,tend:2,termin:2,text:[0,2,3,4],text_view:6,textview:[1,2,6],than:1,thei:[1,2],theloop:0,them:2,ther:[],thi:[0,1,2,4],thing:[2,4],those:4,three:[1,2],through:1,thun:2,tick:0,tile:2,time:[0,1,2],togeth:3,too:1,top:[1,2],toplevel:4,traceback:[0,3],track:[0,1,2],track_ratio:1,trap:2,tupl:1,two:[1,2],txt:[2,3],type:2,typic:[0,1],underlin:[1,2],until:2,updat:[0,1,2],upper:7,usabl:2,use:2,used:0,usefulness:2,user:[2,3],uses:4,using:[2,3],usual:2,valid:1,valu:2,veri:2,version:2,vertic:[1,2],viewer:[0,1,2,3],viewer_at:1,visual:[1,2],vui:[0,1,3,4,5,6,7],want:[1,2],well:2,were:2,what:2,wheel:2,when:[0,1,2],where:2,whether:1,which:[1,2,7],whole:[1,2],wide:0,wider:1,width:2,wiggl:2,window:[0,2,3],within:1,won:2,word:2,work:[],workaround:2,world:[0,1,2,3],would:1,write:[2,3],written:2,x11:2,yet:2,yield:1,you:[1,2,3],your:2,zero:[1,2]},titles:["Core","Display","Welcome to Joy VUI\u2019s documentation!","Main Module","Persist Task","Stack Viewer","Text Viewer","Viewer"],titleterms:{"import":[],core:0,displai:1,document:2,guid:2,how:2,indic:2,joi:2,main:3,modul:[2,3],now:2,persist:4,quick:2,screenshot:2,sequenc:2,stack:5,start:2,structur:[],tabl:2,task:4,text:6,viewer:[5,6,7],vui:2,welcom:2,work:2}}) \ No newline at end of file diff --git a/docs/VUI-docs/build/html/stack_viewer.html b/docs/VUI-docs/build/html/stack_viewer.html deleted file mode 100644 index 1af77e3..0000000 --- a/docs/VUI-docs/build/html/stack_viewer.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - Stack Viewer — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Stack Viewer

-
-
-class joy.vui.stack_viewer.StackViewer(surface)[source]
-
- -
-
-joy.vui.stack_viewer.fsi(item)[source]
-

Format Stack Item

-
- -
- - -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/text_viewer.html b/docs/VUI-docs/build/html/text_viewer.html deleted file mode 100644 index 9249ed6..0000000 --- a/docs/VUI-docs/build/html/text_viewer.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - Text Viewer — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Text Viewer

-
-
-class joy.vui.text_viewer.TextViewer(surface)[source]
-
-
-at(x, y)[source]
-

Given screen coordinates return the line, row, and column of the -character there.

-
- -
-
-close()[source]
-

Close the viewer and release any resources, etc…

-
- -
- -
- - -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/build/html/viewer.html b/docs/VUI-docs/build/html/viewer.html deleted file mode 100644 index 12b1fc0..0000000 --- a/docs/VUI-docs/build/html/viewer.html +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - Viewer — Joy VUI 0.1 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Viewer

-
-
-class joy.vui.viewer.MenuViewer(surface)[source]
-

MenuViewer class

-
-
-draw()[source]
-

Draw the viewer onto its surface.

-
- -
- -
-
-class joy.vui.viewer.SomeViewer(surface)[source]
-
- -
-
-class joy.vui.viewer.Viewer(surface)[source]
-

Base Viewer class

-
-
-close()[source]
-

Close the viewer and release any resources, etc…

-
- -
-
-draw()[source]
-

Draw the viewer onto its surface.

-
- -
-
-split(y)[source]
-

Split the viewer at the y coordinate (which is relative to the -viewer’s surface and must be inside it somewhere) and return the -remaining height. The upper part of the viewer remains (and gets -redrawn on a new surface) and the lower space is now available -for e.g. a new viewer.

-
- -
- -
- - -
-
-
- -
-
- - - - - - - \ No newline at end of file diff --git a/docs/VUI-docs/make.bat b/docs/VUI-docs/make.bat deleted file mode 100644 index 543c6b1..0000000 --- a/docs/VUI-docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd diff --git a/docs/VUI-docs/source/_static/Joy-VUI-screenshot.PNG b/docs/VUI-docs/source/_static/Joy-VUI-screenshot.PNG deleted file mode 100644 index 53f7bf1..0000000 Binary files a/docs/VUI-docs/source/_static/Joy-VUI-screenshot.PNG and /dev/null differ diff --git a/docs/VUI-docs/source/_static/packages_Vui.png b/docs/VUI-docs/source/_static/packages_Vui.png deleted file mode 100644 index a1e8936..0000000 Binary files a/docs/VUI-docs/source/_static/packages_Vui.png and /dev/null differ diff --git a/docs/VUI-docs/source/conf.py b/docs/VUI-docs/source/conf.py deleted file mode 100644 index b376a9b..0000000 --- a/docs/VUI-docs/source/conf.py +++ /dev/null @@ -1,179 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/master/config - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys -sys.path.insert(0, os.path.abspath('../../..')) - - -# -- Project information ----------------------------------------------------- - -project = u'Joy VUI' -copyright = u'2019, Simon Forman' -author = u'Simon Forman' - -# The short X.Y version -version = u'' -# The full version, including alpha/beta/rc tags -release = u'0.1' - - -# -- General configuration --------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.imgmath', - 'sphinx.ext.viewcode', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'colorful' - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} - - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'JoyVUIdoc' - - -# -- Options for LaTeX output ------------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'JoyVUI.tex', u'Joy VUI Documentation', - u'Simon Forman', 'manual'), -] - - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'joyvui', u'Joy VUI Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ---------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'JoyVUI', u'Joy VUI Documentation', - author, 'JoyVUI', 'One line description of project.', - 'Miscellaneous'), -] - - -# -- Options for Epub output ------------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = project - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -# -# epub_identifier = '' - -# A unique identification for the text. -# -# epub_uid = '' - -# A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] - - -# -- Extension configuration ------------------------------------------------- diff --git a/docs/VUI-docs/source/core.rst b/docs/VUI-docs/source/core.rst deleted file mode 100644 index 06bc602..0000000 --- a/docs/VUI-docs/source/core.rst +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.core - :members: diff --git a/docs/VUI-docs/source/display.rst b/docs/VUI-docs/source/display.rst deleted file mode 100644 index 6083403..0000000 --- a/docs/VUI-docs/source/display.rst +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.display - :members: diff --git a/docs/VUI-docs/source/index.rst b/docs/VUI-docs/source/index.rst deleted file mode 100644 index 528549c..0000000 --- a/docs/VUI-docs/source/index.rst +++ /dev/null @@ -1,175 +0,0 @@ -.. Joy VUI documentation master file, created by - sphinx-quickstart on Mon May 06 19:41:42 2019. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to Joy VUI's documentation! -=================================== - -A simple Graphical User Interface for the Joy programming language, -written using Pygame to bypass X11 et. al., modeled on the Oberon OS, and -intended to be just functional enough to support bootstrapping further Joy -development. - -Screenshot ------------------------------ -.. image:: _static/Joy-VUI-screenshot.PNG - - -Quick Start ------------------------------ - -If you have PyGame and Dulwich installed you should be able to start the -VUI with the following command: - -:: - - python -m joy.vui - -This will create a ``~/.thun`` directory in your home dir to store your -data. - -How it works now. ------------------------------ - -The VUI is more-or-less a crude text editor along with -a simple Joy runtime (interpreter, stack, and dictionary.) It auto-saves -any named files (in a versioned home directory) and you can write new Joy -primitives in Python and Joy definitions and immediately install and use -them, as well as recording them for reuse (after restarts.) - -The only dependencies are Pygame and Dulwich (a Python Git library.) - -When the main.py script starts it checks for an environment var "JOY_HOME" -which should point to a directory where you want the system to store the -files ("resources") it will edit and save, this directory defaults to -``~/.thun``. The first time you run it, it will create some default files -as content. Right click on see_resources to open a viewer with the list -of resources (files), copy a name to the stack and right click on -open_resource_at_good_location to open a viewer on that resource. - -Right now the screen size defaults to windowed 1024x768, but if you pass -the ``-f`` option to the main.py script the UI will take up the full screen -at the highest available resolution. The window is divided into two (or -three in fullscreen) vertical "tracks", and the number and width of the -tracks are fixed at start up. (Feel free to edit the values in main.py to -play around with different track configurations.) Each track gets divided -horizontally into zero or more "viewers" (like windows in a windowed GUI, -cf. Chapter 4 of "Project Oberon") for a kind of tiled layout. - -Currently, there are only two kinds of (interesting) viewers: TextViewers -and StackViewer. The TextViewers are crude text editors. They provide -just enough functionality to let the user write text and code (Python and -Joy) and execute Joy functions. One important thing they do is -automatically save their content after changes. No more lost work. - -The StackViewer is a specialized TextViewer that shows the contents of the -Joy stack one line per stack item. It's a very handy visual aid to keep -track of what's going on. There's also a log.txt file that gets written -to when commands are executed, and so records the log of user actions and -system events. It tends to fill up quickly so there's a reset_log command -that clears it out. - -Viewers have "grow" and "close" in their menu bars. These are buttons. -When you right-click on grow a viewer a copy is created that covers that -viewer's entire track. If you grow a viewer that already takes up its -whole track then a copy is created that takes up an additional track, up -to the whole screen. Closing a viewer just deletes that viewer, and when -a track has no more viewers, it is deleted and that exposes any previous -tracks and viewers that were hidden. - -(Note: if you ever close all the viewers and are sitting at a blank screen -with nowhere to type and execute commands, press the Pause/Break key. -This will open a new "trap" viewer which you can then use to recover.) - -Copies of a viewer all share the same model and update their display as it -changes. (If you have two viewers open on the same named resource and edit -one you'll see the other update as you type.) - -UI Guide ------------------------------ - -left mouse sets cursor in text, in menu bar resizes viewer interactively -(this is a little buggy in that you can move the mouse quickly and get -outside the menu, leaving the viewer in the "resizing" state. Until I fix -this, the workaround is to just grab the menu bar again and wiggle it a -few pixels and let go. This will reset the machinery.) - -Right mouse executes Joy command (functions), and you can drag with the -right button to highlight (well, underline) commands. Words that aren't -names of Joy commands won't be underlined. Release the button to execute -the command. - -The middle mouse button (usually a wheel these days) scrolls the text but -you can also click and drag any viewer with it to move that viewer to -another track or to a different location in the same track. There's no -direct visual feedback for this (yet) but that dosen't seem to impair its -usefulness. - -F1, F2 - set selection begin and end markers (crude but usable.) - -F3 - copy selected text to the top of the stack. - -Shift-F3 - as copy then run "parse" command on the string. - -F4 - cut selected text to the top of the stack. - -Shift-F4 - as cut then run "pop" (delete selection.) - -Joy ----------------------------- - -Pretty much all of the rest of the functionality of the system is provided -by executing Joy commands (aka functions, aka "words" in Forth) by right- -clicking on their names in any text. - -To get help on a Joy function select the name of the function in a -TextViewer using F1 and F2, then press shift-F3 to parse the selection. -The function (really its Symbol) will appear on the stack in brackets (a -"quoted program" such as "[pop]".) Then right-click on the word help in -any TextViewer (if it's not already there, just type it in somewhere.) -This will print the docstring or definition of the word (function) to -stdout. At some point I'll write a thing to send that to the log.txt file -instead, but for now look for output in the terminal. - - -Modules ------------------------------ - -.. image:: _static/packages_Vui.png - - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - core - main - display - viewer - text_viewer - stack_viewer - persist_task - - -Start Up Sequence ------------------------------- - -PersistTask is the first (non-PyGame-specific) object created. - -The ``screen``, ``clock``, and ``pt`` are created in ``init()`` and passed -into ``main()``, which calls ``init_context()`` and then starts -the main loop. - -During ``init_context()`` a few text viewers are opened on files -in the home dir with the help of the ``pt``. Then the main loop -is started and the ``pt`` task is installed and ``pt`` and ``world`` -handlers are registered. - - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/VUI-docs/source/main.rst b/docs/VUI-docs/source/main.rst deleted file mode 100644 index f5b6b08..0000000 --- a/docs/VUI-docs/source/main.rst +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.main - :members: diff --git a/docs/VUI-docs/source/persist_task.rst b/docs/VUI-docs/source/persist_task.rst deleted file mode 100644 index ef05e2c..0000000 --- a/docs/VUI-docs/source/persist_task.rst +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.persist_task - :members: diff --git a/docs/VUI-docs/source/stack_viewer.rst b/docs/VUI-docs/source/stack_viewer.rst deleted file mode 100644 index 60f3458..0000000 --- a/docs/VUI-docs/source/stack_viewer.rst +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.stack_viewer - :members: diff --git a/docs/VUI-docs/source/text_viewer.rst b/docs/VUI-docs/source/text_viewer.rst deleted file mode 100644 index 7918dbc..0000000 --- a/docs/VUI-docs/source/text_viewer.rst +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.text_viewer - :members: diff --git a/docs/VUI-docs/source/viewer.rst b/docs/VUI-docs/source/viewer.rst deleted file mode 100644 index 6864c84..0000000 --- a/docs/VUI-docs/source/viewer.rst +++ /dev/null @@ -1,3 +0,0 @@ - -.. automodule:: joy.vui.viewer - :members: diff --git a/docs/sphinx_docs/_build/html/_modules/joy/library.html b/docs/sphinx_docs/_build/html/_modules/joy/library.html index 733f63b..5e6bc9c 100644 --- a/docs/sphinx_docs/_build/html/_modules/joy/library.html +++ b/docs/sphinx_docs/_build/html/_modules/joy/library.html @@ -33,7 +33,7 @@

Source code for joy.library

 # -*- coding: utf-8 -*-
 #
-#    Copyright © 2014, 2015, 2017, 2018 Simon Forman
+#    Copyright © 2014-2020 Simon Forman
 #
 #    This file is part of Thun
 #
@@ -56,12 +56,7 @@
 returns a dictionary of Joy functions suitable for use with the joy()
 function.
 '''
-from __future__ import print_function
 from builtins import map, object, range, zip
-from logging import getLogger
-
-_log = getLogger(__name__)
-_log.info('Loading library.')
 
 from inspect import getdoc
 from functools import wraps
@@ -70,38 +65,13 @@
 import operator, math
 
 from .parser import text_to_expression, Symbol
-from .utils.stack import expression_to_string, list_to_stack, iter_stack, pick, concat
-import sys
-if sys.version_info.major < 3:
-	from .utils.brutal_hackery import rename_code_object
-else:
-	rename_code_object = lambda _: lambda f: f
-
 from .utils import generated_library as genlib
-from .utils.types import (
-	compose,
-	ef,
-	stack_effect,
-	AnyJoyType,
-	AnyStarJoyType,
-	BooleanJoyType,
-	NumberJoyType,
-	NumberStarJoyType,
-	StackJoyType,
-	StackStarJoyType,
-	FloatJoyType,
-	IntJoyType,
-	SymbolJoyType,
-	CombinatorJoyType,
-	TextJoyType,
-	_functions,
-	FUNCTIONS,
-	infer,
-	infer_expression,
-	JoyTypeError,
-	combinator_effect,
-	poly_combinator_effect,
-	doc_from_stack_effect,
+from .utils.stack import (
+	concat,
+	expression_to_string,
+	iter_stack,
+	list_to_stack,
+	pick,
 	)
 
 
@@ -115,38 +85,6 @@
 '''
 
 
-_SYM_NUMS = lambda c=count(): next(c)
-_COMB_NUMS = lambda c=count(): next(c)
-
-
-_R = list(range(10))
-A = a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = list(map(AnyJoyType, _R))
-B = b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 = list(map(BooleanJoyType, _R))
-N = n0, n1, n2, n3, n4, n5, n6, n7, n8, n9 = list(map(NumberJoyType, _R))
-S = s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 = list(map(StackJoyType, _R))
-F = f0, f1, f2, f3, f4, f5, f6, f7, f8, f9 = list(map(FloatJoyType, _R))
-I = i0, i1, i2, i3, i4, i5, i6, i7, i8, i9 = list(map(IntJoyType, _R))
-T = t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 = list(map(TextJoyType, _R))
-
-
-_R = list(range(1, 11))
-As = list(map(AnyStarJoyType, _R))
-Ns = list(map(NumberStarJoyType, _R))
-Ss = list(map(StackStarJoyType, _R))
-
-
-# "sec": stack effect comment, like in Forth.
-sec0 = stack_effect(t1)()
-sec1 = stack_effect(s0, i1)(s1)
-sec2 = stack_effect(s0, i1)(a1)
-sec_binary_cmp = stack_effect(n1, n2)(b1)
-sec_binary_ints = stack_effect(i1, i2)(i3)
-sec_binary_logic = stack_effect(b1, b2)(b3)
-sec_binary_math = stack_effect(n1, n2)(n3)
-sec_unary_logic = stack_effect(a1)(b1)
-sec_unary_math = stack_effect(n1)(n2)
-sec_Ns_math = stack_effect((Ns[1], s1),)(n0)
-
 # This is the main dict we're building.
 _dictionary = {}
 
@@ -168,7 +106,6 @@
 	('bool', ['truthy']),
 	('mul', ['*']),
 	('floordiv', ['/floor', '//']),
-	('floor', ['round']),
 	('truediv', ['/', 'div']),
 	('mod', ['%', 'rem', 'remainder', 'modulus']),
 	('eq', ['=']),
@@ -206,56 +143,6 @@
 			D[alias] = F
-
[docs]def yin_functions(): - ''' - Return a dict of named stack effects. - - "Yin" functions are those that only rearrange items in stacks and - can be defined completely by their stack effects. This means they - can be auto-compiled. - ''' - # pylint: disable=unused-variable - cons = ef(a1, s0)((a1, s0)) - ccons = compose(cons, cons) - dup = ef(a1)(a1, a1) - dupd = ef(a2, a1)(a2, a2, a1) - dupdd = ef(a3, a2, a1)(a3, a3, a2, a1) - first = ef((a1, s1),)(a1,) - over = ef(a2, a1)(a2, a1, a2) - pop = ef(a1)() - popd = ef(a2, a1,)(a1) - popdd = ef(a3, a2, a1,)(a2, a1,) - popop = ef(a2, a1,)() - popopd = ef(a3, a2, a1,)(a1) - popopdd = ef(a4, a3, a2, a1,)(a2, a1) - rest = ef((a1, s0),)(s0,) - rolldown = ef(a1, a2, a3)(a2, a3, a1) - rollup = ef(a1, a2, a3)(a3, a1, a2) - rrest = compose(rest, rest) - second = compose(rest, first) - stack = s0, (s0, s0) - swaack = (s1, s0), (s0, s1) - swap = ef(a1, a2)(a2, a1) - swons = compose(swap, cons) - third = compose(rest, second) - tuck = ef(a2, a1)(a1, a2, a1) - uncons = ef((a1, s0),)(a1, s0) - unswons = compose(uncons, swap) - stuncons = compose(stack, uncons) - stununcons = compose(stack, uncons, uncons) - unit = ef(a1)((a1, ())) - - first_two = compose(uncons, uncons, pop) - fourth = compose(rest, third) - - _Tree_add_Ee = compose(pop, swap, rolldown, rrest, ccons) - _Tree_get_E = compose(popop, second) - _Tree_delete_clear_stuff = compose(rollup, popop, rest) - _Tree_delete_R0 = compose(over, first, swap, dup) - - return locals()
- - definitions = ('''\ ? dup truthy *fraction [uncons] dip uncons [swap] dip concat [*] infra [*] dip cons @@ -290,6 +177,7 @@ sqr dup mul step_zero 0 roll> step swoncat swap concat +tailrec [i] genrec ternary unary [popop] dip unary nullary popd unquoted [i] dip @@ -351,7 +239,6 @@ ''' @FunctionWrapper @wraps(f) - @rename_code_object(f.__name__) def inner(stack, expression, dictionary): return f(stack), expression, dictionary return inner @@ -363,7 +250,6 @@ ''' @FunctionWrapper @wraps(f) - @rename_code_object(f.__name__) def inner(stack, expression, dictionary): (a, (b, stack)) = stack result = f(b, a) @@ -377,7 +263,6 @@ ''' @FunctionWrapper @wraps(f) - @rename_code_object(f.__name__) def inner(stack, expression, dictionary): (a, stack) = stack result = f(a) @@ -426,7 +311,6 @@ Add the definition to the dictionary. ''' F = class_.parse_definition(definition) - _log.info('Adding definition %s := %s', F.name, expression_to_string(F.body)) dictionary[F.name] = F @classmethod @@ -451,7 +335,6 @@
[docs]@inscribe -@sec0 @FunctionWrapper def inscribe_(stack, expression, dictionary): ''' @@ -478,18 +361,17 @@ return expression, stack
-
[docs]@inscribe -@SimpleFunctionWrapper -def infer_(stack): - '''Attempt to infer the stack effect of a Joy expression.''' - E, stack = stack - effects = infer_expression(E) - e = list_to_stack([(fi, (fo, ())) for fi, fo in effects]) - return e, stack
+# @inscribe +# @SimpleFunctionWrapper +# def infer_(stack): +# '''Attempt to infer the stack effect of a Joy expression.''' +# E, stack = stack +# effects = infer_expression(E) +# e = list_to_stack([(fi, (fo, ())) for fi, fo in effects]) +# return e, stack
[docs]@inscribe -@sec2 @SimpleFunctionWrapper def getitem(stack): ''' @@ -511,7 +393,6 @@
[docs]@inscribe -@sec1 @SimpleFunctionWrapper def drop(stack): ''' @@ -539,7 +420,6 @@
[docs]@inscribe -@sec1 @SimpleFunctionWrapper def take(stack): ''' @@ -614,7 +494,6 @@
[docs]@inscribe -@sec_Ns_math @SimpleFunctionWrapper def max_(S): '''Given a list find the maximum.''' @@ -623,7 +502,6 @@
[docs]@inscribe -@sec_Ns_math @SimpleFunctionWrapper def min_(S): '''Given a list find the minimum.''' @@ -632,7 +510,6 @@
[docs]@inscribe -@sec_Ns_math @SimpleFunctionWrapper def sum_(S): '''Given a quoted sequence of numbers return the sum. @@ -679,7 +556,6 @@ return list_to_stack(sorted(iter_stack(tos))), stack
-_functions['clear'] = s0, s1
[docs]@inscribe @SimpleFunctionWrapper def clear(stack): @@ -721,7 +597,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), s7, s6) @SimpleFunctionWrapper def concat_(S): '''Concatinate the two lists on the top of the stack. @@ -731,7 +606,7 @@ ---------------------------- [a b c d e f] -''' + ''' (tos, (second, stack)) = S return concat(second, tos), stack
@@ -772,7 +647,6 @@
[docs]@inscribe -@sec_unary_math @SimpleFunctionWrapper def succ(S): '''Increment TOS.''' @@ -781,7 +655,6 @@
[docs]@inscribe -@sec_unary_math @SimpleFunctionWrapper def pred(S): '''Decrement TOS.''' @@ -883,15 +756,15 @@ def sharing(stack, expression, dictionary): '''Print redistribution information.''' print("You may convey verbatim copies of the Program's source code as" - ' you receive it, in any medium, provided that you conspicuously' - ' and appropriately publish on each copy an appropriate copyright' - ' notice; keep intact all notices stating that this License and' - ' any non-permissive terms added in accord with section 7 apply' - ' to the code; keep intact all notices of the absence of any' - ' warranty; and give all recipients a copy of this License along' - ' with the Program.' - ' You should have received a copy of the GNU General Public License' - ' along with Thun. If not see <http://www.gnu.org/licenses/>.') + ' you receive it, in any medium, provided that you conspicuously' + ' and appropriately publish on each copy an appropriate copyright' + ' notice; keep intact all notices stating that this License and' + ' any non-permissive terms added in accord with section 7 apply' + ' to the code; keep intact all notices of the absence of any' + ' warranty; and give all recipients a copy of this License along' + ' with the Program.' + ' You should have received a copy of the GNU General Public License' + ' along with Thun. If not see <http://www.gnu.org/licenses/>.') return stack, expression, dictionary
@@ -900,14 +773,14 @@ def warranty(stack, expression, dictionary): '''Print warranty information.''' print('THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY' - ' APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE' - ' COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM' - ' "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR' - ' IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES' - ' OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE' - ' ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS' - ' WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE' - ' COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.') + ' APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE' + ' COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM' + ' "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR' + ' IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES' + ' OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE' + ' ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS' + ' WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE' + ' COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.') return stack, expression, dictionary
@@ -964,7 +837,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), s1) @FunctionWrapper def i(stack, expression, dictionary): ''' @@ -982,7 +854,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), s1) @FunctionWrapper def x(stack, expression, dictionary): ''' @@ -1000,7 +871,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), s7, s6) @FunctionWrapper def b(stack, expression, dictionary): ''' @@ -1017,7 +887,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), a1, s1) @FunctionWrapper def dupdip(stack, expression, dictionary): ''' @@ -1037,7 +906,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), s7, s6) @FunctionWrapper def infra(stack, expression, dictionary): ''' @@ -1055,7 +923,6 @@
[docs]@inscribe -#@combinator_effect(_COMB_NUMS(), s7, s6, s5, s4) @FunctionWrapper def genrec(stack, expression, dictionary): ''' @@ -1117,19 +984,18 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), s7, s6) @FunctionWrapper def map_(S, expression, dictionary): ''' Run the quoted program on TOS on the items in the list under it, push a new list with the results in place of the program and original list. ''' -# (quote, (aggregate, stack)) = S -# results = list_to_stack([ -# joy((term, stack), quote, dictionary)[0][0] -# for term in iter_stack(aggregate) -# ]) -# return (results, stack), expression, dictionary + # (quote, (aggregate, stack)) = S + # results = list_to_stack([ + # joy((term, stack), quote, dictionary)[0][0] + # for term in iter_stack(aggregate) + # ]) + # return (results, stack), expression, dictionary (quote, (aggregate, stack)) = S if not aggregate: return (aggregate, stack), expression, dictionary @@ -1198,20 +1064,7 @@ # return (q, (p, stack)), expression, dictionary -def branch_true(stack, expression, dictionary): - # pylint: disable=unused-variable - (then, (else_, (flag, stack))) = stack - return stack, concat(then, expression), dictionary - - -def branch_false(stack, expression, dictionary): - # pylint: disable=unused-variable - (then, (else_, (flag, stack))) = stack - return stack, concat(else_, expression), dictionary - -
[docs]@inscribe -@poly_combinator_effect(_COMB_NUMS(), [branch_true, branch_false], b1, s7, s6) @FunctionWrapper def branch(stack, expression, dictionary): ''' @@ -1236,9 +1089,6 @@ return stack, concat(then if flag else else_, expression), dictionary
-#FUNCTIONS['branch'] = CombinatorJoyType('branch', [branch_true, branch_false], 100) - - ##@inscribe ##@FunctionWrapper ##def ifte(stack, expression, dictionary): @@ -1308,7 +1158,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), a1, s1) @FunctionWrapper def dip(stack, expression, dictionary): ''' @@ -1328,7 +1177,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), a2, a1, s1) @FunctionWrapper def dipd(S, expression, dictionary): ''' @@ -1346,7 +1194,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), a3, a2, a1, s1) @FunctionWrapper def dipdd(S, expression, dictionary): ''' @@ -1364,7 +1211,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), a1, s1) @FunctionWrapper def app1(S, expression, dictionary): ''' @@ -1384,7 +1230,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), a2, a1, s1) @FunctionWrapper def app2(S, expression, dictionary): '''Like app1 with two items. @@ -1405,7 +1250,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), a3, a2, a1, s1) @FunctionWrapper def app3(S, expression, dictionary): '''Like app1 with three items. @@ -1428,7 +1272,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), s7, s6) @FunctionWrapper def step(S, expression, dictionary): ''' @@ -1464,7 +1307,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), i1, s6) @FunctionWrapper def times(stack, expression, dictionary): ''' @@ -1513,21 +1355,7 @@ # return stack, expression, dictionary -def loop_true(stack, expression, dictionary): - quote, (flag, stack) = stack # pylint: disable=unused-variable - return stack, concat(quote, (S_pop, expression)), dictionary - -def loop_two_true(stack, expression, dictionary): - quote, (flag, stack) = stack # pylint: disable=unused-variable - return stack, concat(quote, (S_pop, concat(quote, (S_pop, expression)))), dictionary - -def loop_false(stack, expression, dictionary): - quote, (flag, stack) = stack # pylint: disable=unused-variable - return stack, expression, dictionary - -
[docs]@inscribe -@poly_combinator_effect(_COMB_NUMS(), [loop_two_true, loop_true, loop_false], b1, s6) @FunctionWrapper def loop(stack, expression, dictionary): ''' @@ -1550,7 +1378,6 @@
[docs]@inscribe -@combinator_effect(_COMB_NUMS(), a1, a2, s6, s7, s8) @FunctionWrapper def cmp_(stack, expression, dictionary): ''' @@ -1583,137 +1410,50 @@ #divmod_ = pm = __(n2, n1), __(n4, n3) - sec_binary_cmp(BinaryBuiltinWrapper(operator.eq)), - sec_binary_cmp(BinaryBuiltinWrapper(operator.ge)), - sec_binary_cmp(BinaryBuiltinWrapper(operator.gt)), - sec_binary_cmp(BinaryBuiltinWrapper(operator.le)), - sec_binary_cmp(BinaryBuiltinWrapper(operator.lt)), - sec_binary_cmp(BinaryBuiltinWrapper(operator.ne)), + BinaryBuiltinWrapper(operator.eq), + BinaryBuiltinWrapper(operator.ge), + BinaryBuiltinWrapper(operator.gt), + BinaryBuiltinWrapper(operator.le), + BinaryBuiltinWrapper(operator.lt), + BinaryBuiltinWrapper(operator.ne), - sec_binary_ints(BinaryBuiltinWrapper(operator.xor)), - sec_binary_ints(BinaryBuiltinWrapper(operator.lshift)), - sec_binary_ints(BinaryBuiltinWrapper(operator.rshift)), + BinaryBuiltinWrapper(operator.xor), + BinaryBuiltinWrapper(operator.lshift), + BinaryBuiltinWrapper(operator.rshift), - sec_binary_logic(BinaryBuiltinWrapper(operator.and_)), - sec_binary_logic(BinaryBuiltinWrapper(operator.or_)), + BinaryBuiltinWrapper(operator.and_), + BinaryBuiltinWrapper(operator.or_), - sec_binary_math(BinaryBuiltinWrapper(operator.add)), - sec_binary_math(BinaryBuiltinWrapper(operator.floordiv)), - sec_binary_math(BinaryBuiltinWrapper(operator.mod)), - sec_binary_math(BinaryBuiltinWrapper(operator.mul)), - sec_binary_math(BinaryBuiltinWrapper(operator.pow)), - sec_binary_math(BinaryBuiltinWrapper(operator.sub)), - sec_binary_math(BinaryBuiltinWrapper(operator.truediv)), + BinaryBuiltinWrapper(operator.add), + BinaryBuiltinWrapper(operator.floordiv), + BinaryBuiltinWrapper(operator.mod), + BinaryBuiltinWrapper(operator.mul), + BinaryBuiltinWrapper(operator.pow), + BinaryBuiltinWrapper(operator.sub), + BinaryBuiltinWrapper(operator.truediv), - sec_unary_logic(UnaryBuiltinWrapper(bool)), - sec_unary_logic(UnaryBuiltinWrapper(operator.not_)), + UnaryBuiltinWrapper(bool), + UnaryBuiltinWrapper(operator.not_), - sec_unary_math(UnaryBuiltinWrapper(abs)), - sec_unary_math(UnaryBuiltinWrapper(operator.neg)), - sec_unary_math(UnaryBuiltinWrapper(sqrt)), + UnaryBuiltinWrapper(abs), + UnaryBuiltinWrapper(operator.neg), + UnaryBuiltinWrapper(sqrt), - stack_effect(n1)(i1)(UnaryBuiltinWrapper(floor)), + UnaryBuiltinWrapper(floor), + UnaryBuiltinWrapper(round), ): inscribe(F) del F # Otherwise Sphinx autodoc will pick it up. -YIN_STACK_EFFECTS = yin_functions() -add_aliases(YIN_STACK_EFFECTS, ALIASES) - -# Load the auto-generated primitives into the dictionary. -_functions.update(YIN_STACK_EFFECTS) -# exec ''' - -# eh = compose(dup, bool) -# sqr = compose(dup, mul) -# of = compose(swap, at) - -# ''' in dict(compose=compose), _functions -for name in sorted(_functions): - sec = _functions[name] - F = FUNCTIONS[name] = SymbolJoyType(name, [sec], _SYM_NUMS()) - if name in YIN_STACK_EFFECTS: - _log.info('Setting stack effect for Yin function %s := %s', F.name, doc_from_stack_effect(*sec)) - for name, primitive in getmembers(genlib, isfunction): inscribe(SimpleFunctionWrapper(primitive)) add_aliases(_dictionary, ALIASES) -add_aliases(_functions, ALIASES) -add_aliases(FUNCTIONS, ALIASES) DefinitionWrapper.add_definitions(definitions, _dictionary) - - -EXPECTATIONS = dict( - ifte=(s7, (s6, (s5, s4))), - nullary=(s7, s6), - run=(s7, s6), -) -EXPECTATIONS['while'] = (s7, (s6, s5)) - - -for name in ''' - dinfrirst - nullary - ifte - run - dupdipd codireco - while - '''.split(): - C = _dictionary[name] - expect = EXPECTATIONS.get(name) - if expect: - sec = doc_from_stack_effect(expect) - _log.info('Setting stack EXPECT for combinator %s := %s', C.name, sec) - else: - _log.info('combinator %s', C.name) - FUNCTIONS[name] = CombinatorJoyType(name, [C], _COMB_NUMS(), expect) - - -for name in (''' - of quoted enstacken ? - unary binary ternary - sqr unquoted - '''.split()): - of_ = _dictionary[name] - secs = infer_expression(of_.body) - assert len(secs) == 1, repr(secs) - _log.info( - 'Setting stack effect for definition %s := %s', - name, - doc_from_stack_effect(*secs[0]), - ) - FUNCTIONS[name] = SymbolJoyType(name, infer_expression(of_.body), _SYM_NUMS()) - - -#sec_Ns_math(_dictionary['product']) - -## product == 1 swap [*] step -## flatten == [] swap [concat] step -## pam == [i] map -## size == 0 swap [pop ++] step -## fork == [i] app2 -## cleave == fork [popd] dip -## average == [sum 1.0 *] [size] cleave / -## gcd == 1 [tuck modulus dup 0 >] loop pop -## least_fraction == dup [gcd] infra [div] concat map -## *fraction == [uncons] dip uncons [swap] dip concat [*] infra [*] dip cons -## *fraction0 == concat [[swap] dip * [*] dip] infra -## down_to_zero == [0 >] [dup --] while -## range_to_zero == unit [down_to_zero] infra -## anamorphism == [pop []] swap [dip swons] genrec -## range == [0 <=] [1 - dup] anamorphism -## while == swap [nullary] cons dup dipd concat loop -## dupdipd == dup dipd -## tailrec == [i] genrec -## step_zero == 0 roll> step -## codireco == cons dip rest cons -## make_generator == [codireco] ccons -## ifte == [nullary not] dipd branch
diff --git a/docs/sphinx_docs/_build/html/_modules/joy/parser.html b/docs/sphinx_docs/_build/html/_modules/joy/parser.html index 2b3d36d..7045d3d 100644 --- a/docs/sphinx_docs/_build/html/_modules/joy/parser.html +++ b/docs/sphinx_docs/_build/html/_modules/joy/parser.html @@ -74,7 +74,7 @@ #TODO: explain the details of float lits and strings. -FLOAT = r'-?\d+\.\d*(e(-|\+)\d+)+' +FLOAT = r'-?\d+\.\d*(e(-|\+)\d+)?' INT = r'-?\d+' SYMBOL = r'[•\w!@$%^&*()_+<>?|\/;:`~,.=-]+' BRACKETS = r'\[|\]' diff --git a/docs/sphinx_docs/_build/html/genindex.html b/docs/sphinx_docs/_build/html/genindex.html index f4e47a5..f1daff1 100644 --- a/docs/sphinx_docs/_build/html/genindex.html +++ b/docs/sphinx_docs/_build/html/genindex.html @@ -45,10 +45,8 @@ | H | I | J - | K | L | M - | N | O | P | R @@ -58,35 +56,20 @@ | V | W | X - | Y | Z

A

- +
    @@ -530,14 +447,6 @@
-

Y

- - -
-

Z

- - -
    diff --git a/docs/sphinx_docs/_build/html/library.html b/docs/sphinx_docs/_build/html/library.html index 3b8225c..7a377eb 100644 --- a/docs/sphinx_docs/_build/html/library.html +++ b/docs/sphinx_docs/_build/html/library.html @@ -294,8 +294,7 @@ the stack discarding the rest of the stack.

    joy.library.drop(stack, expression, dictionary)[source]
    -
    -
    drop == [rest] times
    +
    drop == [rest] times
     

    Expects an integer and a quote on the stack and returns the quote with @@ -305,11 +304,6 @@ n items removed off the top.

    [c d]
    -
    -

    Stack effect:

    -
    ([...0] i1 -- [...1])
    -
    -
    @@ -382,8 +376,7 @@ the original definition in the else-part:

    joy.library.getitem(stack, expression, dictionary)[source]
    -
    -
    getitem == drop first
    +
    getitem == drop first
     

    Expects an integer and a quote on the stack and returns the item at the @@ -393,11 +386,6 @@ nth position in the quote counting from 0.

    a
    -
    -

    Stack effect:

    -
    ([...0] i1 -- a1)
    -
    -
    @@ -424,12 +412,6 @@ onto the pending expression for evaluation.

    The identity function.

    -
    -
    -joy.library.infer_(stack, expression, dictionary)[source]
    -

    Attempt to infer the stack effect of a Joy expression.

    -
    -
    joy.library.infra(stack, expression, dictionary)[source]
    @@ -457,19 +439,13 @@ with the list as its stack. Does not affect the rest of the stack.

    joy.library.inscribe_(stack, expression, dictionary)[source]
    -
    -

    Create a new Joy function definition in the Joy dictionary. A +

    Create a new Joy function definition in the Joy dictionary. A definition is given as a string with a name followed by a double equal sign then one or more Joy functions, the body. for example:

    sqr == dup mul

    If you want the definition to persist over restarts, enter it into the definitions.txt resource.

    -
    -

    Stack effect:

    -
    (t1 --)
    -
    -
    @@ -497,21 +473,13 @@ new list with the results in place of the program and original list.

    joy.library.max_(stack, expression, dictionary)[source]
    -

    Given a list find the maximum. -Stack effect:

    -
    ([n2* ...1] -- n0)
    -
    -
    +

    Given a list find the maximum.

    joy.library.min_(stack, expression, dictionary)[source]
    -

    Given a list find the minimum. -Stack effect:

    -
    ([n2* ...1] -- n0)
    -
    -
    +

    Given a list find the minimum.

    @@ -534,11 +502,7 @@ Stack effect:

    joy.library.pred(stack, expression, dictionary)[source]
    -

    Decrement TOS. -Stack effect:

    -
    (n1 -- n2)
    -
    -
    +

    Decrement TOS.

    @@ -673,30 +637,20 @@ on top of the stack.

    joy.library.succ(stack, expression, dictionary)[source]
    -

    Increment TOS. -Stack effect:

    -
    (n1 -- n2)
    -
    -
    +

    Increment TOS.

    joy.library.sum_(stack, expression, dictionary)[source]

    Given a quoted sequence of numbers return the sum.

    -
    -
    sum == 0 swap [+] step
    -

    Stack effect:

    -
    ([n2* ...1] -- n0)
    -
    -
    +

    sum == 0 swap [+] step

    joy.library.take(stack, expression, dictionary)[source]
    -
    -

    Expects an integer and a quote on the stack and returns the quote with +

    Expects an integer and a quote on the stack and returns the quote with just the top n items in reverse order (because that’s easier and you can use reverse if needed.)

             [a b c d] 2 take
    @@ -704,11 +658,6 @@ use reverse if needed.)

    [b a]
    -
    -

    Stack effect:

    -
    ([...0] i1 -- [...1])
    -
    -
    @@ -768,15 +717,6 @@ use reverse if needed.)

    -
    -
    -joy.library.yin_functions()[source]
    -

    Return a dict of named stack effects.

    -

    “Yin” functions are those that only rearrange items in stacks and -can be defined completely by their stack effects. This means they -can be auto-compiled.

    -
    -
    joy.library.zip_(stack, expression, dictionary)[source]
    diff --git a/docs/sphinx_docs/_build/html/objects.inv b/docs/sphinx_docs/_build/html/objects.inv index 9aa0a8b..694511f 100644 Binary files a/docs/sphinx_docs/_build/html/objects.inv and b/docs/sphinx_docs/_build/html/objects.inv differ diff --git a/docs/sphinx_docs/_build/html/py-modindex.html b/docs/sphinx_docs/_build/html/py-modindex.html index 1743d7c..1a4c911 100644 --- a/docs/sphinx_docs/_build/html/py-modindex.html +++ b/docs/sphinx_docs/_build/html/py-modindex.html @@ -80,11 +80,6 @@
    joy.utils.stack
    - joy.utils.types -
diff --git a/docs/sphinx_docs/_build/html/searchindex.js b/docs/sphinx_docs/_build/html/searchindex.js index 0c896a4..4c32cfc 100644 --- a/docs/sphinx_docs/_build/html/searchindex.js +++ b/docs/sphinx_docs/_build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["index","joy","lib","library","notebooks/Categorical","notebooks/Derivatives_of_Regular_Expressions","notebooks/Developing","notebooks/Generator_Programs","notebooks/Intro","notebooks/Newton-Raphson","notebooks/NoUpdates","notebooks/Ordered_Binary_Trees","notebooks/Quadratic","notebooks/Recursion_Combinators","notebooks/Replacing","notebooks/The_Four_Operations","notebooks/Treestep","notebooks/TypeChecking","notebooks/Types","notebooks/Zipper","notebooks/index","parser","pretty","stack","types"],envversion:52,filenames:["index.rst","joy.rst","lib.rst","library.rst","notebooks/Categorical.rst","notebooks/Derivatives_of_Regular_Expressions.rst","notebooks/Developing.rst","notebooks/Generator_Programs.rst","notebooks/Intro.rst","notebooks/Newton-Raphson.rst","notebooks/NoUpdates.rst","notebooks/Ordered_Binary_Trees.rst","notebooks/Quadratic.rst","notebooks/Recursion_Combinators.rst","notebooks/Replacing.rst","notebooks/The_Four_Operations.rst","notebooks/Treestep.rst","notebooks/TypeChecking.rst","notebooks/Types.rst","notebooks/Zipper.rst","notebooks/index.rst","parser.rst","pretty.rst","stack.rst","types.rst"],objects:{"joy.joy":{joy:[1,1,1,""],repl:[1,1,1,""],run:[1,1,1,""]},"joy.library":{"void":[3,1,1,""],BinaryBuiltinWrapper:[3,1,1,""],DefinitionWrapper:[3,2,1,""],FunctionWrapper:[3,1,1,""],SimpleFunctionWrapper:[3,1,1,""],UnaryBuiltinWrapper:[3,1,1,""],add_aliases:[3,1,1,""],app1:[3,1,1,""],app2:[3,1,1,""],app3:[3,1,1,""],b:[3,1,1,""],branch:[3,1,1,""],choice:[3,1,1,""],clear:[3,1,1,""],cmp_:[3,1,1,""],concat_:[3,1,1,""],cond:[3,1,1,""],dip:[3,1,1,""],dipd:[3,1,1,""],dipdd:[3,1,1,""],disenstacken:[3,1,1,""],divmod_:[3,1,1,""],drop:[3,1,1,""],dupdip:[3,1,1,""],floor:[3,1,1,""],genrec:[3,1,1,""],getitem:[3,1,1,""],help_:[3,1,1,""],i:[3,1,1,""],id_:[3,1,1,""],infer_:[3,1,1,""],infra:[3,1,1,""],initialize:[3,1,1,""],inscribe:[3,1,1,""],inscribe_:[3,1,1,""],loop:[3,1,1,""],map_:[3,1,1,""],max_:[3,1,1,""],min_:[3,1,1,""],parse:[3,1,1,""],pm:[3,1,1,""],pred:[3,1,1,""],primrec:[3,1,1,""],remove:[3,1,1,""],reverse:[3,1,1,""],select:[3,1,1,""],sharing:[3,1,1,""],shunt:[3,1,1,""],sort_:[3,1,1,""],sqrt:[3,1,1,""],step:[3,1,1,""],succ:[3,1,1,""],sum_:[3,1,1,""],take:[3,1,1,""],times:[3,1,1,""],unique:[3,1,1,""],warranty:[3,1,1,""],words:[3,1,1,""],x:[3,1,1,""],yin_functions:[3,1,1,""],zip_:[3,1,1,""]},"joy.library.DefinitionWrapper":{add_def:[3,3,1,""],add_definitions:[3,3,1,""],parse_definition:[3,3,1,""]},"joy.parser":{ParseError:[21,4,1,""],Symbol:[21,2,1,""],text_to_expression:[21,1,1,""]},"joy.utils":{generated_library:[3,0,0,"-"],pretty_print:[22,0,0,"-"],stack:[23,0,0,"-"],types:[24,0,0,"-"]},"joy.utils.generated_library":{ccons:[3,1,1,""],cons:[3,1,1,""],dup:[3,1,1,""],dupd:[3,1,1,""],dupdd:[3,1,1,""],first:[3,1,1,""],first_two:[3,1,1,""],fourth:[3,1,1,""],over:[3,1,1,""],pop:[3,1,1,""],popd:[3,1,1,""],popdd:[3,1,1,""],popop:[3,1,1,""],popopd:[3,1,1,""],popopdd:[3,1,1,""],rest:[3,1,1,""],rolldown:[3,1,1,""],rollup:[3,1,1,""],rrest:[3,1,1,""],second:[3,1,1,""],stack:[3,1,1,""],stuncons:[3,1,1,""],stununcons:[3,1,1,""],swaack:[3,1,1,""],swap:[3,1,1,""],swons:[3,1,1,""],third:[3,1,1,""],tuck:[3,1,1,""],uncons:[3,1,1,""],unit:[3,1,1,""],unswons:[3,1,1,""]},"joy.utils.pretty_print":{TracePrinter:[22,2,1,""],trace:[22,1,1,""]},"joy.utils.pretty_print.TracePrinter":{go:[22,5,1,""],viewer:[22,5,1,""]},"joy.utils.stack":{concat:[23,1,1,""],expression_to_string:[23,1,1,""],iter_stack:[23,1,1,""],list_to_stack:[23,1,1,""],pick:[23,1,1,""],stack_to_string:[23,1,1,""]},"joy.utils.types":{AnyJoyType:[24,2,1,""],BooleanJoyType:[24,2,1,""],CombinatorJoyType:[24,2,1,""],FloatJoyType:[24,2,1,""],FunctionJoyType:[24,2,1,""],IntJoyType:[24,2,1,""],JoyTypeError:[24,4,1,""],KleeneStar:[24,2,1,""],NumberJoyType:[24,2,1,""],StackJoyType:[24,2,1,""],SymbolJoyType:[24,2,1,""],TextJoyType:[24,2,1,""],compilable:[24,1,1,""],compile_:[24,1,1,""],compose:[24,1,1,""],delabel:[24,1,1,""],doc_from_stack_effect:[24,1,1,""],infer:[24,1,1,""],meta_compose:[24,1,1,""],poly_compose:[24,1,1,""],reify:[24,1,1,""],relabel:[24,1,1,""],type_check:[24,1,1,""],uni_unify:[24,1,1,""]},"joy.utils.types.BooleanJoyType":{accept:[24,6,1,""]},"joy.utils.types.FloatJoyType":{accept:[24,6,1,""]},"joy.utils.types.IntJoyType":{accept:[24,6,1,""]},"joy.utils.types.KleeneStar":{kind:[24,6,1,""]},"joy.utils.types.StackJoyType":{accept:[24,6,1,""]},"joy.utils.types.TextJoyType":{accept:[24,6,1,""]},joy:{joy:[1,0,0,"-"],library:[3,0,0,"-"],parser:[21,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","classmethod","Python class method"],"4":["py","exception","Python exception"],"5":["py","method","Python method"],"6":["py","attribute","Python attribute"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:classmethod","4":"py:exception","5":"py:method","6":"py:attribute"},terms:{"05s":5,"0b11100111011011":6,"23rd":18,"5bkei":11,"9a9d60354c35":18,"\u03b4":5,"\u03b5":9,"abstract":[8,11],"boolean":[2,3,8,11,15],"break":[5,8,18],"byte":[5,6],"case":[2,3,13,15,16,18,23],"char":5,"class":[3,5,8,18,21,22,23,24],"default":[3,7,11,23],"export":[3,21],"final":[2,11,13],"float":[3,8,18,19,21,24],"function":[0,1,4,6,7,10,12,17,19,20,21,22,23,24],"g\u00e9rard":19,"goto":5,"import":[2,5,6,7,9,11,12,13,14,16,17,18,19],"int":[5,7,8,13,18,19,21,23,24],"long":[11,18,20],"new":[2,3,5,7,8,10,13,14,18,24],"p\u00f6ial":20,"p\u00f6ial06typingtool":18,"public":10,"return":[1,3,5,6,8,11,13,14,15,16,18,21,22,23,24],"static":[2,10],"super":18,"switch":[2,18],"throw":[11,24],"true":[2,3,5,6,13,15,18,24],"try":[7,9,12,13,16,17,18,20],"void":[0,3],"while":[3,5,8,11,18,21,23],AND:[5,18],Adding:[8,14,20],And:[5,6,7,9,11,13,15,18,19,23],But:[0,4,6,7,8,11,14,18],CPS:8,For:[2,3,11,13,14,18,20,23,24],Its:3,NOT:5,Not:18,One:[2,8,15,18,20],REs:5,TOS:[2,3],That:[6,11],The:[0,1,2,3,4,5,7,9,10,12,19,20,21,22,23,24],Then:[2,3,11,12,13,18],There:[5,12,13,15,16,18,23],These:[15,18,20,23,24],Use:[3,9,13],Used:15,Using:[0,9,11,20],With:[9,13,18,20,24],_1000:18,__add__:18,__builtin__:24,__call__:5,__class__:18,__eq__:18,__ge__:18,__hash__:18,__init__:[5,18],__main__:18,__radd__:18,__repr__:18,__str__:22,_and:5,_compaction_rul:5,_con:5,_dictionari:18,_ge:18,_infer:18,_interpret:18,_log:18,_log_it:18,_names_for:18,_or:5,_templat:5,_to_str:18,_tree_add_:11,_tree_add_e:[11,24],_tree_add_p:11,_tree_add_r:11,_tree_add_t:11,_tree_delete_:11,_tree_delete_clear_stuff:[11,24],_tree_delete_del:11,_tree_delete_r0:[11,24],_tree_delete_r1:11,_tree_delete_rightmost:11,_tree_delete_w:11,_tree_get_:[11,24],_tree_get_p:11,_tree_get_r:11,_tree_get_t:11,_tree_iter_order_curr:11,_tree_iter_order_left:11,_tree_iter_order_r:11,_tree_iter_order_right:11,_tree_t:11,_treestep_0:16,_treestep_1:16,_uniqu:18,_within_b:9,_within_p:9,_within_r:9,a10001:18,a10002:18,a10003:18,a10004:18,abbrevi:16,abl:[5,15,18,24],about:[0,8,11,15,18,19,23],abov:[0,5,6,9,11,13,15,18],abs:9,absolut:8,accept:[1,2,3,5,6,7,8,11,12,14,15,16,18,19,24],accord:5,accordingli:[11,15],accumul:6,act:[5,24],action:[0,8,14,18,19,20],actual:[2,6,8,11,15,18],adapt:20,add:[3,5,6,7,8,14,18,22,24],add_alias:3,add_def:3,add_definit:[3,11,16],added:[4,11],adding:[10,18],addit:[0,2,3,6,8,13,14,16],address:20,adjust:11,advantag:18,affect:[3,15],after:[5,6,7,8,13,15,18,24],afterward:8,again:[2,3,6,8,11,13,18,24],against:[18,24],aggreg:19,ahead:18,aka:[5,8,19,24],albrecht:0,algorithm:[5,8,18],alia:[3,24],alias:[3,8],align:[8,22],all:[3,5,6,7,8,11,13,14,15,16,18,22,24],alloc:18,allow:[10,11,15],almost:11,along:[5,8,13,18,24],alphabet:[3,20],alreadi:[5,9,14,18,19],also:[0,5,6,8,11,15,18,22,23,24],alter:[5,18],altern:[4,18,24],although:[4,11],altogeth:7,alwai:[6,10,13,15],amend:15,among:18,amort:11,analysi:[4,20],anamorph:[8,20],ani:[4,5,6,8,10,11,15,18,19,21,24],annual:8,anonym:11,anoth:[5,11,15,18,23,24],anyhow:[15,18],anyjoytyp:[18,24],anymor:18,anystarjoytyp:18,anyth:[2,3,5,8,18,24],apart:18,api:10,app1:3,app2:[3,8,12,13,14,15],app3:[3,15],app:8,appear:[2,4,5,6,11,24],append:18,appendix:20,appli:[2,3,6,7,11,13,18,24],applic:7,approach:6,appropri:5,approxim:20,archiv:0,aren:19,arg:[2,3],argument:[2,3,8,9,12,13,20,22,23],arithmet:2,ariti:[2,15],around:[6,18,21,23],arrang:16,arriv:[7,16],arrow:5,articl:[0,4,7,13],ascii:5,ascii_lowercas:5,ask:[4,7,18],aspect:0,assembl:5,assert:[5,18],assign:[15,23],associ:11,assum:9,asterisk:16,asterix:[18,24],asyncron:15,attack:8,attempt:[0,1,3,18],attribut:3,attributeerror:18,author:18,auto:[0,18,24],automat:[4,15,18,24],auxiliari:[5,16],avail:[0,18,24],averag:[8,14],avoid:[11,24],awai:[11,18],awar:2,awkward:[11,13,18],azur:20,back:[3,11,18],backtrack:24,backward:[10,11,12,16],bad:18,bag:8,banana:13,bar:15,barb:13,base:[0,2,3,10,13,16,18],basestr:24,basic:[2,3,8,11],basicconfig:[17,18],becaas:5,becaus:[2,3,5,8,11,15,16,18,19,23,24],becom:[11,16,23],becuas:18,been:[5,9,10,11,18,19],befor:[5,7,8,11],begin:[11,16],behavior:[10,16,24],behaviour:[0,1,18,24],behind:15,being:[0,15,24],below:[2,3,5,6,7,11,18,19],bespok:8,best:0,better:[6,11,13,18],between:[0,6,24],beyond:7,biannual:8,bin:5,binari:[0,7,8,20],binary_search_tre:11,binarybuiltinwrapp:3,bind:8,bingo:19,bit:[5,6,7,11,18],blank:21,bliss:[0,20],block:6,bodi:[2,3,5,8,11,15],body_text:3,booktitl:18,bool:[13,18,24],booleanjoytyp:24,borrow:[8,18],both:[2,6,8,12,13,14,15,18,23],bottom:7,bounce_to:5,bracket:[8,18,21],branch:[3,5,6,7,13,18,20,24],branch_fals:18,branch_tru:18,breakpoint:8,bring:[6,8,18],bruijn:18,brutal:15,brzozowski:[18,20],brzozowskian:5,btree:[11,16],buck:11,bug:[0,8],build:[7,8,12,13,19,23],built:[12,18],bundl:[2,3,13],burgeon:8,calculu:4,call:[1,2,5,8,10,11,13,15,18,22,23],caller:[11,18],can:[0,2,3,4,5,6,7,8,9,10,12,13,14,15,16,18,19,20,21,23,24],cancel:15,cannot:[17,18,21],captur:8,card:8,care:[6,23],carefulli:19,carri:[7,11,24],cartesian:4,catamorph:20,categor:[0,20],categori:[4,15],ccc:4,ccon:[3,11,17,18,24],cell:[13,18],certain:[8,23],certainli:11,chain:[3,15],chang:[2,10,11,18,19],charact:[5,19],chat:8,chatter:[0,18],check:[0,7,9,18,20,24],child:16,choic:[3,13],choos:10,chop:12,chose:5,cinf:11,circl:5,circuit:4,cite_not:11,classmethod:3,claus:[3,18],clean:18,clear:[3,6,8],clear_stuff:11,cleav:[8,12,14],close:[0,1,4],clunki:[6,18],clv:15,cmp:[3,16,20],cmp_:3,code:[0,1,4,5,12,13,15,18,20,24],codireco:[7,9],collaps:13,collect:[4,5,7,8,18],collis:24,combin:[0,3,6,7,8,9,12,15,16,19,20,22,24],combinatorjoytyp:[18,24],come:[8,11,18],command:[8,11,18],comment:[15,24],common:[2,6,15],compar:[3,4,5,18],comparison:[0,11],compat:15,compel:4,compil:[2,3,4,5,8,11,14,15,20,24],compile_:24,complement:5,complet:[3,4],complex:[3,15,18,19,24],complic:18,compos:[5,24],composit:[18,24],compostit:18,compound:11,comput:[2,4,5,6,8,12,15,18,24],con:[3,5,6,7,8,9,11,12,13,15,16,19,23,24],conal:[4,15],concat:[3,7,8,15,16,18,23],concat_:3,concaten:[0,5],concatin:[0,3,5,23],concern:15,conclus:20,concurr:2,cond:[3,11],condit:[3,8],confer:18,conflict:[11,18,24],consecut:20,consid:[5,6,7,11,13,16,18,19],consist:[2,7,8,15,16],constant:11,constitu:13,construct:[15,18],consum:[15,18],contain:[0,2,3,5,7,8,13,18,21],content:18,context:2,conting:11,continu:[0,5,13,18,19],control:8,conveni:[4,15,18],convent:15,convers:18,convert:[13,14,16,18,21,23],cool:11,copi:[2,3,6,11,13,15,16,17,20],copyright:8,correspond:[4,15],could:[2,4,5,6,8,10,11,15,18,19],couldn:15,count:[3,18],counter:[6,18],coupl:16,cours:[6,11,18],cover:18,cpu:15,crack:11,crash:11,creat:[0,2,3,6,9,11,15,18],creativ:18,crude:[11,18,21,24],cruft:18,curent:24,current:[2,3,8,13,15,16,18,19,22,24],curri:5,custom:10,cycl:[6,7],cython:8,d010101:5,d0101:5,d01:5,d10:5,d_compact:5,dai:8,data:[2,3,5,13],datastructur:[0,2,13,18,20,21,23],datatyp:23,ddididi:19,deal:[0,5,11,15],dealt:18,debugg:18,decid:11,declar:18,decor:3,decoupl:13,decrement:3,deduc:[6,18],deeper:0,deepli:4,def:[3,5,8,13,14,18,23],defaultdict:[5,18],defi:3,defin:[2,3,4,5,6,7,8,9,10,12,13,14,15,18,19,20],definit:[0,2,3,6,7,8,10,11,13,16,18,20,24],definitionwrapp:[3,11,13,16],defint:15,del:17,delabel:24,deleg:8,delet:20,deliber:18,demo:18,demonstr:4,depend:[3,11,13,15],deposit:16,depth:[18,24],dequot:13,der:11,deriv:[2,3,6,8,9,11,18,20],derv:5,describ:[3,4,5,11,13,15,16,18,21,24],descript:[6,8],descriptor:18,design:[2,3,11,15,20],desir:[8,16],destin:5,destruct:11,detail:[8,11,18],detect:[5,7,11,13,18],determin:20,develop:[0,7,8,18,20],diagram:6,dialect:1,dict:[1,3,5,18,22,24],dictionari:[0,1,3,8,18,20,22],did:18,differ:[0,4,6,9,11,12,13,15,23],differenti:4,difficult:18,difficulti:15,dig:[11,19],digit:6,digraph:5,dinfrirst:[8,18,24],dip:[3,6,7,8,9,11,12,13,14,15,16,18,20,24],dipd:[3,7,8,11,12,13,15,18,19,24],dipdd:[3,11],direco:20,direct:8,directli:[6,15,16,18,23],disappear:[2,5,18,24],discard:[3,7,9,11,13],disciplin:11,disctionari:1,disenstacken:[3,8],disk:8,displac:2,displai:18,distiguish:18,distribut:15,ditch:11,div:[3,8,18,24],dive:16,divis:[11,18],divmod:[3,24],divmod_:[3,18],doc:[2,3,8,18,24],doc_from_stack_effect:[17,24],docstr:18,document:[18,20,21,23],doe:[0,1,3,4,5,7,8,14,15,18,20,22,24],doesn:[6,10,11,15,16,18,23],doing:[4,6,8,15,18,19],domain:[4,18],don:[5,6,8,11,18,24],done:[2,6,8,10,18],dooooc:18,door:8,dot:[5,22],doubl:[3,5,6,8,18],doublecircl:5,down:[2,5,9,13,19,24],down_to_zero:8,dozen:8,draft:[4,10],dream:8,drive:[7,9],driven:6,driver:[5,7],drop:[3,11],dudipd:8,due:18,dup:[3,6,7,8,9,11,12,13,15,17,19,23,24],dupd:[3,18,24],dupdd:[3,24],dupdip:[3,6,11,12,13],duplic:[3,11,13],durat:2,dure:[2,13],each:[2,3,4,5,6,8,13,14,15,16,18,22,24],easi:[0,11,16,18,19],easier:[3,11,15],easili:4,eat:5,edit:20,effect:[2,3,5,8,15,19,20,24],effici:[7,14,19],efg:18,either:[1,2,3,5,11,13,18],elabor:18,eleg:[0,5,8,11,15,20],element:[2,3],elif:18,elimin:[5,18],elliott:[4,15],els:[2,3,5,13,15,18],else_:18,embed:[4,11,19],emit:18,empti:[3,5,8,16,18,23,24],encapsul:8,enclos:8,encod:7,encount:18,end:[5,6,11,13,16,18,23],endless:7,enforc:[2,8],engend:8,enough:[5,8,13,22,24],enstacken:[7,8,18],enter:[3,8,24],enter_guard:18,entir:23,entri:[3,19,22],enumer:18,epsilon:9,equal:[3,6,16,23],equat:[8,9],equival:15,ergo:[5,11],err:[11,17],error:[8,18,21],essai:0,establish:18,etc:[3,16,18,19,21],euler:20,euro:18,eval:[0,18],evalu:[1,2,3,8,9,11,12,13,14,15,16,18,22],event:15,eventu:[15,18],ever:18,everi:[1,7,15],everybodi:15,everyth:[3,5,11,12,15,18],evolv:10,examin:13,exampl:[0,3,5,6,18,20,21,23,24],exce:7,except:[5,8,11,17,18,21,24],execut:[0,1,2,3,8,13,14,15,16,18,19,23,24],exend:18,exercis:[5,11],exist:[4,11,18],expand:11,expect:[2,3,15,16,18,23,24],experi:[8,16],explain:18,explan:8,explor:[8,18],express:[0,1,2,3,4,11,13,14,18,19,20,22,23],expression_to_str:[18,23],extend:18,extra:[6,7],extract:[11,12,20],extrem:8,extrememli:8,f_g:18,f_in:18,f_out:18,f_python:18,facet:0,facil:8,fact:21,factor:[2,6,8,11,18],factori:[3,20],fail:[2,3,11,20,21,24],fail_fail:3,fairli:18,fake:5,fall:18,fals:[2,3,5,6,13,15,18,24],falsei:18,far:[9,11,13,18,24],fascin:0,favorit:15,fear:[11,18],few:[6,8,9,12,15,18],fewer:[3,8],fg_in:18,fg_out:18,fib:7,fib_gen:7,fibonacci:20,figur:[2,3,11,13,18],filter:11,fin:6,find:[2,3,5,6,7,15,16,18,20],finder:9,fine:[0,5,6,11,18,24],finite_state_machin:5,first:[3,5,7,8,9,11,12,13,14,16,19,20,24],first_two:[3,11,24],fit:[6,8],five:[6,8,20],fix:[2,3,5,13,18,24],fixm:[5,18],flag:[15,18],flatten:[8,16,18],flesh:5,flexibl:20,floatjoytyp:[18,24],floatstarjoytyp:18,floor:3,floordiv:[6,24],flow:8,follow:[0,2,3,5,8,10,13,15,16,18,19,24],foo:[8,10,11,15,18],foo_ii:10,fork:15,form:[2,3,4,5,6,7,13,16,18,23],forman:8,format:[17,18,20,22],formula:[0,6,20],forth:[8,18],forum:0,forward:18,found:8,four:[0,2,3,6,7,8,11,20],fourteen:6,fourth:[2,3,11,13,24],fractal:8,fraction0:8,fraction:[2,8],frame:13,framework:8,free:[4,8,11],freeli:2,from:[0,1,2,3,5,6,7,8,9,11,12,14,15,16,17,18,19,20,23],from_:5,front:[2,3,13],frozenset:5,fulin:15,full:6,fun:[5,20],func:18,functionjoytyp:[18,24],functionwrapp:3,functool:5,fundament:[0,20],funtion:11,further:[9,18,20],futur:15,g_in:18,g_out:18,garbag:8,gari:11,gcd:8,gener:[0,2,4,15,18,20,23,24],generated_librari:3,genrec:[3,8,11,13,15,16,18],geometr:6,get:[2,4,5,6,7,8,12,13,18,20],getch:5,getitem:3,getrecursionlimit:23,getsourc:8,ghc:4,give:[4,6,11,13,16,18,23],given:[2,3,6,7,9,11,15,18,19,20],global:[17,18],glue:8,goe:24,going:[5,11,12,15,16,18,19],good:[6,11,18],grab:18,grammar:21,grand:8,graph:15,graphic:5,graphviz:5,great:[0,8,18,20],greater:23,grind:18,group:0,grow:5,gsra:9,guard:[11,18,24],had:[5,6,19],haiku:8,half:[6,18,19],hallmark:15,hand:[5,8,14,18,20],handi:[9,18],handl:[11,18,23,24],happen:[8,18],happi:5,hard:[5,18,19],hardwar:4,has:[0,2,3,5,7,8,9,10,11,13,15,18,19,23],hasattr:18,hash:18,haskel:4,have:[2,3,5,6,7,8,9,10,13,14,15,18,19,20,23,24],haven:24,head:23,heh:18,help:[8,11,13,18],help_:3,helper:[3,5],herd:8,here:[5,6,7,11,16,18,19,24],hide:11,hierarchi:18,higher:[5,8,11,18],highli:8,hij:5,histori:[18,22,24],hit:5,hmm:[5,11],hoist:3,hold:[6,18],hood:11,hope:[0,6,8,20],hopefulli:13,host:20,how:[0,4,5,9,11,13,18,19,20],howev:[13,14,15,18],html:[2,3,7,12,13,20],http:11,huet:19,huge:11,hugh:[9,16],human:8,hybrid:24,hylomorph:20,hypothet:2,id_:3,idea:[4,6,8,18],ident:[3,5,13,18,24],if_not_empti:11,ift:[3,11,13,16,18,24],ignor:[1,3,11,18],iii:20,illustr:[5,13],imagin:[5,15,19],imap:18,imit:[5,16],immedi:[5,13],immut:[5,8,11],imper:13,implement:[0,1,2,3,4,8,10,11,13,14,15,20,24],implementaion:15,implicit:8,improv:18,includ:[4,11,15,16,18,24],inclus:6,incom:23,incompat:10,incorpor:12,increas:6,increment:[3,4,6,10,15],indetermin:24,index:[0,8,18,23],indexerror:23,indic:[15,16,18,24],ineffici:18,infer:[0,3,17],infer_:3,inferenc:24,info:[17,18],inform:[3,5,18,24],infra:[3,7,8,11,12,14,15,16,18,20,24],infrastructur:3,initi:[2,3,5,8,9,11,18],inlin:11,inner:18,inproceed:18,input:[1,9,15,17,18,24],input_:5,inscrib:3,inscribe_:3,insert:18,insight:13,inspect:8,inspect_stack:18,instal:0,instanc:18,instanti:[4,22],instead:[5,6,7,11,13,18,19,23,24],instruct:5,integ:[2,3,8,16,18,21],integr:3,intend:[0,8],interact:[8,20],interest:[0,6,11,18,20],interfer:15,interlud:20,intermedi:13,intern:[0,18,22,23],interpret:[0,4,10,14,21,22,24],interrupt:8,intersect:5,interspers:15,interv:[4,6],intjoytyp:[18,24],introduc:10,introduct:0,intstarjoytyp:18,intuit:18,invalid:24,invari:3,invent:18,involv:18,ipf:8,ipython:18,isinst:[5,18],isn:[5,11,19],issubclass:18,item:[2,3,8,11,13,15,16,18,20,23],iter:[1,3,5,8,13,15,16,18,20,23],iter_stack:[14,23],iteritem:[5,18],itertool:[5,18],its:[0,1,2,3,4,6,8,11,13,15,16,18,23],itself:[0,2,8,11,15,18,24],j05cmp:[2,3,13],jaanu:18,jmp:5,job:[15,20],john:[9,16],joi:[2,4,10,11,12,14,15,17],join:[5,18],joypi:19,joytypeerror:[17,24],jump:5,jump_from:5,junk:18,jupyt:20,just:[0,2,3,5,7,8,10,11,13,15,16,18,19,22],juxtaposit:15,keep:[5,11,12,15,18,19],kei:[5,16,20],kevin:0,key_n:11,keyerror:[5,11,18],kind:[2,4,8,11,13,16,18,24],kinda:18,kleen:[16,18,24],kleenestar:[18,24],kleffner:18,know:[6,11,18],knowledg:18,known:[4,15],kstar:5,l_kei:11,l_left:11,l_right:11,l_valu:11,label:[5,18],lambda:[4,5,18],languag:[3,4,5,8,10,11,14,18],larg:[5,18],larger:[20,23],largest:3,last:[6,11,13,18],lastli:7,later:[5,8,16,18],law:2,lazi:18,lazili:9,lcm:6,lead:[5,8,18,24],leaf:11,lean:8,learn:0,least:[2,6,13,18,23],least_fract:8,leav:[3,6,15],left:[5,8,12,13,15,16,18,19,22,23,24],leftov:13,legend:5,len:[5,18],length:[3,6,23],lens:13,less:[6,7,8,13,18,23],let:[7,9,11,12,13,16,18,19,20],letter:18,level:[4,5,11,17,18],librari:[0,5,14],like:[2,3,5,6,8,15,16,18,20,21,22,24],limit:[18,24],line:[3,8,11,12,18,22,24],linear:23,link:[0,5,18],linux:0,list:[0,3,5,6,8,9,11,15,16,18,19,22,24],list_to_stack:[18,23],liter:[1,11,16,18,19,21],literatur:18,littl:[5,7,11,15,18,20],live:20,lkei:16,load:[6,8],local:18,locat:2,locu:22,log:[17,18],log_2:11,logic:[0,6,20],longer:[11,18],look:[1,5,7,8,9,11,12,15,18],lookup:8,loop:[0,1,3,5,6,18,20,24],lose:18,lot:[5,8,11,18,19],love:6,low:[4,5],lower:6,lowercas:[5,18],lowest:11,lshift:24,machin:[0,20],machineri:[11,18],macro:8,made:[0,8,15,18,19],magic:18,mai:[2,13,15],mail:0,main:[0,3,8,12,15,18,19],mainloop:10,maintain:19,major:10,make:[2,3,4,6,8,11,13,14,15,16,18,19,20],make_gener:9,make_graph:5,manfr:[0,2,3,4,13],mani:[0,5,8,18],manipul:18,manner:12,map:[1,3,5,6,8,10,13,16,18,22],map_:3,marker:8,mask:[6,7],match:[0,1,18,20],materi:0,math:[0,8,9,11,12,18],mathemat:8,matter:[6,9,11,16],max_:3,maximum:3,mayb:[11,18],mean:[3,4,6,8,9,11,13,16,18,23,24],meant:[8,11,13,16],mem:5,member:[2,3,13],memo:5,mental:8,mention:2,mercuri:0,mess:18,messag:[17,18],meta:[8,11,14],meta_compos:[18,24],method:[0,3,8,18,20,22],midpoint:6,might:[4,5,7,11,18],mike:11,million:7,min_:3,mind:18,minimum:3,minor:11,minu:3,mirror:0,miscellan:0,mismatch:18,mix:[8,18],mod:3,mode:18,model:[4,8],modern:0,modif:[7,18],modifi:[8,11,19],modul:[0,1,3,8,18,21],modulo:18,modulu:[8,24],moment:18,month:8,more:[0,3,4,5,6,7,8,9,13,14,15,16,18,21,23,24],most:[5,18,24],mostli:0,move:[5,11],movement:2,much:[5,6,7,11,13,18],muck:11,mul:[3,8,12,17,19,22,24],multi:3,multipl:[20,24],multipli:3,must:[2,3,6,10,13,15,16,18,21],myself:18,n10001:18,n10002:18,n10003:18,n1001:18,n1002:18,n1003:18,name:[1,3,5,8,10,11,13,18,19,20,21,22,23,24],narr:18,natur:[5,6,7,11,18],navig:19,nearli:18,neat:11,neato:18,necessarili:18,need:[2,3,6,7,9,10,11,13,15,18],neg:[3,12,24],neither:[15,18],ness:5,nest:[3,8,11,19],network:8,never:[5,10,13],new_def:18,new_f:18,new_fo:18,new_kei:11,new_valu:11,newton:[0,20],next:[5,6,15,16,18,24],nice:[0,5,13,23],niether:2,node:[5,16,20],node_kei:11,node_valu:11,non:[5,16,18,24],none:[1,3,18,24],nope:16,nor:5,normal:15,notat:[8,11],note:[2,5,6,9,11,13,15,18,23],notebook:[6,7,8,18,19,20],notebook_preambl:[2,6,7,9,11,12,13,14,16,18,19],noth:[2,11,15],notic:6,now:[3,5,6,7,8,13,14,16,18,20],nth:[3,23],nullari:[8,11,15,18,24],number:[1,2,3,6,7,9,15,23,24],numberjoytyp:[18,24],numberstarjoytyp:18,numer:18,object:[5,18,21],observ:6,obviou:7,obvious:18,occur:11,odd:[6,7],off:[2,3,6,7,12,18,19],often:[5,15],old:[2,14],old_k:11,old_kei:11,old_valu:11,omg:5,omit:[13,18,21],onc:[3,5,10,11],one:[2,3,5,6,7,11,13,15,16,18,22,23,24],ones:[5,7,18],onli:[2,3,5,6,11,13,15,18,19,23,24],onto:[1,2,3,8,13,23],open:[8,18],oper:[0,3,5,8,11,13,20,23],oppos:18,optim:11,option:[1,8,11,18,23],orchestr:15,order:[0,2,3,8,13,15,17,18,20,23],org:[0,11],origin:[0,1,2,3,11,19],other:[0,2,3,4,5,8,11,13,16,18,23,24],otherwis:[3,5,6,7,11,16,18,24],our:[5,6,7,8,9,13,16,18],out:[2,3,4,6,7,8,9,11,12,13,15,18,19,20],outcom:16,outlin:5,output:[5,9,13,15,17,18,24],outsid:4,over:[3,4,6,7,8,9,11,12,15,16,18,20,24],overhaul:18,overview:[3,18],own:[11,18],pack:23,packag:[0,8],page:[0,11,18,23],pair:[2,3,6,7,11,18],palidrom:6,palindrom:6,pam:8,paper:[4,8,13,15,19],paradigm:20,parallel:[2,20],paramet:[1,2,3,13,14,21,22,23],parameter:20,paramorph:13,parenthes:[11,23],pariti:7,pars:[0,3,5,8],parse_definit:3,parseerror:21,parser:[0,17,18],part:[2,3,9,13,16,20],partial:[5,18],particular:19,pass:[0,5,11,18,22,24],patch:5,path:[5,18,20],pattern:[5,6,15,16,20],pe1:[6,7],pe2:7,pearl:19,pend:[3,8,13,18,19,22],peopl:20,per:[8,16],perfectli:15,perform:[5,15,18],perhap:7,period:8,permit:[15,18,23],permut:18,persist:[3,11],phase:2,phi:5,pick:[6,7,15,23],pickl:8,pictur:11,piec:13,pip:0,place:[3,6,8,18],plai:0,plu:3,plug:[7,13,16],point:[4,5,8,11,13,15],pointless:2,poly_compos:24,pool:15,pop:[3,5,6,7,8,11,13,14,16,17,23,24],popd:[3,8,9,11,14,15,18,24],popdd:[3,7,12,18,24],popop:[3,6,7,8,9,11,16,18,24],popopd:[3,24],popopdd:[3,24],posit:[3,6,8,13],possibilit:11,possibl:[11,16,18,20],post:8,poswrd:18,potenti:15,pow:24,power:[8,18],pprint:5,pragmat:6,preambl:9,preceed:15,precis:[0,1],pred:[3,18,24],predecessor:3,predic:[2,3,5,7,13,15,24],prefix:[18,22],preliminari:5,present:18,preserv:[4,16],pretti:[9,11,12,15,16,18,22,23],pretty_print:0,previou:[8,15],prime:9,primit:[2,3,18,20],primrec:[3,7,8,9,13],print:[0,1,2,3,5,17,18,22,23,24],probabl:[7,8,11,18],problem:[8,18,20],proc_curr:11,proc_left:11,proc_right:11,proce:[6,24],process:[5,8,16,18,22],produc:[3,6,11,13,16,18],product:[5,7,8,17,18],program:[0,2,3,7,8,9,11,13,15,18,19,24],programm:[15,18],progress:15,project:20,prolog:18,promis:15,prompt:8,proper:[2,3,13,15,24],properti:0,provid:[0,3,4,8,15,18,24],pun:[0,8],punctuat:18,pure:[0,5],puriti:8,purpos:8,push:[2,3,8,13,19,23],put:[1,2,7,8,15,18,20,23],pypi:0,python3:8,python:[0,2,3,5,11,13,15,19,20,21,23,24],quadrat:[0,20],queri:[11,16],query_kei:16,queu:13,quit:[0,16],quot:[0,3,7,8,11,12,13,15,16,18,19,22,24],quotat:[2,3,13],quotient:3,r_kei:11,r_left:11,r_right:11,r_valu:11,rais:[5,11,18,21,23],rang:[5,8,18],range_revers:13,range_to_zero:8,ranger:13,ranger_revers:13,rankdir:5,raphson:9,rather:[6,8,13,16],ratio:8,reach:[5,6,7,13],read:[0,1,6,7,11,18,19],readabl:14,reader:[5,11],readi:18,real:11,realiz:[4,11],rearrang:[2,3,11,18],reason:[6,8,15,18],rebuild:[16,19],rec1:[2,3,13],rec2:[2,3,13],recent:18,recogn:21,recombin:15,record:[8,22],recur:[3,13,18],recurs:[0,2,3,5,7,8,9,15,18,20,23],recus:8,redefin:20,redistribut:[3,8],redo:5,reduc:[2,18],redund:23,refactor:[8,10],refer:[0,2],referenti:15,reflect:15,regard:15,regist:2,regular:[18,20,21],reifi:[17,24],reimplement:[15,20],relabel:24,relat:[5,18],releas:10,remain:[2,8,10,18],remaind:[3,9],rememb:5,remind:18,remov:[3,11,18,23],render:20,repeat:6,repeatedli:6,repetit:5,repl:[0,1],replac:[0,2,3,7,12,13,15,16,18,19,20,23],repositori:0,repr:[5,18],repres:[2,8,11,15,21,22,24],represent:[23,24],reprod:7,repurpos:18,requir:[15,18,23],res:18,research:18,resembl:8,resolut:15,resourc:[3,15],respect:[5,6,15],rest:[3,6,7,8,11,13,19,20,23,24],rest_two:11,restart:3,restor:2,result:[1,2,3,5,6,11,12,13,15,16,18,19],resum:8,retir:2,retri:8,reus:[11,18],revers:[3,6,7,13,18,19,20,23],revisit:18,rewrit:[3,8,18],rewritten:8,rid:11,right:[7,8,12,16,18,20,22,23,24],rightest:11,rightmost:6,rigor:15,risk:18,rkei:16,rob:18,roll:[3,9,11,16],roll_dn:18,rolldown:[3,17,18,24],rollup:[3,18,24],root:[3,9,12],round:18,row:5,rrest:[3,17,18,24],rshift:24,rule:[15,20],run:[0,1,3,6,8,9,11,12,13,15,16,18,19],runtim:15,runtimeerror:23,sai:[5,7,11,12,16,18],same:[2,4,6,11,15,18,23],sandwich:[2,3,13],save:[2,5,6,8],scan:3,scanner:[8,21],scenario:19,scope:[7,11],search:[0,11],sec:[18,24],second:[3,8,11,13,16,23,24],section:13,see:[0,5,7,8,9,10,12,13,14,18,19,22],seem:[0,6,8,16,18,24],seen:[18,19,24],select:3,self:[5,15,18],semant:[2,3,8,10,11,15,18],semi:8,send:8,sens:[0,2,6,18,19],separ:[8,15,18,21],seq:18,sequenc:[0,1,2,3,6,8,11,13,14,19,20,21,24],sequence_to_stack:18,seri:[6,7,11,19],ses:18,set:[2,3,5,13,18,20],seven:[6,7],sever:[0,4,8,13],shape:[5,15],share:[3,8],shelf:2,shew:5,shift:[6,7],shorter:20,shorthand:11,should:[2,3,5,6,11,13,15,18],shouldn:8,show:[4,15,18,19],shunt:[3,19],side:[5,11,17,18,24],sign:3,signatur:24,signifi:[8,11],similar:[11,16,18],simon:8,simpl:[5,8,13,23,24],simplefunctionwrapp:[3,14,18],simpler:16,simplest:[18,20],simpli:4,simplifi:[6,11,19],sinc:[2,6,11,18],singl:[3,7,8,14,15,18,21,24],singleton:5,situ:11,situat:11,six:[6,7,8],sixti:[6,7],size:[5,8,20],skeptic:8,skip:18,slight:9,slightli:[11,13,18],smallest:3,smart:11,softwar:8,solei:2,solut:[6,7],solvabl:8,some:[2,3,5,7,8,11,13,15,16,18,20,23,24],somehow:[11,18],someth:[2,10,11,18],sometim:11,somewher:[11,20],sort:[3,5,11,15,18],sort_:3,sourc:[0,1,3,18,20,21,22,23,24],space:[6,22],span:6,spawn:18,special:[7,11,20],specif:[0,4],specifi:[11,15,24],speed:14,spell:[5,16],sphinx:[20,23],spirit:[0,1,16],split:[5,18,24],sqr:[3,8,9,12,19],sqrt:[3,9,18,24],squar:[3,9,18,21],stack:[0,1,3,6,7,9,11,12,13,14,15,16,17,19,20,21,22,24],stack_effect:18,stack_effect_com:18,stack_to_str:[17,23],stacki:18,stackjoytyp:[18,24],stackstarjoytyp:18,stage:16,stai:[0,1],stand:[4,5],standard:[8,11],star:[16,18,24],stare:11,start:[5,6,7,8,9,11,13,16,18,24],state:[8,20],state_nam:5,statement:[3,5],stdout:[17,18],step:[3,6,8,11,14,18,19,20],still:[5,11,18],stop:11,stopiter:5,storag:[6,11],store:[6,13,18],stori:13,str:[1,5,18,21,22,23],straightforward:[5,7,9,18,20],stream:[6,17,18],stretch:11,string:[1,2,3,8,18,19,20,21,22,23,24],stringi:5,structur:[8,15,16,18,19,20,23],stuck:5,studi:5,stuff:[11,18],stuncon:[3,24],stununcon:[3,24],style:[0,4,18],sub:[10,15,24],subclass:8,subject:[15,19],subsequ:15,subset:[18,24],substitut:[5,11,18,24],subtract:6,subtyp:20,succ:[3,18,24],succe:18,success:9,suck:18,suffic:18,suffici:11,suffix:18,suggest:[4,5,11],suitabl:[3,4,6],sum:[3,7,8,12,13,14,16],sum_:[3,18],summand:6,sumtre:16,suppli:[11,21],support:[8,18,22,23],sure:15,suspect:2,svg:5,swaack:[3,12,14,18,19,24],swap:[3,6,7,8,9,11,13,14,15,16,17,19,24],swon:[3,7,8,13,16,18,19,24],swoncat:[7,8,9,13,16],swuncon:13,sym:5,symbol:[1,2,3,5,15,18,19,20,21],symboljoytyp:[18,24],symmetr:[6,11],symmetri:5,syntact:8,syntax:[8,23],sys:[17,18,23],system:[8,11,15],tabl:[5,18],tag:[5,18],tail:[11,18,20,23],tailrec:3,take:[3,5,6,8,9,11,13,15,18,23],talk:[8,11,18,23],target:19,tast:4,tbd:8,tear:13,technic:2,techniqu:[4,19],technolog:2,temporari:19,ten:6,term:[1,2,5,8,9,13,15,18,20,21,23,24],termin:[2,3,5,13],ternari:8,test:[2,3,13],text:[0,1,3,18],text_to_express:[8,17,21],textjoytyp:24,textual:8,than:[0,3,5,6,7,8,9,13,15,16,18,23,24],thei:[2,3,5,6,7,8,11,13,15,18,19,21,23,24],them:[2,3,5,6,7,11,13,15,18,19,20,24],themselv:[15,18,24],theori:[2,3,13,15],therefor:7,thi:[0,1,2,3,4,5,6,7,8,9,12,13,15,16,18,19,20,21,22,23,24],thing:[2,7,11,13,15,18,19,21,23,24],think:[2,6,8,11,13,15,16,18],third:[3,7,8,11,24],thirti:6,those:[2,3,5,11,13,18,20,24],though:[6,15],thought:[8,15],thousand:6,thread:[2,15],three:[2,3,5,6,8,11,12,16,18,20],through:[1,6,8,16,18,19,23,24],thun:[2,3,4,10,13,15],thunder:8,thunk:15,time:[3,5,6,8,9,11,13,15,18,19],titl:18,to_check:5,to_set:11,todai:8,todo:[8,21],togeth:[7,8,15,18,20],token:21,toler:20,too:[5,13,18],tool:[8,18],tooo:18,top:[2,3,8,13,18,22,23],total:6,tower:18,trace:[0,8,12,13,19,20,23],traceback:18,traceprint:22,track:[12,18,19],tracker:0,transform:4,transit:5,translat:[4,12,18],trap:5,travers:[0,20],treasur:0,treat:[0,2,3,13,18,20],treatment:7,tree:[0,8,20],treegrind:20,treestep:[0,20],tri:6,triangl:15,triangular_numb:13,trick:[6,18],tricki:18,trinari:24,trobe:0,trove:0,truediv:24,truthi:[3,8,15,18],tuck:[3,8,18,24],tupl:[3,5,8,18,23,24],turn:[2,3,5,18,24],twice:[11,13],two:[2,3,6,8,9,11,12,13,15,16,17,18,19,20,23,24],txt:3,type:[0,1,4,8,11,13,15,20,21,22,23],type_check:24,typeerror:18,typeless:18,typic:[2,3,12,13],unari:8,unarybuiltinwrapp:3,unbalanc:[11,21],unbound:24,unchang:11,uncompil:18,uncon:[3,7,8,11,13,16,19,24],under:[2,3,8,11],underli:[5,15,18],underscor:18,understand:[0,11],undistinguish:11,undocu:8,unfinish:5,unfortun:23,uni_unifi:24,unicod:18,unif:[18,20],unifi:[17,24],union:5,uniqu:[3,5,11,18],unit:[3,8,13,15,24],univers:[0,8,15,18,24],unlik:15,unnecessari:20,unnecesssari:18,unpack:[2,3,11,23],unpair:6,unquot:[8,16,21],unrol:5,unstack:18,unswon:[3,24],untangl:13,until:[5,7,15],unus:6,unusu:11,unwrap:5,updat:[0,17,20,24],uppercas:5,upward:15,usag:8,use:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,16,19,20,23],used:[3,4,8,11,13,15,18,19,21,23,24],useful:[0,15,18],user:16,uses:[2,3,5,6,13],using:[7,11,12,13,16,19,24],usual:[0,2,13],util:[0,3,14,17,18],valid:18,valu:[0,1,2,3,6,8,9,12,13,14,15,16,18,20,21,23,24],value_n:11,valueerror:[5,18,23],variabl:[18,20,24],variant:11,variat:[13,15,20],varieti:[4,8],variou:0,vener:23,verbos:4,veri:[0,1,4,5,8,11,23],versa:[2,18],version:[0,1,2,5,7,10,16,19,20],via:8,vice:[2,18],view:[11,20],viewer:[1,8,10,22],vii:20,visibl:18,von:[0,2,3,4,13],waaaai:5,wai:[0,2,3,4,5,6,8,13,14,15,18],wait:15,want:[2,3,6,7,9,11,13,18],warranti:[3,8],wash:8,wast:8,web:23,websit:[0,6],welcom:8,well:[0,4,8,9,11,18,21],went:18,were:[8,18,19],what:[2,3,4,5,8,11,13,15,16,18,22],whatev:[2,3,13,16,23],when:[6,7,8,11,13,15,18,19,21,23,24],where:[2,3,5,8,11,13,18,20,23],whether:[3,13],which:[0,1,3,5,6,8,9,11,15,16,18,19,21,23,24],whole:[2,3,6,13,16,18],whose:7,why:[9,15,16],wiki:11,wikipedia:[0,11,19],wildli:8,wind:8,wire:13,within:[8,11,14,20],without:[2,8,11,12,15,18],won:[11,18,23],word:[0,3,6,8,13,19],work:[0,3,5,6,7,8,9,11,12,13,15,16,19,20,23,24],worker:15,worri:15,worth:6,would:[2,6,7,8,9,11,13,15,18,19,23,24],wrap:[3,8],wrapper:18,write:[4,5,9,11,13,15,16,18,19,20,23],written:[0,1,9,11,14,18,23],wrong:2,wrote:18,xrang:18,yang:18,yeah:15,year:[8,18],yet:[11,15,18,19,24],yield:[2,3,13,18,23,24],yin:[3,20],yin_funct:3,you:[0,2,3,5,6,7,8,10,11,12,13,14,15,16,18,19,22,23],your:[2,3,8,13,18],yourself:[5,8,11],zero:[3,5,11,13,15,16,18,21,23,24],zerodivisionerror:18,zip:[5,6,18],zip_:3,zipper:[0,20],zstr:19},titles:["Thun 0.4.0 Documentation","Joy Interpreter","Functions Grouped by, er, Function with Examples","Function Reference","Categorical Programming","\u2202RE","Developing a Program in Joy","Using x to Generate Values","Thun: Joy in Python","Newton\u2019s method","No Updates","Treating Trees I: Ordered Binary Trees","Quadratic formula","Recursion Combinators","Replacing Functions in the Dictionary","The Four Fundamental Operations of Definite Action","Treating Trees II: treestep","Type Checking","The Blissful Elegance of Typing Joy","Traversing Datastructures with Zippers","Essays about Programming in Joy","Parsing Text into Joy Expressions","Tracing Joy Execution","Stack or Quote or Sequence or List\u2026","Type Inference of Joy Expressions"],titleterms:{"\u03bb":5,"\u03d5":5,"case":[9,11],"function":[2,3,5,8,9,11,13,14,15,16,18],"long":14,"new":11,"p\u00f6ial":18,"try":5,"void":2,"while":[2,15],Adding:11,One:[7,11],The:[6,8,11,13,15,16,18],There:8,Using:7,With:[5,16],about:20,action:15,add:[2,11],adding:11,address:19,alphabet:5,altern:16,ana:13,analysi:6,anamorph:[2,13],app1:2,app2:2,app3:2,appendix:[11,13,18],appli:15,approxim:9,argument:18,auto:3,averag:2,base:[9,11],binari:[2,11,16],bliss:18,both:11,branch:[2,11,15],brzozowski:5,can:11,cata:13,catamorph:13,categor:4,chatter:2,check:17,child:11,choic:2,clear:2,cleav:[2,15],cmp:11,code:[8,11],combin:[2,11,13,18],comment:18,compact:5,compar:11,comparison:2,compil:[7,18],compile_:18,compos:18,comput:9,con:[2,18],concat:2,conclus:[13,18],consecut:9,continu:8,current:11,datastructur:[5,8,11,19],deal:18,defin:[11,16],definit:[12,15],delabel:18,delet:11,deriv:[5,12,13,16],design:13,determin:19,develop:6,diagram:5,dialect:0,dictionari:14,dip:[2,19],dipd:2,dipdd:2,direco:7,disenstacken:2,distinguish:18,div:2,doc_from_stack_effect:18,document:0,doe:11,down_to_zero:2,drive:5,drop:2,dup:[2,18],dupd:2,dupdip:2,effect:18,eleg:18,els:11,empti:11,enstacken:2,equal:11,essai:20,euler:[6,7],eval:8,even:7,exampl:[2,8,11,13,16,17],execut:22,explor:5,express:[5,8,21,24],extract:16,factori:13,fail:17,fibonacci:7,filter:6,find:[9,11,13],finish:15,finit:5,first:[2,6,15,18],five:7,flatten:2,flexibl:16,floordiv:2,formula:12,found:11,four:[13,15],from:13,fsm:5,fulmin:15,fun:13,fundament:15,further:6,gcd:2,gener:[3,5,6,7,9,13],genrec:2,get:[11,16],getitem:2,given:[13,16],greater:11,group:2,handl:15,have:[11,16],help:2,highest:11,host:0,how:[6,7],hybrid:18,hylo:13,hylomorph:13,identifi:18,ift:[2,15],iii:18,implement:[5,18],indic:0,infer:[18,24],inferenc:18,inform:0,infra:[2,19],integ:[6,13],interest:7,interlud:11,intern:21,interpret:[1,8,18],item:19,iter:[6,11],joi:[0,1,3,6,8,13,18,19,20,21,22,23,24],join:15,just:6,kei:11,kind:15,languag:0,larger:5,least_fract:2,left:11,less:11,let:[5,6],letter:5,librari:[3,8,18],like:11,list:[2,13,23],literari:8,littl:6,logic:[2,18],loop:[2,8,15],lower:11,lshift:2,machin:5,make:[7,9],mani:6,map:[2,15],match:5,math:2,memoiz:5,method:9,min:2,miscellan:2,mod:2,modifi:18,modulu:2,more:11,most:11,mul:[2,18],multipl:[6,7,18],must:11,name:12,neg:2,newton:9,next:9,node:11,non:11,now:11,nullari:2,nulli:5,number:[13,18],one:8,onli:8,oper:15,order:[11,16],osdn:0,other:15,our:11,out:5,over:2,pack:6,pam:[2,15],para:13,paradigm:18,parallel:15,parameter:[11,16],pars:[2,21],parser:[8,21],part:18,pass:8,path:19,pattern:13,per:11,pop:[2,18],popd:2,popop:2,pow:2,power:7,pred:2,predic:[6,9,11,16],pretty_print:22,primit:13,primrec:2,print:8,problem:[6,7],process:11,product:2,program:[4,6,12,16,20],progress:18,project:[0,6,7],pure:8,put:[11,12,16],python:[8,14,18],quadrat:12,quick:0,quot:[2,23],rang:[2,6,13],range_to_zero:2,read:8,recur:[9,11],recurs:[11,13,16],redefin:[11,16],refactor:[6,11],refer:3,regular:[5,8],reimplement:16,relabel:18,rem:2,remaind:2,remov:2,render:6,repl:8,replac:[11,14],repres:[5,18],represent:5,reset:7,rest:[2,18],revers:[2,5,17],right:[11,19],rightmost:11,roll:[2,18],rolldown:2,rollup:2,rshift:2,rule:[5,18],run:[2,7],second:[2,18],select:2,sequenc:[7,15,18,23],set:[9,11],shorter:14,should:8,shunt:2,simpl:18,simplest:6,size:[2,14],sourc:11,special:[13,18],sqr:[2,18],sqrt:[2,12],stack:[2,8,18,23],start:0,state:5,step:[2,13,16],straightforward:12,stream:5,string:5,structur:11,style:8,sub:[2,11],subtyp:18,succ:2,sum:[2,6],swaack:2,swap:[2,18],swon:2,swoncat:2,symbol:[8,13],tabl:0,tail:13,take:2,term:[6,7,16],ternari:2,text:21,than:11,them:12,thi:11,third:[2,18],three:7,thun:[0,8],time:[2,7],togeth:[11,12,16],token:8,toler:9,trace:[14,22],traceprint:8,trampolin:5,travers:[11,16,19],treat:[11,16],tree:[11,16,19],treegrind:16,treestep:16,triangular:13,truediv:2,truthi:2,tuck:2,two:[5,7],type:[17,18,24],unari:2,unbound:18,uncon:[2,18],unif:17,unifi:18,unit:2,unnecessari:6,unquot:2,unstack:2,updat:[10,18],use:18,util:[22,23,24],valu:[7,11],variabl:12,variat:7,version:[6,11,14,18],view:8,vii:18,which:13,within:9,word:2,work:[17,18],write:12,xor:2,yin:18,zero:7,zip:2,zipper:19}}) \ No newline at end of file +Search.setIndex({docnames:["index","joy","lib","library","notebooks/Categorical","notebooks/Derivatives_of_Regular_Expressions","notebooks/Developing","notebooks/Generator_Programs","notebooks/Intro","notebooks/Newton-Raphson","notebooks/NoUpdates","notebooks/Ordered_Binary_Trees","notebooks/Quadratic","notebooks/Recursion_Combinators","notebooks/Replacing","notebooks/The_Four_Operations","notebooks/Treestep","notebooks/TypeChecking","notebooks/Types","notebooks/Zipper","notebooks/index","parser","pretty","stack","types"],envversion:52,filenames:["index.rst","joy.rst","lib.rst","library.rst","notebooks/Categorical.rst","notebooks/Derivatives_of_Regular_Expressions.rst","notebooks/Developing.rst","notebooks/Generator_Programs.rst","notebooks/Intro.rst","notebooks/Newton-Raphson.rst","notebooks/NoUpdates.rst","notebooks/Ordered_Binary_Trees.rst","notebooks/Quadratic.rst","notebooks/Recursion_Combinators.rst","notebooks/Replacing.rst","notebooks/The_Four_Operations.rst","notebooks/Treestep.rst","notebooks/TypeChecking.rst","notebooks/Types.rst","notebooks/Zipper.rst","notebooks/index.rst","parser.rst","pretty.rst","stack.rst","types.rst"],objects:{"joy.joy":{joy:[1,1,1,""],repl:[1,1,1,""],run:[1,1,1,""]},"joy.library":{"void":[3,1,1,""],BinaryBuiltinWrapper:[3,1,1,""],DefinitionWrapper:[3,2,1,""],FunctionWrapper:[3,1,1,""],SimpleFunctionWrapper:[3,1,1,""],UnaryBuiltinWrapper:[3,1,1,""],add_aliases:[3,1,1,""],app1:[3,1,1,""],app2:[3,1,1,""],app3:[3,1,1,""],b:[3,1,1,""],branch:[3,1,1,""],choice:[3,1,1,""],clear:[3,1,1,""],cmp_:[3,1,1,""],concat_:[3,1,1,""],cond:[3,1,1,""],dip:[3,1,1,""],dipd:[3,1,1,""],dipdd:[3,1,1,""],disenstacken:[3,1,1,""],divmod_:[3,1,1,""],drop:[3,1,1,""],dupdip:[3,1,1,""],floor:[3,1,1,""],genrec:[3,1,1,""],getitem:[3,1,1,""],help_:[3,1,1,""],i:[3,1,1,""],id_:[3,1,1,""],infra:[3,1,1,""],initialize:[3,1,1,""],inscribe:[3,1,1,""],inscribe_:[3,1,1,""],loop:[3,1,1,""],map_:[3,1,1,""],max_:[3,1,1,""],min_:[3,1,1,""],parse:[3,1,1,""],pm:[3,1,1,""],pred:[3,1,1,""],primrec:[3,1,1,""],remove:[3,1,1,""],reverse:[3,1,1,""],select:[3,1,1,""],sharing:[3,1,1,""],shunt:[3,1,1,""],sort_:[3,1,1,""],sqrt:[3,1,1,""],step:[3,1,1,""],succ:[3,1,1,""],sum_:[3,1,1,""],take:[3,1,1,""],times:[3,1,1,""],unique:[3,1,1,""],warranty:[3,1,1,""],words:[3,1,1,""],x:[3,1,1,""],zip_:[3,1,1,""]},"joy.library.DefinitionWrapper":{add_def:[3,3,1,""],add_definitions:[3,3,1,""],parse_definition:[3,3,1,""]},"joy.parser":{ParseError:[21,4,1,""],Symbol:[21,2,1,""],text_to_expression:[21,1,1,""]},"joy.utils":{generated_library:[3,0,0,"-"],pretty_print:[22,0,0,"-"],stack:[23,0,0,"-"]},"joy.utils.generated_library":{ccons:[3,1,1,""],cons:[3,1,1,""],dup:[3,1,1,""],dupd:[3,1,1,""],dupdd:[3,1,1,""],first:[3,1,1,""],first_two:[3,1,1,""],fourth:[3,1,1,""],over:[3,1,1,""],pop:[3,1,1,""],popd:[3,1,1,""],popdd:[3,1,1,""],popop:[3,1,1,""],popopd:[3,1,1,""],popopdd:[3,1,1,""],rest:[3,1,1,""],rolldown:[3,1,1,""],rollup:[3,1,1,""],rrest:[3,1,1,""],second:[3,1,1,""],stack:[3,1,1,""],stuncons:[3,1,1,""],stununcons:[3,1,1,""],swaack:[3,1,1,""],swap:[3,1,1,""],swons:[3,1,1,""],third:[3,1,1,""],tuck:[3,1,1,""],uncons:[3,1,1,""],unit:[3,1,1,""],unswons:[3,1,1,""]},"joy.utils.pretty_print":{TracePrinter:[22,2,1,""],trace:[22,1,1,""]},"joy.utils.pretty_print.TracePrinter":{go:[22,5,1,""],viewer:[22,5,1,""]},"joy.utils.stack":{concat:[23,1,1,""],expression_to_string:[23,1,1,""],iter_stack:[23,1,1,""],list_to_stack:[23,1,1,""],pick:[23,1,1,""],stack_to_string:[23,1,1,""]},joy:{joy:[1,0,0,"-"],library:[3,0,0,"-"],parser:[21,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","classmethod","Python class method"],"4":["py","exception","Python exception"],"5":["py","method","Python method"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:classmethod","4":"py:exception","5":"py:method"},terms:{"05s":5,"0b11100111011011":6,"23rd":18,"5bkei":11,"9a9d60354c35":18,"\u03b4":5,"\u03b5":9,"abstract":[8,11],"boolean":[2,3,8,11,15],"break":[5,8,18],"byte":[5,6],"case":[2,3,13,15,16,18,23],"char":5,"class":[3,5,8,18,21,22,23],"default":[3,7,11,23],"export":[3,21],"final":[2,11,13],"float":[3,8,18,19,21],"function":[0,1,4,6,7,10,12,17,19,20,21,22,23,24],"g\u00e9rard":19,"goto":5,"import":[2,5,6,7,9,11,12,13,14,16,17,18,19],"int":[5,7,8,13,18,19,21,23],"long":[11,18,20],"new":[2,3,5,7,8,10,13,14,18],"p\u00f6ial":20,"p\u00f6ial06typingtool":18,"public":10,"return":[1,3,5,6,8,11,13,14,15,16,18,21,22,23],"static":[2,10],"super":18,"switch":[2,18],"throw":[11,24],"true":[2,3,5,6,13,15,18],"try":[7,9,12,13,16,17,18,20],"void":[0,3],"while":[3,5,8,11,18,21,23],AND:[5,18],Adding:[8,14,20],And:[5,6,7,9,11,13,15,18,19,23],But:[0,4,6,7,8,11,14,18],CPS:8,For:[2,3,11,13,14,18,20,23],Its:3,NOT:5,Not:18,One:[2,8,15,18,20],REs:5,TOS:[2,3],That:[6,11],The:[0,1,2,3,4,5,7,9,10,12,19,20,21,22,23,24],Then:[2,3,11,12,13,18],There:[5,12,13,15,16,18,23],These:[15,18,20,23],Use:[3,9,13],Used:15,Using:[0,9,11,20],With:[9,13,18,20,24],_1000:18,__add__:18,__builtin__:[],__call__:5,__class__:18,__eq__:18,__ge__:18,__hash__:18,__init__:[5,18],__main__:18,__radd__:18,__repr__:18,__str__:22,_and:5,_compaction_rul:5,_con:5,_dictionari:18,_ge:18,_infer:18,_interpret:18,_log:18,_log_it:18,_names_for:18,_or:5,_templat:5,_to_str:18,_tree_add_:11,_tree_add_e:[11,24],_tree_add_p:11,_tree_add_r:11,_tree_add_t:11,_tree_delete_:11,_tree_delete_clear_stuff:[11,24],_tree_delete_del:11,_tree_delete_r0:[11,24],_tree_delete_r1:11,_tree_delete_rightmost:11,_tree_delete_w:11,_tree_get_:[11,24],_tree_get_p:11,_tree_get_r:11,_tree_get_t:11,_tree_iter_order_curr:11,_tree_iter_order_left:11,_tree_iter_order_r:11,_tree_iter_order_right:11,_tree_t:11,_treestep_0:16,_treestep_1:16,_uniqu:18,_within_b:9,_within_p:9,_within_r:9,a10001:18,a10002:18,a10003:18,a10004:18,abbrevi:16,abl:[5,15,18,24],about:[0,8,11,15,18,19,23],abov:[0,5,6,9,11,13,15,18],abs:9,absolut:8,accept:[1,2,3,5,6,7,8,11,12,14,15,16,18,19],accord:5,accordingli:[11,15],accumul:6,act:[5,24],action:[0,8,14,18,19,20],actual:[2,6,8,11,15,18],adapt:20,add:[3,5,6,7,8,14,18,22,24],add_alias:3,add_def:3,add_definit:[3,11,16],added:[4,11],adding:[10,18],addit:[0,2,3,6,8,13,14,16],address:20,adjust:11,advantag:18,affect:[3,15],after:[5,6,7,8,13,15,18,24],afterward:8,again:[2,3,6,8,11,13,18],against:18,aggreg:19,ahead:18,aka:[5,8,19,24],albrecht:0,algorithm:[5,8,18],alia:3,alias:[3,8],align:[8,22],all:[3,5,6,7,8,11,13,14,15,16,18,22],alloc:18,allow:[10,11,15],almost:11,along:[5,8,13,18],alphabet:[3,20],alreadi:[5,9,14,18,19],also:[0,5,6,8,11,15,18,22,23],alter:[5,18],altern:[4,18],although:[4,11],altogeth:7,alwai:[6,10,13,15],amend:15,among:18,amort:11,analysi:[4,20],anamorph:[8,20],ani:[4,5,6,8,10,11,15,18,19,21],annual:8,anonym:11,anoth:[5,11,15,18,23,24],anyhow:[15,18],anyjoytyp:18,anymor:18,anystarjoytyp:18,anyth:[2,3,5,8,18,24],apart:18,api:10,app1:3,app2:[3,8,12,13,14,15],app3:[3,15],app:8,appear:[2,4,5,6,11],append:18,appendix:20,appli:[2,3,6,7,11,13,18],applic:7,approach:6,appropri:5,approxim:20,archiv:0,aren:19,arg:[2,3],argument:[2,3,8,9,12,13,20,22,23],arithmet:2,ariti:[2,15],around:[6,18,21,23],arrang:16,arriv:[7,16],arrow:5,articl:[0,4,7,13],ascii:5,ascii_lowercas:5,ask:[4,7,18],aspect:0,assembl:5,assert:[5,18],assign:[15,23],associ:11,assum:9,asterisk:16,asterix:[18,24],asyncron:15,attack:8,attempt:[0,1,18],attribut:3,attributeerror:18,author:18,auto:[0,18,24],automat:[4,15,18],auxiliari:[5,16],avail:[0,18,24],averag:[8,14],avoid:11,awai:[11,18],awar:2,awkward:[11,13,18],azur:20,back:[3,11,18],backtrack:24,backward:[10,11,12,16],bad:18,bag:8,banana:13,bar:15,barb:13,base:[0,2,3,10,13,16,18],basestr:[],basic:[2,3,8,11],basicconfig:[17,18],becaas:5,becaus:[2,3,5,8,11,15,16,18,19,23],becom:[11,16,23],becuas:18,been:[5,9,10,11,18,19],befor:[5,7,8,11],begin:[11,16],behavior:[10,16,24],behaviour:[0,1,18],behind:15,being:[0,15],below:[2,3,5,6,7,11,18,19],bespok:8,best:0,better:[6,11,13,18],between:[0,6],beyond:7,biannual:8,bin:5,binari:[0,7,8,20],binary_search_tre:11,binarybuiltinwrapp:3,bind:8,bingo:19,bit:[5,6,7,11,18],blank:21,bliss:[0,20],block:6,bodi:[2,3,5,8,11,15],body_text:3,booktitl:18,bool:[13,18,24],booleanjoytyp:[],borrow:[8,18],both:[2,6,8,12,13,14,15,18,23],bottom:7,bounce_to:5,bracket:[8,18,21],branch:[3,5,6,7,13,18,20,24],branch_fals:18,branch_tru:18,breakpoint:8,bring:[6,8,18],bruijn:18,brutal:15,brzozowski:[18,20],brzozowskian:5,btree:[11,16],buck:11,bug:[0,8],build:[7,8,12,13,19,23],built:[12,18],bundl:[2,3,13],burgeon:8,calculu:4,call:[1,2,5,8,10,11,13,15,18,22,23],caller:[11,18],can:[0,2,3,4,5,6,7,8,9,10,12,13,14,15,16,18,19,20,21,23,24],cancel:15,cannot:[17,18,21],captur:8,card:8,care:[6,23],carefulli:19,carri:[7,11],cartesian:4,catamorph:20,categor:[0,20],categori:[4,15],ccc:4,ccon:[3,11,17,18,24],cell:[13,18],certain:[8,23],certainli:11,chain:[3,15],chang:[2,10,11,18,19],charact:[5,19],chat:8,chatter:[0,18],check:[0,7,9,18,20],child:16,choic:[3,13],choos:10,chop:12,chose:5,cinf:11,circl:5,circuit:4,cite_not:11,classmethod:3,claus:[3,18],clean:18,clear:[3,6,8],clear_stuff:11,cleav:[8,12,14],close:[0,1,4],clunki:[6,18],clv:15,cmp:[3,16,20],cmp_:3,code:[0,1,4,5,12,13,15,18,20,24],codireco:[7,9],collaps:13,collect:[4,5,7,8,18],collis:[],combin:[0,3,6,7,8,9,12,15,16,19,20,22,24],combinatorjoytyp:18,come:[8,11,18],command:[8,11,18],comment:15,common:[2,6,15],compar:[3,4,5,18],comparison:[0,11],compat:15,compel:4,compil:[2,4,5,8,11,14,15,20,24],compile_:[],complement:5,complet:4,complex:[3,15,18,19,24],complic:18,compos:[5,24],composit:18,compostit:18,compound:11,comput:[2,4,5,6,8,12,15,18,24],con:[3,5,6,7,8,9,11,12,13,15,16,19,23,24],conal:[4,15],concat:[3,7,8,15,16,18,23],concat_:3,concaten:[0,5],concatin:[0,3,5,23],concern:15,conclus:20,concurr:2,cond:[3,11],condit:[3,8],confer:18,conflict:[11,18],consecut:20,consid:[5,6,7,11,13,16,18,19],consist:[2,7,8,15,16],constant:11,constitu:13,construct:[15,18],consum:[15,18],contain:[0,2,3,5,7,8,13,18,21],content:18,context:2,conting:11,continu:[0,5,13,18,19],control:8,conveni:[4,15,18],convent:15,convers:18,convert:[13,14,16,18,21,23],cool:11,copi:[2,3,6,11,13,15,16,17,20],copyright:8,correspond:[4,15],could:[2,4,5,6,8,10,11,15,18,19],couldn:15,count:[3,18],counter:[6,18],coupl:16,cours:[6,11,18],cover:18,cpu:15,crack:11,crash:11,creat:[0,2,3,6,9,11,15,18],creativ:18,crude:[11,18,21],cruft:18,curent:24,current:[2,3,8,13,15,16,18,19,22,24],curri:5,custom:10,cycl:[6,7],cython:8,d010101:5,d0101:5,d01:5,d10:5,d_compact:5,dai:8,data:[2,3,5,13],datastructur:[0,2,13,18,20,21,23],datatyp:23,ddididi:19,deal:[0,5,11,15],dealt:18,debugg:18,decid:11,declar:18,decor:3,decoupl:13,decrement:3,deduc:[6,18],deeper:0,deepli:4,def:[3,5,8,13,14,18,23],defaultdict:[5,18],defi:3,defin:[2,3,4,5,6,7,8,9,10,12,13,14,15,18,19,20],definit:[0,2,3,6,7,8,10,11,13,16,18,20,24],definitionwrapp:[3,11,13,16],defint:15,del:17,delabel:[],deleg:8,delet:20,deliber:18,demo:18,demonstr:4,depend:[3,11,13,15],deposit:16,depth:[18,24],dequot:13,der:11,deriv:[2,3,6,8,9,11,18,20],derv:5,describ:[3,4,5,11,13,15,16,18,21],descript:[6,8],descriptor:18,design:[2,3,11,15,20],desir:[8,16],destin:5,destruct:11,detail:[8,11,18],detect:[5,7,11,13,18],determin:20,develop:[0,7,8,18,20],diagram:6,dialect:1,dict:[1,3,5,18,22],dictionari:[0,1,3,8,18,20,22],did:18,differ:[0,4,6,9,11,12,13,15,23],differenti:4,difficult:18,difficulti:15,dig:[11,19],digit:6,digraph:5,dinfrirst:[8,18,24],dip:[3,6,7,8,9,11,12,13,14,15,16,18,20,24],dipd:[3,7,8,11,12,13,15,18,19,24],dipdd:[3,11],direco:20,direct:8,directli:[6,15,16,18,23],disappear:[2,5,18],discard:[3,7,9,11,13],disciplin:11,disctionari:1,disenstacken:[3,8],disk:8,displac:2,displai:18,distiguish:18,distribut:15,ditch:11,div:[3,8,18,24],dive:16,divis:[11,18],divmod:[3,24],divmod_:[3,18],doc:[2,3,8,18],doc_from_stack_effect:17,docstr:18,document:[18,20,21,23],doe:[0,1,3,4,5,7,8,14,15,18,20,22,24],doesn:[6,10,11,15,16,18,23],doing:[4,6,8,15,18,19],domain:[4,18],don:[5,6,8,11,18],done:[2,6,8,10,18],dooooc:18,door:8,dot:[5,22],doubl:[3,5,6,8,18],doublecircl:5,down:[2,5,9,13,19,24],down_to_zero:8,dozen:8,draft:[4,10],dream:8,drive:[7,9],driven:6,driver:[5,7],drop:[3,11],dudipd:8,due:18,dup:[3,6,7,8,9,11,12,13,15,17,19,23,24],dupd:[3,18,24],dupdd:[3,24],dupdip:[3,6,11,12,13],duplic:[3,11,13],durat:2,dure:[2,13],each:[2,3,4,5,6,8,13,14,15,16,18,22,24],easi:[0,11,16,18,19],easier:[3,11,15],easili:4,eat:5,edit:20,effect:[2,3,5,8,15,19,20,24],effici:[7,14,19],efg:18,either:[1,2,3,5,11,13,18],elabor:18,eleg:[0,5,8,11,15,20],element:[2,3],elif:18,elimin:[5,18],elliott:[4,15],els:[2,3,5,13,15,18],else_:18,embed:[4,11,19],emit:18,empti:[3,5,8,16,18,23,24],encapsul:8,enclos:8,encod:7,encount:18,end:[5,6,11,13,16,18,23],endless:7,enforc:[2,8],engend:8,enough:[5,8,13,22,24],enstacken:[7,8,18],enter:[3,8],enter_guard:18,entir:23,entri:[3,19,22],enumer:18,epsilon:9,equal:[3,6,16,23],equat:[8,9],equival:15,ergo:[5,11],err:[11,17],error:[8,18,21],essai:0,establish:18,etc:[3,16,18,19,21],euler:20,euro:18,eval:[0,18],evalu:[1,2,3,8,9,11,12,13,14,15,16,18,22],event:15,eventu:[15,18],ever:18,everi:[1,7,15],everybodi:15,everyth:[3,5,11,12,15,18],evolv:10,examin:13,exampl:[0,3,5,6,18,20,21,23,24],exce:7,except:[5,8,11,17,18,21],execut:[0,1,2,3,8,13,14,15,16,18,19,23,24],exend:18,exercis:[5,11],exist:[4,11,18],expand:11,expect:[2,3,15,16,18,23],experi:[8,16],explain:18,explan:8,explor:[8,18],express:[0,1,2,3,4,11,13,14,18,19,20,22,23],expression_to_str:[18,23],extend:18,extra:[6,7],extract:[11,12,20],extrem:8,extrememli:8,f_g:18,f_in:18,f_out:18,f_python:18,facet:0,facil:8,fact:21,factor:[2,6,8,11,18],factori:[3,20],fail:[2,3,11,20,21],fail_fail:3,fairli:18,fake:5,fall:18,fals:[2,3,5,6,13,15,18],falsei:18,far:[9,11,13,18,24],fascin:0,favorit:15,fear:[11,18],few:[6,8,9,12,15,18],fewer:[3,8],fg_in:18,fg_out:18,fib:7,fib_gen:7,fibonacci:20,figur:[2,3,11,13,18],filter:11,fin:6,find:[2,3,5,6,7,15,16,18,20],finder:9,fine:[0,5,6,11,18,24],finite_state_machin:5,first:[3,5,7,8,9,11,12,13,14,16,19,20,24],first_two:[3,11,24],fit:[6,8],five:[6,8,20],fix:[2,3,5,13,18],fixm:[5,18],flag:[15,18],flatten:[8,16,18],flesh:5,flexibl:20,floatjoytyp:18,floatstarjoytyp:18,floor:3,floordiv:[6,24],flow:8,follow:[0,2,3,5,8,10,13,15,16,18,19],foo:[8,10,11,15,18],foo_ii:10,fork:15,form:[2,3,4,5,6,7,13,16,18,23],forman:8,format:[17,18,20,22],formula:[0,6,20],forth:[8,18],forum:0,forward:18,found:8,four:[0,2,3,6,7,8,11,20],fourteen:6,fourth:[2,3,11,13,24],fractal:8,fraction0:8,fraction:[2,8],frame:13,framework:8,free:[4,8,11],freeli:2,from:[0,1,2,3,5,6,7,8,9,11,12,14,15,16,17,18,19,20,23],from_:5,front:[2,3,13],frozenset:5,fulin:15,full:6,fun:[5,20],func:18,functionjoytyp:18,functionwrapp:3,functool:5,fundament:[0,20],funtion:11,further:[9,18,20],futur:15,g_in:18,g_out:18,garbag:8,gari:11,gcd:8,gener:[0,2,4,15,18,20,23,24],generated_librari:3,genrec:[3,8,11,13,15,16,18],geometr:6,get:[2,4,5,6,7,8,12,13,18,20],getch:5,getitem:3,getrecursionlimit:23,getsourc:8,ghc:4,give:[4,6,11,13,16,18,23],given:[2,3,6,7,9,11,15,18,19,20],global:[17,18],glue:8,goe:24,going:[5,11,12,15,16,18,19],good:[6,11,18],grab:18,grammar:21,grand:8,graph:15,graphic:5,graphviz:5,great:[0,8,18,20],greater:23,grind:18,group:0,grow:5,gsra:9,guard:[11,18],had:[5,6,19],haiku:8,half:[6,18,19],hallmark:15,hand:[5,8,14,18,20],handi:[9,18],handl:[11,18,23,24],happen:[8,18],happi:5,hard:[5,18,19],hardwar:4,has:[0,2,3,5,7,8,9,10,11,13,15,18,19,23],hasattr:18,hash:18,haskel:4,have:[2,3,5,6,7,8,9,10,13,14,15,18,19,20,23,24],haven:[],head:23,heh:18,help:[8,11,13,18],help_:3,helper:[3,5],herd:8,here:[5,6,7,11,16,18,19,24],hide:11,hierarchi:18,higher:[5,8,11,18],highli:8,hij:5,histori:[18,22],hit:5,hmm:[5,11],hoist:3,hold:[6,18],hood:11,hope:[0,6,8,20],hopefulli:13,host:20,how:[0,4,5,9,11,13,18,19,20],howev:[13,14,15,18],html:[2,3,7,12,13,20],http:11,huet:19,huge:11,hugh:[9,16],human:8,hybrid:24,hylomorph:20,hypothet:2,id_:3,idea:[4,6,8,18],ident:[3,5,13,18,24],if_not_empti:11,ift:[3,11,13,16,18,24],ignor:[1,3,11,18],iii:20,illustr:[5,13],imagin:[5,15,19],imap:18,imit:[5,16],immedi:[5,13],immut:[5,8,11],imper:13,implement:[0,1,2,3,4,8,10,11,13,14,15,20,24],implementaion:15,implicit:8,improv:18,includ:[4,11,15,16,18,24],inclus:6,incom:23,incompat:10,incorpor:12,increas:6,increment:[3,4,6,10,15],indetermin:[],index:[0,8,18,23],indexerror:23,indic:[15,16,18,24],ineffici:18,infer:[0,17],infer_:[],inferenc:24,info:[17,18],inform:[3,5,18,24],infra:[3,7,8,11,12,14,15,16,18,20,24],infrastructur:3,initi:[2,3,5,8,9,11,18],inlin:11,inner:18,inproceed:18,input:[1,9,15,17,18],input_:5,inscrib:3,inscribe_:3,insert:18,insight:13,inspect:8,inspect_stack:18,instal:0,instanc:18,instanti:[4,22],instead:[5,6,7,11,13,18,19,23,24],instruct:5,integ:[2,3,8,16,18,21],integr:3,intend:[0,8],interact:[8,20],interest:[0,6,11,18,20],interfer:15,interlud:20,intermedi:13,intern:[0,18,22,23],interpret:[0,4,10,14,21,22,24],interrupt:8,intersect:5,interspers:15,interv:[4,6],intjoytyp:18,introduc:10,introduct:0,intstarjoytyp:18,intuit:18,invalid:[],invari:3,invent:18,involv:18,ipf:8,ipython:18,isinst:[5,18],isn:[5,11,19],issubclass:18,item:[2,3,8,11,13,15,16,18,20,23],iter:[1,3,5,8,13,15,16,18,20,23],iter_stack:[14,23],iteritem:[5,18],itertool:[5,18],its:[0,1,2,3,4,6,8,11,13,15,16,18,23],itself:[0,2,8,11,15,18],j05cmp:[2,3,13],jaanu:18,jmp:5,job:[15,20],john:[9,16],joi:[2,4,10,11,12,14,15,17],join:[5,18],joypi:19,joytypeerror:17,jump:5,jump_from:5,junk:18,jupyt:20,just:[0,2,3,5,7,8,10,11,13,15,16,18,19,22],juxtaposit:15,keep:[5,11,12,15,18,19],kei:[5,16,20],kevin:0,key_n:11,keyerror:[5,11,18],kind:[2,4,8,11,13,16,18,24],kinda:18,kleen:[16,18],kleenestar:18,kleffner:18,know:[6,11,18],knowledg:18,known:[4,15],kstar:5,l_kei:11,l_left:11,l_right:11,l_valu:11,label:[5,18],lambda:[4,5,18],languag:[3,4,5,8,10,11,14,18],larg:[5,18],larger:[20,23],largest:3,last:[6,11,13,18],lastli:7,later:[5,8,16,18],law:2,lazi:18,lazili:9,lcm:6,lead:[5,8,18],leaf:11,lean:8,learn:0,least:[2,6,13,18,23],least_fract:8,leav:[3,6,15],left:[5,8,12,13,15,16,18,19,22,23],leftov:13,legend:5,len:[5,18],length:[3,6,23],lens:13,less:[6,7,8,13,18,23],let:[7,9,11,12,13,16,18,19,20],letter:18,level:[4,5,11,17,18],librari:[0,5,14],like:[2,3,5,6,8,15,16,18,20,21,22,24],limit:[18,24],line:[3,8,11,12,18,22,24],linear:23,link:[0,5,18],linux:0,list:[0,3,5,6,8,9,11,15,16,18,19,22],list_to_stack:[18,23],liter:[1,11,16,18,19,21],literatur:18,littl:[5,7,11,15,18,20],live:20,lkei:16,load:[6,8],local:18,locat:2,locu:22,log:[17,18],log_2:11,logic:[0,6,20],longer:[11,18],look:[1,5,7,8,9,11,12,15,18],lookup:8,loop:[0,1,3,5,6,18,20,24],lose:18,lot:[5,8,11,18,19],love:6,low:[4,5],lower:6,lowercas:[5,18],lowest:11,lshift:24,machin:[0,20],machineri:[11,18],macro:8,made:[0,8,15,18,19],magic:18,mai:[2,13,15],mail:0,main:[0,3,8,12,15,18,19],mainloop:10,maintain:19,major:10,make:[2,3,4,6,8,11,13,14,15,16,18,19,20],make_gener:9,make_graph:5,manfr:[0,2,3,4,13],mani:[0,5,8,18],manipul:18,manner:12,map:[1,3,5,6,8,10,13,16,18,22],map_:3,marker:8,mask:[6,7],match:[0,1,18,20],materi:0,math:[0,8,9,11,12,18],mathemat:8,matter:[6,9,11,16],max_:3,maximum:3,mayb:[11,18],mean:[4,6,8,9,11,13,16,18,23],meant:[8,11,13,16],mem:5,member:[2,3,13],memo:5,mental:8,mention:2,mercuri:0,mess:18,messag:[17,18],meta:[8,11,14],meta_compos:18,method:[0,3,8,18,20,22],midpoint:6,might:[4,5,7,11,18],mike:11,million:7,min_:3,mind:18,minimum:3,minor:11,minu:3,mirror:0,miscellan:0,mismatch:18,mix:[8,18],mod:3,mode:18,model:[4,8],modern:0,modif:[7,18],modifi:[8,11,19],modul:[0,1,3,8,18,21],modulo:18,modulu:[8,24],moment:18,month:8,more:[0,3,4,5,6,7,8,9,13,14,15,16,18,21,23,24],most:[5,18,24],mostli:0,move:[5,11],movement:2,much:[5,6,7,11,13,18],muck:11,mul:[3,8,12,17,19,22,24],multi:3,multipl:[20,24],multipli:3,must:[2,3,6,10,13,15,16,18,21],myself:18,n10001:18,n10002:18,n10003:18,n1001:18,n1002:18,n1003:18,name:[1,3,5,8,10,11,13,18,19,20,21,22,23,24],narr:18,natur:[5,6,7,11,18],navig:19,nearli:18,neat:11,neato:18,necessarili:18,need:[2,3,6,7,9,10,11,13,15,18],neg:[3,12,24],neither:[15,18],ness:5,nest:[3,8,11,19],network:8,never:[5,10,13],new_def:18,new_f:18,new_fo:18,new_kei:11,new_valu:11,newton:[0,20],next:[5,6,15,16,18,24],nice:[0,5,13,23],niether:2,node:[5,16,20],node_kei:11,node_valu:11,non:[5,16,18],none:[1,3,18],nope:16,nor:5,normal:15,notat:[8,11],note:[2,5,6,9,11,13,15,18,23],notebook:[6,7,8,18,19,20],notebook_preambl:[2,6,7,9,11,12,13,14,16,18,19],noth:[2,11,15],notic:6,now:[3,5,6,7,8,13,14,16,18,20],nth:[3,23],nullari:[8,11,15,18,24],number:[1,2,3,6,7,9,15,23,24],numberjoytyp:18,numberstarjoytyp:18,numer:18,object:[5,18,21],observ:6,obviou:7,obvious:18,occur:11,odd:[6,7],off:[2,3,6,7,12,18,19],often:[5,15],old:[2,14],old_k:11,old_kei:11,old_valu:11,omg:5,omit:[13,18,21],onc:[3,5,10,11],one:[2,3,5,6,7,11,13,15,16,18,22,23,24],ones:[5,7,18],onli:[2,3,5,6,11,13,15,18,19,23],onto:[1,2,3,8,13,23],open:[8,18],oper:[0,3,5,8,11,13,20,23],oppos:18,optim:11,option:[1,8,11,18,23],orchestr:15,order:[0,2,3,8,13,15,17,18,20,23],org:[0,11],origin:[0,1,2,3,11,19],other:[0,2,3,4,5,8,11,13,16,18,23],otherwis:[3,5,6,7,11,16,18],our:[5,6,7,8,9,13,16,18],out:[2,3,4,6,7,8,9,11,12,13,15,18,19,20],outcom:16,outlin:5,output:[5,9,13,15,17,18,24],outsid:4,over:[3,4,6,7,8,9,11,12,15,16,18,20,24],overhaul:18,overview:[3,18],own:[11,18],pack:23,packag:[0,8],page:[0,11,18,23],pair:[2,3,6,7,11,18],palidrom:6,palindrom:6,pam:8,paper:[4,8,13,15,19],paradigm:20,parallel:[2,20],paramet:[1,2,3,13,14,21,22,23],parameter:20,paramorph:13,parenthes:[11,23],pariti:7,pars:[0,3,5,8],parse_definit:3,parseerror:21,parser:[0,17,18],part:[2,3,9,13,16,20],partial:[5,18],particular:19,pass:[0,5,11,18,22],patch:5,path:[5,18,20],pattern:[5,6,15,16,20],pe1:[6,7],pe2:7,pearl:19,pend:[3,8,13,18,19,22],peopl:20,per:[8,16],perfectli:15,perform:[5,15,18],perhap:7,period:8,permit:[15,18,23],permut:18,persist:[3,11],phase:2,phi:5,pick:[6,7,15,23],pickl:8,pictur:11,piec:13,pip:0,place:[3,6,8,18],plai:0,plu:3,plug:[7,13,16],point:[4,5,8,11,13,15],pointless:2,poly_compos:[],pool:15,pop:[3,5,6,7,8,11,13,14,16,17,23,24],popd:[3,8,9,11,14,15,18,24],popdd:[3,7,12,18,24],popop:[3,6,7,8,9,11,16,18,24],popopd:[3,24],popopdd:[3,24],posit:[3,6,8,13],possibilit:11,possibl:[11,16,18,20],post:8,poswrd:18,potenti:15,pow:24,power:[8,18],pprint:5,pragmat:6,preambl:9,preceed:15,precis:[0,1],pred:[3,18,24],predecessor:3,predic:[2,3,5,7,13,15],prefix:[18,22],preliminari:5,present:18,preserv:[4,16],pretti:[9,11,12,15,16,18,22,23],pretty_print:0,previou:[8,15],prime:9,primit:[2,3,18,20],primrec:[3,7,8,9,13],print:[0,1,2,3,5,17,18,22,23],probabl:[7,8,11,18],problem:[8,18,20],proc_curr:11,proc_left:11,proc_right:11,proce:[6,24],process:[5,8,16,18,22],produc:[3,6,11,13,16,18],product:[5,7,8,17,18],program:[0,2,3,7,8,9,11,13,15,18,19],programm:[15,18],progress:15,project:20,prolog:18,promis:15,prompt:8,proper:[2,3,13,15,24],properti:0,provid:[0,3,4,8,15,18,24],pun:[0,8],punctuat:18,pure:[0,5],puriti:8,purpos:8,push:[2,3,8,13,19,23],put:[1,2,7,8,15,18,20,23],pypi:0,python3:8,python:[0,2,3,5,11,13,15,19,20,21,23,24],quadrat:[0,20],queri:[11,16],query_kei:16,queu:13,quit:[0,16],quot:[0,3,7,8,11,12,13,15,16,18,19,22],quotat:[2,3,13],quotient:3,r_kei:11,r_left:11,r_right:11,r_valu:11,rais:[5,11,18,21,23],rang:[5,8,18],range_revers:13,range_to_zero:8,ranger:13,ranger_revers:13,rankdir:5,raphson:9,rather:[6,8,13,16],ratio:8,reach:[5,6,7,13],read:[0,1,6,7,11,18,19],readabl:14,reader:[5,11],readi:18,real:11,realiz:[4,11],rearrang:[2,11,18],reason:[6,8,15,18],rebuild:[16,19],rec1:[2,3,13],rec2:[2,3,13],recent:18,recogn:21,recombin:15,record:[8,22],recur:[3,13,18],recurs:[0,2,3,5,7,8,9,15,18,20,23],recus:8,redefin:20,redistribut:[3,8],redo:5,reduc:[2,18],redund:23,refactor:[8,10],refer:[0,2],referenti:15,reflect:15,regard:15,regist:2,regular:[18,20,21],reifi:17,reimplement:[15,20],relabel:[],relat:[5,18],releas:10,remain:[2,8,10,18],remaind:[3,9],rememb:5,remind:18,remov:[3,11,18,23],render:20,repeat:6,repeatedli:6,repetit:5,repl:[0,1],replac:[0,2,3,7,12,13,15,16,18,19,20,23],repositori:0,repr:[5,18],repres:[2,8,11,15,21,22],represent:23,reprod:7,repurpos:18,requir:[15,18,23],res:18,research:18,resembl:8,resolut:15,resourc:[3,15],respect:[5,6,15],rest:[3,6,7,8,11,13,19,20,23,24],rest_two:11,restart:3,restor:2,result:[1,2,3,5,6,11,12,13,15,16,18,19],resum:8,retir:2,retri:8,reus:[11,18],revers:[3,6,7,13,18,19,20,23],revisit:18,rewrit:[3,8,18],rewritten:8,rid:11,right:[7,8,12,16,18,20,22,23],rightest:11,rightmost:6,rigor:15,risk:18,rkei:16,rob:18,roll:[3,9,11,16],roll_dn:18,rolldown:[3,17,18,24],rollup:[3,18,24],root:[3,9,12],round:18,row:5,rrest:[3,17,18,24],rshift:24,rule:[15,20],run:[0,1,3,6,8,9,11,12,13,15,16,18,19],runtim:15,runtimeerror:23,sai:[5,7,11,12,16,18],same:[2,4,6,11,15,18,23],sandwich:[2,3,13],save:[2,5,6,8],scan:3,scanner:[8,21],scenario:19,scope:[7,11],search:[0,11],sec:18,second:[3,8,11,13,16,23,24],section:13,see:[0,5,7,8,9,10,12,13,14,18,19,22],seem:[0,6,8,16,18,24],seen:[18,19],select:3,self:[5,15,18],semant:[2,3,8,10,11,15,18],semi:8,send:8,sens:[0,2,6,18,19],separ:[8,15,18,21],seq:18,sequenc:[0,1,2,3,6,8,11,13,14,19,20,21,24],sequence_to_stack:18,seri:[6,7,11,19],ses:18,set:[2,3,5,13,18,20],seven:[6,7],sever:[0,4,8,13],shape:[5,15],share:[3,8],shelf:2,shew:5,shift:[6,7],shorter:20,shorthand:11,should:[2,3,5,6,11,13,15,18],shouldn:8,show:[4,15,18,19],shunt:[3,19],side:[5,11,17,18,24],sign:3,signatur:24,signifi:[8,11],similar:[11,16,18],simon:8,simpl:[5,8,13,23,24],simplefunctionwrapp:[3,14,18],simpler:16,simplest:[18,20],simpli:4,simplifi:[6,11,19],sinc:[2,6,11,18],singl:[3,7,8,14,15,18,21,24],singleton:5,situ:11,situat:11,six:[6,7,8],sixti:[6,7],size:[5,8,20],skeptic:8,skip:18,slight:9,slightli:[11,13,18],smallest:3,smart:11,softwar:8,solei:2,solut:[6,7],solvabl:8,some:[2,3,5,7,8,11,13,15,16,18,20,23,24],somehow:[11,18],someth:[2,10,11,18],sometim:11,somewher:[11,20],sort:[3,5,11,15,18],sort_:3,sourc:[0,1,3,18,20,21,22,23],space:[6,22],span:6,spawn:18,special:[7,11,20],specif:[0,4],specifi:[11,15],speed:14,spell:[5,16],sphinx:[20,23],spirit:[0,1,16],split:[5,18],sqr:[3,8,9,12,19],sqrt:[3,9,18,24],squar:[3,9,18,21],stack:[0,1,3,6,7,9,11,12,13,14,15,16,17,19,20,21,22,24],stack_effect:18,stack_effect_com:18,stack_to_str:[17,23],stacki:18,stackjoytyp:18,stackstarjoytyp:18,stage:16,stai:[0,1],stand:[4,5],standard:[8,11],star:[16,18],stare:11,start:[5,6,7,8,9,11,13,16,18,24],state:[8,20],state_nam:5,statement:[3,5],stdout:[17,18],step:[3,6,8,11,14,18,19,20],still:[5,11,18],stop:11,stopiter:5,storag:[6,11],store:[6,13,18],stori:13,str:[1,5,18,21,22,23],straightforward:[5,7,9,18,20],stream:[6,17,18],stretch:11,string:[1,2,3,8,18,19,20,21,22,23],stringi:5,structur:[8,15,16,18,19,20,23],stuck:5,studi:5,stuff:[11,18],stuncon:[3,24],stununcon:[3,24],style:[0,4,18],sub:[10,15,24],subclass:8,subject:[15,19],subsequ:15,subset:[18,24],substitut:[5,11,18],subtract:6,subtyp:20,succ:[3,18,24],succe:18,success:9,suck:18,suffic:18,suffici:11,suffix:18,suggest:[4,5,11],suitabl:[3,4,6],sum:[3,7,8,12,13,14,16],sum_:[3,18],summand:6,sumtre:16,suppli:[11,21],support:[8,18,22,23],sure:15,suspect:2,svg:5,swaack:[3,12,14,18,19,24],swap:[3,6,7,8,9,11,13,14,15,16,17,19,24],swon:[3,7,8,13,16,18,19,24],swoncat:[7,8,9,13,16],swuncon:13,sym:5,symbol:[1,2,3,5,15,18,19,20,21],symboljoytyp:18,symmetr:[6,11],symmetri:5,syntact:8,syntax:[8,23],sys:[17,18,23],system:[8,11,15],tabl:[5,18],tag:[5,18],tail:[11,18,20,23],tailrec:3,take:[3,5,6,8,9,11,13,15,18,23],talk:[8,11,18,23],target:19,tast:4,tbd:8,tear:13,technic:2,techniqu:[4,19],technolog:2,temporari:19,ten:6,term:[1,2,5,8,9,13,15,18,20,21,23,24],termin:[2,3,5,13],ternari:8,test:[2,3,13],text:[0,1,3,18],text_to_express:[8,17,21],textjoytyp:[],textual:8,than:[0,3,5,6,7,8,9,13,15,16,18,23,24],thei:[2,5,6,7,8,11,13,15,18,19,21,23],them:[2,3,5,6,7,11,13,15,18,19,20,24],themselv:[15,18],theori:[2,3,13,15],therefor:7,thi:[0,1,2,3,4,5,6,7,8,9,12,13,15,16,18,19,20,21,22,23,24],thing:[2,7,11,13,15,18,19,21,23,24],think:[2,6,8,11,13,15,16,18],third:[3,7,8,11,24],thirti:6,those:[2,3,5,11,13,18,20,24],though:[6,15],thought:[8,15],thousand:6,thread:[2,15],three:[2,3,5,6,8,11,12,16,18,20],through:[1,6,8,16,18,19,23,24],thun:[2,3,4,10,13,15],thunder:8,thunk:15,time:[3,5,6,8,9,11,13,15,18,19],titl:18,to_check:5,to_set:11,todai:8,todo:[8,21],togeth:[7,8,15,18,20],token:21,toler:20,too:[5,13,18],tool:[8,18],tooo:18,top:[2,3,8,13,18,22,23],total:6,tower:18,trace:[0,8,12,13,19,20,23],traceback:18,traceprint:22,track:[12,18,19],tracker:0,transform:4,transit:5,translat:[4,12,18],trap:5,travers:[0,20],treasur:0,treat:[0,2,3,13,18,20],treatment:7,tree:[0,8,20],treegrind:20,treestep:[0,20],tri:6,triangl:15,triangular_numb:13,trick:[6,18],tricki:18,trinari:[],trobe:0,trove:0,truediv:24,truthi:[3,8,15,18],tuck:[3,8,18,24],tupl:[3,5,8,18,23],turn:[2,3,5,18],twice:[11,13],two:[2,3,6,8,9,11,12,13,15,16,17,18,19,20,23,24],txt:3,type:[0,1,4,8,11,13,15,20,21,22,23],type_check:[],typeerror:18,typeless:18,typic:[2,3,12,13],unari:8,unarybuiltinwrapp:3,unbalanc:[11,21],unbound:24,unchang:11,uncompil:18,uncon:[3,7,8,11,13,16,19,24],under:[2,3,8,11],underli:[5,15,18],underscor:18,understand:[0,11],undistinguish:11,undocu:8,unfinish:5,unfortun:23,uni_unifi:[],unicod:18,unif:[18,20],unifi:17,union:5,uniqu:[3,5,11,18],unit:[3,8,13,15,24],univers:[0,8,15,18],unlik:15,unnecessari:20,unnecesssari:18,unpack:[2,3,11,23],unpair:6,unquot:[8,16,21],unrol:5,unstack:18,unswon:[3,24],untangl:13,until:[5,7,15],unus:6,unusu:11,unwrap:5,updat:[0,17,20],uppercas:5,upward:15,usag:8,use:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,16,19,20,23],used:[3,4,8,11,13,15,18,19,21,23],useful:[0,15,18],user:16,uses:[2,3,5,6,13],using:[7,11,12,13,16,19,24],usual:[0,2,13],util:[0,3,14,17,18],valid:18,valu:[0,1,2,3,6,8,9,12,13,14,15,16,18,20,21,23,24],value_n:11,valueerror:[5,18,23],variabl:[18,20],variant:11,variat:[13,15,20],varieti:[4,8],variou:0,vener:23,verbos:4,veri:[0,1,4,5,8,11,23],versa:[2,18],version:[0,1,2,5,7,10,16,19,20],via:8,vice:[2,18],view:[11,20],viewer:[1,8,10,22],vii:20,visibl:18,von:[0,2,3,4,13],waaaai:5,wai:[0,2,3,4,5,6,8,13,14,15,18],wait:15,want:[2,3,6,7,9,11,13,18],warranti:[3,8],wash:8,wast:8,web:23,websit:[0,6],welcom:8,well:[0,4,8,9,11,18,21],went:18,were:[8,18,19],what:[2,3,4,5,8,11,13,15,16,18,22],whatev:[2,3,13,16,23],when:[6,7,8,11,13,15,18,19,21,23,24],where:[2,3,5,8,11,13,18,20,23],whether:[3,13],which:[0,1,3,5,6,8,9,11,15,16,18,19,21,23,24],whole:[2,3,6,13,16,18],whose:7,why:[9,15,16],wiki:11,wikipedia:[0,11,19],wildli:8,wind:8,wire:13,within:[8,11,14,20],without:[2,8,11,12,15,18],won:[11,18,23],word:[0,3,6,8,13,19],work:[0,3,5,6,7,8,9,11,12,13,15,16,19,20,23,24],worker:15,worri:15,worth:6,would:[2,6,7,8,9,11,13,15,18,19,23],wrap:[3,8],wrapper:18,write:[4,5,9,11,13,15,16,18,19,20,23],written:[0,1,9,11,14,18,23],wrong:2,wrote:18,xrang:18,yang:18,yeah:15,year:[8,18],yet:[11,15,18,19],yield:[2,3,13,18,23],yin:20,yin_funct:[],you:[0,2,3,5,6,7,8,10,11,12,13,14,15,16,18,19,22,23],your:[2,3,8,13,18],yourself:[5,8,11],zero:[3,5,11,13,15,16,18,21,23],zerodivisionerror:18,zip:[5,6,18],zip_:3,zipper:[0,20],zstr:19},titles:["Thun 0.4.0 Documentation","Joy Interpreter","Functions Grouped by, er, Function with Examples","Function Reference","Categorical Programming","\u2202RE","Developing a Program in Joy","Using x to Generate Values","Thun: Joy in Python","Newton\u2019s method","No Updates","Treating Trees I: Ordered Binary Trees","Quadratic formula","Recursion Combinators","Replacing Functions in the Dictionary","The Four Fundamental Operations of Definite Action","Treating Trees II: treestep","Type Checking","The Blissful Elegance of Typing Joy","Traversing Datastructures with Zippers","Essays about Programming in Joy","Parsing Text into Joy Expressions","Tracing Joy Execution","Stack or Quote or Sequence or List\u2026","Type Inference of Joy Expressions"],titleterms:{"\u03bb":5,"\u03d5":5,"case":[9,11],"function":[2,3,5,8,9,11,13,14,15,16,18],"long":14,"new":11,"p\u00f6ial":18,"try":5,"void":2,"while":[2,15],Adding:11,One:[7,11],The:[6,8,11,13,15,16,18],There:8,Using:7,With:[5,16],about:20,action:15,add:[2,11],adding:11,address:19,alphabet:5,altern:16,ana:13,analysi:6,anamorph:[2,13],app1:2,app2:2,app3:2,appendix:[11,13,18],appli:15,approxim:9,argument:18,auto:3,averag:2,base:[9,11],binari:[2,11,16],bliss:18,both:11,branch:[2,11,15],brzozowski:5,can:11,cata:13,catamorph:13,categor:4,chatter:2,check:17,child:11,choic:2,clear:2,cleav:[2,15],cmp:11,code:[8,11],combin:[2,11,13,18],comment:18,compact:5,compar:11,comparison:2,compil:[7,18],compile_:18,compos:18,comput:9,con:[2,18],concat:2,conclus:[13,18],consecut:9,continu:8,current:11,datastructur:[5,8,11,19],deal:18,defin:[11,16],definit:[12,15],delabel:18,delet:11,deriv:[5,12,13,16],design:13,determin:19,develop:6,diagram:5,dialect:0,dictionari:14,dip:[2,19],dipd:2,dipdd:2,direco:7,disenstacken:2,distinguish:18,div:2,doc_from_stack_effect:18,document:0,doe:11,down_to_zero:2,drive:5,drop:2,dup:[2,18],dupd:2,dupdip:2,effect:18,eleg:18,els:11,empti:11,enstacken:2,equal:11,essai:20,euler:[6,7],eval:8,even:7,exampl:[2,8,11,13,16,17],execut:22,explor:5,express:[5,8,21,24],extract:16,factori:13,fail:17,fibonacci:7,filter:6,find:[9,11,13],finish:15,finit:5,first:[2,6,15,18],five:7,flatten:2,flexibl:16,floordiv:2,formula:12,found:11,four:[13,15],from:13,fsm:5,fulmin:15,fun:13,fundament:15,further:6,gcd:2,gener:[3,5,6,7,9,13],genrec:2,get:[11,16],getitem:2,given:[13,16],greater:11,group:2,handl:15,have:[11,16],help:2,highest:11,host:0,how:[6,7],hybrid:18,hylo:13,hylomorph:13,identifi:18,ift:[2,15],iii:18,implement:[5,18],indic:0,infer:[18,24],inferenc:18,inform:0,infra:[2,19],integ:[6,13],interest:7,interlud:11,intern:21,interpret:[1,8,18],item:19,iter:[6,11],joi:[0,1,3,6,8,13,18,19,20,21,22,23,24],join:15,just:6,kei:11,kind:15,languag:0,larger:5,least_fract:2,left:11,less:11,let:[5,6],letter:5,librari:[3,8,18],like:11,list:[2,13,23],literari:8,littl:6,logic:[2,18],loop:[2,8,15],lower:11,lshift:2,machin:5,make:[7,9],mani:6,map:[2,15],match:5,math:2,memoiz:5,method:9,min:2,miscellan:2,mod:2,modifi:18,modulu:2,more:11,most:11,mul:[2,18],multipl:[6,7,18],must:11,name:12,neg:2,newton:9,next:9,node:11,non:11,now:11,nullari:2,nulli:5,number:[13,18],one:8,onli:8,oper:15,order:[11,16],osdn:0,other:15,our:11,out:5,over:2,pack:6,pam:[2,15],para:13,paradigm:18,parallel:15,parameter:[11,16],pars:[2,21],parser:[8,21],part:18,pass:8,path:19,pattern:13,per:11,pop:[2,18],popd:2,popop:2,pow:2,power:7,pred:2,predic:[6,9,11,16],pretty_print:22,primit:13,primrec:2,print:8,problem:[6,7],process:11,product:2,program:[4,6,12,16,20],progress:18,project:[0,6,7],pure:8,put:[11,12,16],python:[8,14,18],quadrat:12,quick:0,quot:[2,23],rang:[2,6,13],range_to_zero:2,read:8,recur:[9,11],recurs:[11,13,16],redefin:[11,16],refactor:[6,11],refer:3,regular:[5,8],reimplement:16,relabel:18,rem:2,remaind:2,remov:2,render:6,repl:8,replac:[11,14],repres:[5,18],represent:5,reset:7,rest:[2,18],revers:[2,5,17],right:[11,19],rightmost:11,roll:[2,18],rolldown:2,rollup:2,rshift:2,rule:[5,18],run:[2,7],second:[2,18],select:2,sequenc:[7,15,18,23],set:[9,11],shorter:14,should:8,shunt:2,simpl:18,simplest:6,size:[2,14],sourc:11,special:[13,18],sqr:[2,18],sqrt:[2,12],stack:[2,8,18,23],start:0,state:5,step:[2,13,16],straightforward:12,stream:5,string:5,structur:11,style:8,sub:[2,11],subtyp:18,succ:2,sum:[2,6],swaack:2,swap:[2,18],swon:2,swoncat:2,symbol:[8,13],tabl:0,tail:13,take:2,term:[6,7,16],ternari:2,text:21,than:11,them:12,thi:11,third:[2,18],three:7,thun:[0,8],time:[2,7],togeth:[11,12,16],token:8,toler:9,trace:[14,22],traceprint:8,trampolin:5,travers:[11,16,19],treat:[11,16],tree:[11,16,19],treegrind:16,treestep:16,triangular:13,truediv:2,truthi:2,tuck:2,two:[5,7],type:[17,18,24],unari:2,unbound:18,uncon:[2,18],unif:17,unifi:18,unit:2,unnecessari:6,unquot:2,unstack:2,updat:[10,18],use:18,util:[22,23,24],valu:[7,11],variabl:12,variat:7,version:[6,11,14,18],view:8,vii:18,which:13,within:9,word:2,work:[17,18],write:12,xor:2,yin:18,zero:7,zip:2,zipper:19}}) \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/types.html b/docs/sphinx_docs/_build/html/types.html index eb52770..581069a 100644 --- a/docs/sphinx_docs/_build/html/types.html +++ b/docs/sphinx_docs/_build/html/types.html @@ -107,214 +107,6 @@ auto-compiled to Python):

unswons = ([a1 ...1] -- [...1] a1) *
-
-
-class joy.utils.types.AnyJoyType(number)[source]
-

Joy type variable. Represents any Joy value.

-
- -
-
-class joy.utils.types.BooleanJoyType(number)[source]
-
-
-accept
-

alias of __builtin__.bool

-
- -
- -
-
-class joy.utils.types.CombinatorJoyType(name, sec, number, expect=None)[source]
-

Represent combinators.

-

These type variables carry Joy functions that implement the -behaviour of Joy combinators and they can appear in expressions. -For simple combinators the implementation functions can be the -combinators themselves.

-

These types can also specify a stack effect (input side only) to -guard against being used on invalid types.

-
- -
-
-class joy.utils.types.FloatJoyType(number)[source]
-
-
-accept
-

alias of __builtin__.float

-
- -
- -
-
-class joy.utils.types.FunctionJoyType(name, sec, number)[source]
-
- -
-
-class joy.utils.types.IntJoyType(number)[source]
-
-
-accept
-

alias of __builtin__.int

-
- -
- -
-
-exception joy.utils.types.JoyTypeError[source]
-
- -
-
-class joy.utils.types.KleeneStar(number)[source]
-

A sequence of zero or more AnyJoyType variables would be:

-
-
A*
-

The A* works by splitting the universe into two alternate histories:

-
-

A* → ∅

-

A* → A A*

-
-

The Kleene star variable disappears in one universe, and in the other -it turns into an AnyJoyType variable followed by itself again.

-

We have to return all universes (represented by their substitution -dicts, the “unifiers”) that don’t lead to type conflicts.

-
-
-kind
-

alias of AnyJoyType

-
- -
- -
-
-class joy.utils.types.NumberJoyType(number)[source]
-
- -
-
-class joy.utils.types.StackJoyType(number)[source]
-
-
-accept
-

alias of __builtin__.tuple

-
- -
- -
-
-class joy.utils.types.SymbolJoyType(name, sec, number)[source]
-

Represent non-combinator functions.

-

These type variables carry the stack effect comments and can -appear in expressions (as in quoted programs.)

-
- -
-
-class joy.utils.types.TextJoyType(number)[source]
-
-
-accept
-

alias of __builtin__.basestring

-
- -
- -
-
-joy.utils.types.compilable(f)[source]
-

Return True if a stack effect represents a function that can be -automatically compiled (to Python), False otherwise.

-
- -
-
-joy.utils.types.compile_(name, f, doc=None)[source]
-

Return a string of Python code implementing the function described -by the stack effect. If no doc string is passed doc_from_stack_effect() -is used to generate one.

-
- -
-
-joy.utils.types.compose(*functions)[source]
-

Return the stack effect of the composition of some of stack effects.

-
- -
-
-joy.utils.types.delabel(f, seen=None, c=None)[source]
-

Fix up type variable numbers after relabel().

-
- -
-
-joy.utils.types.doc_from_stack_effect(inputs, outputs=('??', ()))[source]
-

Return a crude string representation of a stack effect.

-
- -
-
-joy.utils.types.infer(*expression)[source]
-

Return a list of stack effects for a Joy expression.

-

For example:

-
h = infer(pop, swap, rolldown, rest, rest, cons, cons)
-for fi, fo in h:
-                print doc_from_stack_effect(fi, fo)
-
-
-

Prints:

-
([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1])
-
-
-
- -
-
-joy.utils.types.meta_compose(F, G, e)[source]
-

Yield the stack effects of the composition of two lists of stack -effects. An expression is carried along and updated and yielded.

-
- -
-
-joy.utils.types.poly_compose(f, g, e)[source]
-

Yield the stack effects of the composition of two stack effects. An -expression is carried along and updated and yielded.

-
- -
-
-joy.utils.types.reify(meaning, name, seen=None)[source]
-

Apply substitution dict to term, returning new term.

-
- -
-
-joy.utils.types.relabel(left, right)[source]
-

Re-number type variables to avoid collisions between stack effects.

-
- -
-
-joy.utils.types.type_check(name, stack)[source]
-

Trinary predicate. True if named function type-checks, False if it -fails, None if it’s indeterminate (because I haven’t entered it into -the FUNCTIONS dict yet.)

-
- -
-
-joy.utils.types.uni_unify(u, v, s=None)[source]
-

Return a substitution dict representing a unifier for u and v.

-
-

Example output of the infer() function. The first number on each line is the depth of the Python stack. It goes down when the function backtracks. The next thing on each line is the currently-computed stack diff --git a/i3.json b/i3.json deleted file mode 100644 index aa1c3a4..0000000 --- a/i3.json +++ /dev/null @@ -1,88 +0,0 @@ -// vim:ts=4:sw=4:et -{ - // splitv split container with 2 children - "border": "normal", - "floating": "auto_off", - "layout": "splitv", - "percent": 0.25, - "type": "con", - "nodes": [ - { - // splith split container with 1 children - "border": "normal", - "floating": "auto_off", - "layout": "splith", - "percent": 0.25, - "type": "con", - "nodes": [ - { - "border": "normal", - "current_border_width": 2, - "floating": "auto_off", - "geometry": { - "height": 244, - "width": 204, - "x": 0, - "y": 0 - }, - "name": "Stack", - "percent": 1, - "swallows": [ - { - "class": "^Toplevel$", - "title": "^Stack$" - // "transient_for": "^$" - } - ], - "type": "con" - } - ] - }, - { - "border": "normal", - "current_border_width": 2, - "floating": "auto_off", - "geometry": { - "height": 200, - "width": 200, - "x": 0, - "y": 0 - }, - "name": "Log", - "percent": 0.75, - "swallows": [ - { - "class": "^Toplevel$", - // "instance": "^140192861986616$", - "title": "^Log$" - // "transient_for": "^$" - } - ], - "type": "con" - } - ] -} - -{ - "border": "normal", - "current_border_width": 2, - "floating": "auto_off", - "geometry": { - "height": 200, - "width": 200, - "x": 0, - "y": 0 - }, - "name": "Joy - /home/sforman/.joypy", - "percent": 0.75, - "swallows": [ - { - "class": "^Tk$" - // "instance": "^tk$", - // "title": "^Joy\\ \\-\\ \\/home\\/sforman\\/\\.joypy$" - // "transient_for": "^$" - } - ], - "type": "con" -} - diff --git a/joy/gui/__init__.py b/joy/gui/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/joy/gui/__main__.py b/joy/gui/__main__.py deleted file mode 100644 index 77cca65..0000000 --- a/joy/gui/__main__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2018 Simon Forman -# -# This file is part of Joypy. -# -# Joypy is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Joypy is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Joypy. If not see . -# -import sys -import joy.gui.main - - -sys.exit(joy.gui.main.main()) diff --git a/joy/gui/controllerlistbox.py b/joy/gui/controllerlistbox.py deleted file mode 100644 index eabc23c..0000000 --- a/joy/gui/controllerlistbox.py +++ /dev/null @@ -1,156 +0,0 @@ -''' - Copyright (C) 2004 - 2008 Simon Forman - - This file is part of Xerblin. - - Xerblin is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -''' -from future import standard_library -standard_library.install_aliases() -from builtins import map, object, str -from tkinter import Listbox, SINGLE -from tkinter.dnd import dnd_start -from joy.utils.stack import iter_stack, list_to_stack, expression_to_string - - -class SourceWrapper(object): - ''' - Helper object for drag and drop. - ''' - def __init__(self, source, widget, index=None): - ''' - source is the object being dragged, widget is the container that's - initialing the drag operation, and index s thu index of the item - in the widget's model object (which presumably is a ListModel - containing the source object.) - ''' - self.source = source - self.widget = widget - self.index = index - - def dnd_end(self, target, event): - try: - self.widget.clear() - except AttributeError: - pass - - -class DraggyListbox(Listbox): - - def __init__(self, master=None, **kw): - - # Get our stack. - self.stack = kw.pop('items') - - # Override any passed in selectmode. - kw['selectmode'] = SINGLE - - Listbox.__init__(self, master, **kw) - - self.bind('', self.startDrag) - self.bind('', self.clear) - - def clear(self, event=None): - i = self.curselection() - if i: - i = int(i[0]) - self.selection_clear(i) - - def startDrag(self, event): - i = self.nearest(event.y) - if i >= 0: - self.selection_set(i) - source = self.stack[i] - source = SourceWrapper(source, self, i) - event.num = 1 # Don't ask. (See Tkdnd.py) - dnd_start(source, event) - return "break" - - -class ControllerListbox(DraggyListbox): - - def __init__(self, master=None, **kw): - DraggyListbox.__init__(self, master, **kw) - self._dragIndex = -1 - - def dnd_accept(self, source, event): - self.focus_force() - return self - - def dnd_enter(self, source, event): - pass - - def dnd_motion(self, source, event): - I = self.nearest(event.y_root - self.winfo_rooty()) - if self._dragIndex >= 0: - self.delete(self._dragIndex) - self._dragIndex = I - self.insert(I, '---') - - def dnd_leave(self, source, event): - if self._dragIndex >= 0: - self.delete(self._dragIndex) - self._dragIndex = -1 - - def dnd_commit(self, source, event): - i = self._dragIndex - - if i >= 0: - self.delete(i) - self._dragIndex = -1 - - try: - if self is source.widget: - - # Don't duplicate something by dropping it on itself. - if i == source.index: - return - - # Instead, move it by removing it before the pending append. - del self.stack[source.index] - if i > source.index: - i -= 1 - - self.stack.insert(i, source.source) - - finally: - self.clear() - - -class StackListbox(ControllerListbox): - - def __init__(self, world, master=None, **kw): - ControllerListbox.__init__(self, master, **kw) - self.world = world - - def _update(self): - self.delete(0, 'end') - self.insert(0, *map(self.format, self.stack)) - - def update_stack(self, stack): - self.stack = list(iter_stack(stack)) - self._update() - - def dnd_commit(self, source, event): - ControllerListbox.dnd_commit(self, source, event) - self._update() - self.world.stack = list_to_stack(self.stack) - - @staticmethod - def format(item): - if isinstance(item, tuple): - return '[%s]' % expression_to_string(item) - return str(item) diff --git a/joy/gui/default_joy_home/definitions.txt b/joy/gui/default_joy_home/definitions.txt deleted file mode 100644 index 635ab69..0000000 --- a/joy/gui/default_joy_home/definitions.txt +++ /dev/null @@ -1,49 +0,0 @@ - -round_to_cents == 100 * ++ floor 100 / - - -Ordered Binary Tree datastructure functions. - -fourth == rest_two rest first -?fourth == [] [fourth] [] ifte -first_two == uncons uncons pop -ccons == cons cons -cinf == cons infra -rest_two == rest rest - -_Tree_T> == [dipd] cinf -_Tree_T< == [dipdd] cinf - -_Tree_add_P == over [popop popop first] nullary -_Tree_add_T> == ccons _Tree_T< -_Tree_add_T< == ccons _Tree_T> -_Tree_add_Ee = = pop swap roll< rest_two ccons -_Tree_add_R == _Tree_add_P [_Tree_add_T>] [_Tree_add_Ee] [_Tree_add_T<] cmp -_Tree_add_E == [pop] dipd Tree-new - -_Tree_iter_order_left == [cons dip] dupdip -_Tree_iter_order_current == [[F] dupdip] dip -_Tree_iter_order_right == [fourth] dip i -_Tree_iter_order_R == _Tree_iter_order_left _Tree_iter_order_current _Tree_iter_order_right - -_Tree_get_P == over [pop popop first] nullary -_Tree_get_T> == [fourth] dipd i -_Tree_get_T< == [third] dipd i -_Tree_get_E = = popop second -_Tree_get_R == _Tree_get_P [_Tree_get_T>] [_Tree_get_E] [_Tree_get_T<] cmp - -_Tree_delete_rightmost == [?fourth] [fourth] while -_Tree_delete_clear_stuff = = roll> popop rest -_Tree_delete_del == dip cons dipd swap -_Tree_delete_W == dup _Tree_delete_rightmost first_two over -_Tree_delete_E.0 == _Tree_delete_clear_stuff [_Tree_delete_W] _Tree_delete_del -_Tree_delete_E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[_Tree_delete_E.0] cinf]] cond -_Tree_delete_R0 = = over first swap dup -_Tree_delete_R1 == cons roll> [_Tree_T>] [_Tree_delete_E] [_Tree_T<] cmp - -Tree-new == swap [[] []] ccons -Tree-add == [popop not] [_Tree_add_E] [] [_Tree_add_R] genrec -Tree-iter == [not] [pop] roll< [dupdip rest_two] cons [step] genrec -Tree-iter-order == [not] [pop] [dup third] [_Tree_iter_order_R] genrec -Tree-get == [pop not] swap [] [_Tree_get_R] genrec -Tree-delete == [pop not] [pop] [_Tree_delete_R0] [_Tree_delete_R1] genrec \ No newline at end of file diff --git a/joy/gui/default_joy_home/log.txt b/joy/gui/default_joy_home/log.txt deleted file mode 100644 index a0d63f8..0000000 --- a/joy/gui/default_joy_home/log.txt +++ /dev/null @@ -1,4 +0,0 @@ -Joypy - Copyright © 2018 Simon Forman -This program comes with ABSOLUTELY NO WARRANTY; for details right-click "warranty". This is free software, and you are welcome to redistribute it under certain conditions; right-click "sharing" for details. Right-click on these commands to see docs on UI commands: key_bindings mouse_bindings - - <- diff --git a/joy/gui/default_joy_home/scratch.txt b/joy/gui/default_joy_home/scratch.txt deleted file mode 100644 index 2903d58..0000000 --- a/joy/gui/default_joy_home/scratch.txt +++ /dev/null @@ -1,59 +0,0 @@ -reset_log words mouse_bindings key_bindings - -Stack Chatter - - dup dupd dupdd over tuck - pop popd popdd popop popopd popopdd - swap roll< roll> rolldown rollup - unit clear - -Math - - add + sub - mul * truediv / mod % - div divmod floor pm - abs sqr sqrt neg pow - max min sum average product - pred -- succ ++ lshift << rshift >> - -Logic - - ge gt eq le lt ne - < <= = >= > != <> - and & or not xor ^ - bool truthy ? - -Combinators - - i x b infra dip dipd dipdd dupdip dupdipd - cleave fork app1 app2 app3 map pam - nullary unary binary ternary - -Control Flow - - branch cond ifte choice - loop while genrec primrec - make_generator - -List Manipulation - - enstacken disenstacken stack unstack - first first_two second third fourth rest rrest - flatten drop take reverse select zip - size sort shunt getitem - step step_zero times - cons ccons uncons swons unswons - concat unique - remove - at of pick - unquoted quoted - -Misc - - down_to_zero cmp gcd help id - least_fraction parse quoted - range range_to_zero - reset_log show_log - run - stuncons stununcons - swaack - void diff --git a/joy/gui/default_joy_home/stack.pickle b/joy/gui/default_joy_home/stack.pickle deleted file mode 100644 index 4b4aaa9..0000000 --- a/joy/gui/default_joy_home/stack.pickle +++ /dev/null @@ -1 +0,0 @@ -(t. \ No newline at end of file diff --git a/joy/gui/default_joy_home/thun.config b/joy/gui/default_joy_home/thun.config deleted file mode 100644 index 503287e..0000000 --- a/joy/gui/default_joy_home/thun.config +++ /dev/null @@ -1,15 +0,0 @@ - -[key bindings] - = swap - = dup - = roll< - = roll> - = over - = tuck - = parse - = words - = reset_log show_log - = clear reset_log show_log - = pop - = i - diff --git a/joy/gui/init_joy_home.py b/joy/gui/init_joy_home.py deleted file mode 100644 index 103e8f8..0000000 --- a/joy/gui/init_joy_home.py +++ /dev/null @@ -1,106 +0,0 @@ -''' -Utility module to help with setting up the initial contents of the -JOY_HOME directory. - -These contents are kept in this Python module as a base64-encoded zip -file, so you can just do, e.g.: - - import init_joy_home - init_joy_home.initialize(JOY_HOME) - -''' -from __future__ import print_function -from future import standard_library -standard_library.install_aliases() -import base64, os, io, zipfile - - -def initialize(joy_home): - Z.extractall(joy_home) - - -def create_data(from_dir='./default_joy_home'): - f = io.StringIO() - z = zipfile.ZipFile(f, mode='w') - for fn in os.listdir(from_dir): - from_fn = os.path.join(from_dir, fn) - z.write(from_fn, fn) - z.close() - return base64.encodestring(f.getvalue()) - - -Z = zipfile.ZipFile(io.BytesIO(base64.decodestring(b'''\ -UEsDBBQAAAAAAJKh9Uw/yHAgFQQAABUEAAALAAAAc2NyYXRjaC50eHRyZXNldF9sb2cgd29yZHMg -bW91c2VfYmluZGluZ3Mga2V5X2JpbmRpbmdzCgpTdGFjayBDaGF0dGVyCgogZHVwIGR1cGQgZHVw -ZGQgb3ZlciB0dWNrCiBwb3AgcG9wZCBwb3BkZCBwb3BvcCBwb3BvcGQgcG9wb3BkZAogc3dhcCBy -b2xsPCByb2xsPiByb2xsZG93biByb2xsdXAgCiB1bml0IGNsZWFyCgpNYXRoCgogYWRkICsgc3Vi -IC0gbXVsICogdHJ1ZWRpdiAvIG1vZCAlCiBkaXYgZGl2bW9kIGZsb29yIHBtCiBhYnMgc3FyIHNx -cnQgbmVnIHBvdwogbWF4IG1pbiBzdW0gYXZlcmFnZSBwcm9kdWN0CiBwcmVkIC0tIHN1Y2MgKysg -bHNoaWZ0IDw8IHJzaGlmdCA+PgoKTG9naWMKCiBnZSBndCBlcSBsZSBsdCBuZQogIDwgPD0gPSAg -Pj0gPiAgIT0gPD4KIGFuZCAmIG9yIG5vdCB4b3IgXgogYm9vbCB0cnV0aHkgPwoKQ29tYmluYXRv -cnMKCiBpIHggYiBpbmZyYSBkaXAgZGlwZCBkaXBkZCBkdXBkaXAgZHVwZGlwZAogY2xlYXZlIGZv -cmsgYXBwMSBhcHAyIGFwcDMgbWFwIHBhbQogbnVsbGFyeSB1bmFyeSBiaW5hcnkgdGVybmFyeSAK -CkNvbnRyb2wgRmxvdwoKIGJyYW5jaCBjb25kIGlmdGUgY2hvaWNlCiBsb29wIHdoaWxlIGdlbnJl -YyBwcmltcmVjCiBtYWtlX2dlbmVyYXRvcgoKTGlzdCBNYW5pcHVsYXRpb24KCiBlbnN0YWNrZW4g -ZGlzZW5zdGFja2VuIHN0YWNrIHVuc3RhY2sKIGZpcnN0IGZpcnN0X3R3byBzZWNvbmQgdGhpcmQg -Zm91cnRoIHJlc3QgcnJlc3QKIGZsYXR0ZW4gZHJvcCB0YWtlIHJldmVyc2Ugc2VsZWN0IHppcAog -c2l6ZSBzb3J0IHNodW50IGdldGl0ZW0KIHN0ZXAgc3RlcF96ZXJvIHRpbWVzIAogY29ucyBjY29u -cyB1bmNvbnMgc3dvbnMgdW5zd29ucwogY29uY2F0IHVuaXF1ZQogcmVtb3ZlCiBhdCBvZiBwaWNr -CiB1bnF1b3RlZCBxdW90ZWQKCk1pc2MKCiBkb3duX3RvX3plcm8gY21wIGdjZCBoZWxwIGlkIAog -bGVhc3RfZnJhY3Rpb24gcGFyc2UgcXVvdGVkCiByYW5nZSByYW5nZV90b196ZXJvCiByZXNldF9s -b2cgIHNob3dfbG9nCiBydW4gCiBzdHVuY29ucyBzdHVudW5jb25zCiBzd2FhY2sgCiB2b2lkICAg -ICAKUEsDBBQAAAAAAEBB9Uzn5GRHUQEAAFEBAAAHAAAAbG9nLnR4dEpveXB5IC0gQ29weXJpZ2h0 -IMKpIDIwMTggU2ltb24gRm9ybWFuClRoaXMgcHJvZ3JhbSBjb21lcyB3aXRoIEFCU09MVVRFTFkg -Tk8gV0FSUkFOVFk7IGZvciBkZXRhaWxzIHJpZ2h0LWNsaWNrICJ3YXJyYW50eSIuIFRoaXMgaXMg -ZnJlZSBzb2Z0d2FyZSwgYW5kIHlvdSBhcmUgd2VsY29tZSB0byByZWRpc3RyaWJ1dGUgaXQgdW5k -ZXIgY2VydGFpbiBjb25kaXRpb25zOyByaWdodC1jbGljayAic2hhcmluZyIgZm9yIGRldGFpbHMu -IFJpZ2h0LWNsaWNrIG9uIHRoZXNlIGNvbW1hbmRzIHRvIHNlZSBkb2NzIG9uIFVJIGNvbW1hbmRz -OiBrZXlfYmluZGluZ3MgbW91c2VfYmluZGluZ3MKCiA8LQpQSwMEFAAAAAAAQUH1THd/ml4DAAAA -AwAAAAwAAABzdGFjay5waWNrbGUodC5QSwMEFAAAAAAApqH1TNL4a8/sAAAA7AAAAAsAAAB0aHVu -LmNvbmZpZwpba2V5IGJpbmRpbmdzXQo8RjU+ID0gc3dhcAo8RjY+ID0gZHVwCjxTaGlmdC1GNT4g -PSByb2xsPAo8U2hpZnQtRjY+ID0gcm9sbD4KPEY3PiA9IG92ZXIKPFNoaWZ0LUY3PiA9IHR1Y2sK -PEY4PiA9IHBhcnNlCjxGMTI+ID0gd29yZHMKPEYxPiA9IHJlc2V0X2xvZyBzaG93X2xvZwo8RXNj -YXBlPiA9IGNsZWFyIHJlc2V0X2xvZyBzaG93X2xvZwo8Q29udHJvbC1EZWxldGU+ID0gcG9wCjxD -b250cm9sLWk+ID0gaQoKUEsDBBQAAAAAAHOh9UyQUJ4KOgcAADoHAAAPAAAAZGVmaW5pdGlvbnMu -dHh0CnJvdW5kX3RvX2NlbnRzID09IDEwMCAqICsrIGZsb29yIDEwMCAvCgoKT3JkZXJlZCBCaW5h -cnkgVHJlZSBkYXRhc3RydWN0dXJlIGZ1bmN0aW9ucy4KCmZvdXJ0aCA9PSByZXN0X3R3byByZXN0 -IGZpcnN0Cj9mb3VydGggPT0gW10gW2ZvdXJ0aF0gW10gaWZ0ZQpmaXJzdF90d28gPT0gdW5jb25z -IHVuY29ucyBwb3AKY2NvbnMgPT0gY29ucyBjb25zCmNpbmYgPT0gY29ucyBpbmZyYQpyZXN0X3R3 -byA9PSByZXN0IHJlc3QKCl9UcmVlX1Q+ID09IFtkaXBkXSBjaW5mCl9UcmVlX1Q8ID09IFtkaXBk -ZF0gY2luZgoKX1RyZWVfYWRkX1AgPT0gb3ZlciBbcG9wb3AgcG9wb3AgZmlyc3RdIG51bGxhcnkK -X1RyZWVfYWRkX1Q+ID09IGNjb25zIF9UcmVlX1Q8Cl9UcmVlX2FkZF9UPCA9PSBjY29ucyBfVHJl -ZV9UPgpfVHJlZV9hZGRfRWUgPSA9IHBvcCBzd2FwIHJvbGw8IHJlc3RfdHdvIGNjb25zCl9UcmVl -X2FkZF9SID09IF9UcmVlX2FkZF9QIFtfVHJlZV9hZGRfVD5dIFtfVHJlZV9hZGRfRWVdIFtfVHJl -ZV9hZGRfVDxdIGNtcApfVHJlZV9hZGRfRSA9PSBbcG9wXSBkaXBkIFRyZWUtbmV3CgpfVHJlZV9p -dGVyX29yZGVyX2xlZnQgPT0gW2NvbnMgZGlwXSBkdXBkaXAKX1RyZWVfaXRlcl9vcmRlcl9jdXJy -ZW50ID09IFtbRl0gZHVwZGlwXSBkaXAKX1RyZWVfaXRlcl9vcmRlcl9yaWdodCA9PSBbZm91cnRo -XSBkaXAgaQpfVHJlZV9pdGVyX29yZGVyX1IgPT0gX1RyZWVfaXRlcl9vcmRlcl9sZWZ0IF9UcmVl -X2l0ZXJfb3JkZXJfY3VycmVudCBfVHJlZV9pdGVyX29yZGVyX3JpZ2h0CgpfVHJlZV9nZXRfUCA9 -PSBvdmVyIFtwb3AgcG9wb3AgZmlyc3RdIG51bGxhcnkKX1RyZWVfZ2V0X1Q+ID09IFtmb3VydGhd -IGRpcGQgaQpfVHJlZV9nZXRfVDwgPT0gW3RoaXJkXSBkaXBkIGkKX1RyZWVfZ2V0X0UgPSA9IHBv -cG9wIHNlY29uZApfVHJlZV9nZXRfUiA9PSBfVHJlZV9nZXRfUCBbX1RyZWVfZ2V0X1Q+XSBbX1Ry -ZWVfZ2V0X0VdIFtfVHJlZV9nZXRfVDxdIGNtcAoKX1RyZWVfZGVsZXRlX3JpZ2h0bW9zdCA9PSBb -P2ZvdXJ0aF0gW2ZvdXJ0aF0gd2hpbGUKX1RyZWVfZGVsZXRlX2NsZWFyX3N0dWZmID0gPSByb2xs -PiBwb3BvcCByZXN0Cl9UcmVlX2RlbGV0ZV9kZWwgPT0gZGlwIGNvbnMgZGlwZCBzd2FwCl9UcmVl -X2RlbGV0ZV9XID09IGR1cCBfVHJlZV9kZWxldGVfcmlnaHRtb3N0IGZpcnN0X3R3byBvdmVyCl9U -cmVlX2RlbGV0ZV9FLjAgPT0gX1RyZWVfZGVsZXRlX2NsZWFyX3N0dWZmIFtfVHJlZV9kZWxldGVf -V10gX1RyZWVfZGVsZXRlX2RlbApfVHJlZV9kZWxldGVfRSA9PSBbW1twb3AgdGhpcmQgbm90XSBw -b3AgZm91cnRoXSBbW3BvcCBmb3VydGggbm90XSBwb3AgdGhpcmRdIFtbX1RyZWVfZGVsZXRlX0Uu -MF0gY2luZl1dIGNvbmQKX1RyZWVfZGVsZXRlX1IwID0gPSBvdmVyIGZpcnN0IHN3YXAgZHVwCl9U -cmVlX2RlbGV0ZV9SMSA9PSBjb25zIHJvbGw+IFtfVHJlZV9UPl0gW19UcmVlX2RlbGV0ZV9FXSBb -X1RyZWVfVDxdIGNtcAoKVHJlZS1uZXcgPT0gc3dhcCBbW10gW11dIGNjb25zClRyZWUtYWRkID09 -IFtwb3BvcCBub3RdIFtfVHJlZV9hZGRfRV0gW10gW19UcmVlX2FkZF9SXSBnZW5yZWMKVHJlZS1p -dGVyID09IFtub3RdIFtwb3BdIHJvbGw8IFtkdXBkaXAgcmVzdF90d29dIGNvbnMgW3N0ZXBdIGdl -bnJlYwpUcmVlLWl0ZXItb3JkZXIgPT0gW25vdF0gW3BvcF0gW2R1cCB0aGlyZF0gW19UcmVlX2l0 -ZXJfb3JkZXJfUl0gZ2VucmVjClRyZWUtZ2V0ID09IFtwb3Agbm90XSBzd2FwIFtdIFtfVHJlZV9n -ZXRfUl0gZ2VucmVjClRyZWUtZGVsZXRlID09IFtwb3Agbm90XSBbcG9wXSBbX1RyZWVfZGVsZXRl -X1IwXSBbX1RyZWVfZGVsZXRlX1IxXSBnZW5yZWNQSwECFAMUAAAAAACSofVMP8hwIBUEAAAVBAAA -CwAAAAAAAAAAAAAAgIEAAAAAc2NyYXRjaC50eHRQSwECFAMUAAAAAABAQfVM5+RkR1EBAABRAQAA -BwAAAAAAAAAAAAAAgIE+BAAAbG9nLnR4dFBLAQIUAxQAAAAAAEFB9Ux3f5peAwAAAAMAAAAMAAAA -AAAAAAAAAACAgbQFAABzdGFjay5waWNrbGVQSwECFAMUAAAAAACmofVM0vhrz+wAAADsAAAACwAA -AAAAAAAAAAAAtIHhBQAAdGh1bi5jb25maWdQSwECFAMUAAAAAABzofVMkFCeCjoHAAA6BwAADwAA -AAAAAAAAAAAAtIH2BgAAZGVmaW5pdGlvbnMudHh0UEsFBgAAAAAFAAUAHgEAAF0OAAAAAA=='''))) - - -if __name__ == '__main__': - print(create_data()) diff --git a/joy/gui/main.py b/joy/gui/main.py deleted file mode 100755 index 669ecda..0000000 --- a/joy/gui/main.py +++ /dev/null @@ -1,198 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This is a script, the module namespace is used as a kind of singleton -# for organizing the moving parts of the system. I forget why I didn't -# use a more typical class. -# -# This docstring doubles as the log header that the system prints when -# the log is reset. - -('''\ -Joypy - Copyright © 2018 Simon Forman -''' -'This program comes with ABSOLUTELY NO WARRANTY; for details right-click "warranty".' -' This is free software, and you are welcome to redistribute it under certain conditions;' -' right-click "sharing" for details.' -' Right-click on these commands to see docs on UI commands: key_bindings mouse_bindings') - -from __future__ import print_function -from future import standard_library -standard_library.install_aliases() -import logging, os, pickle, sys -from datetime import datetime -from textwrap import dedent -from configparser import RawConfigParser - -from joy.gui.utils import init_home, argparser, FileFaker - - -DATETIME_FORMAT = "Thun • %B %d %a • %I:%M %p" -VIEWER_DEFAULTS = dict(width=80, height=25) - - -args = argparser.parse_args() -JOY_HOME = args.joy_home -repo = init_home(JOY_HOME) -homed = lambda fn: os.path.join(JOY_HOME, fn) - -# Set up logging before doing anything else. - -_log = logging.getLogger(__name__) -logging.basicConfig( - format='%(asctime)-15s %(levelname)s %(name)s %(message)s', - filename=os.path.join(JOY_HOME, 'thun.log'), - level=logging.INFO, - ) -_log.info('Starting with JOY_HOME=%s', JOY_HOME) - -# Now that logging is set up, continue loading the system. - -from joy.gui.textwidget import TextViewerWidget, tk, get_font -from joy.gui.world import StackWorld -from joy.gui.controllerlistbox import StackListbox -from joy.library import initialize, DefinitionWrapper -from joy.utils.stack import stack_to_string - - -cp = RawConfigParser() -# Don't mess with uppercase. We need it for Tk event binding. -cp.optionxform = str -with open(os.path.join(args.joy_home, 'thun.config')) as f: - cp.readfp(f) - - -GLOBAL_COMMANDS = dict(cp.items('key bindings')) - - -def repo_relative_path(path): - return os.path.relpath( - path, - os.path.commonprefix((repo.controldir(), path)) - ) - -def commands(): - ''' - We define a bunch of meta-interpreter command functions here and - return them in a dictionary. They have all the contents of this - module in their scope so they can e.g. modify the log viewer window. - ''' - # pylint: disable=unused-variable - - def key_bindings(*args): - commands = [ # These are bound in the TextViewerWidget. - 'Control-Enter - Run the selection as Joy code, or if there\'s no selection the line containing the cursor.', - 'F3 - Copy selection to stack.', - 'Shift-F3 - Cut selection to stack.', - 'F4 - Paste item on top of stack to insertion cursor.', - 'Shift-F4 - Pop and paste top of stack to insertion cursor.', - ] - for key, command in GLOBAL_COMMANDS.items(): - commands.append('%s - %s' % (key.lstrip('<').rstrip('>'), command)) - print('\n'.join([''] + sorted(commands))) - return args - - - def mouse_bindings(*args): - print(dedent(''' - Mouse button chords (to cancel a chord, click the third mouse button.) - - Left - Point, sweep selection - Left-Middle - Copy the selection, place text on stack - Left-Right - Run the selection as Joy code - - Middle - Paste selection (bypass stack); click and drag to scroll. - Middle-Left - Paste from top of stack, preserve - Middle-Right - Paste from top of stack, pop - - Right - Execute command word under mouse cursor - Right-Left - Print docs of command word under mouse cursor - Right-Middle - Lookup word (kinda useless now) - ''')) - return args - - - def reset_log(*args): - log.delete('0.0', tk.END) - print(datetime.now().strftime(DATETIME_FORMAT)) - return args - - - def Thun(*args): - print(__doc__) - return args - - - def show_log(*args): - log_window.wm_deiconify() - log_window.update() - return args - - - def show_stack(*args): - stack_window.wm_deiconify() - stack_window.update() - return args - - - def grand_reset(s, e, d): - stack = world.load_stack() or () - log.reset() - t.reset() - return stack, e, d - - return locals() - - -# Identify the system core files. -DEFS_FN = homed('definitions.txt') -JOY_FN = homed('scratch.txt') -LOG_FN = homed('log.txt') -STACK_FN = homed('stack.pickle') -REL_STACK_FN = repo_relative_path(STACK_FN) - -# Initialize the Joy dictionary. -D = initialize() -D.update(commands()) -DefinitionWrapper.load_definitions(DEFS_FN, D) - -world = StackWorld(repo, STACK_FN, REL_STACK_FN, dictionary=D) - -t = TextViewerWidget(world, **VIEWER_DEFAULTS) - -log_window = tk.Toplevel() -# Make it so that you can't actually close the log window, if you try it -# will just "withdraw" (which is like minifying but without a entry in -# the taskbar or icon or whatever.) -log_window.protocol("WM_DELETE_WINDOW", log_window.withdraw) -log = TextViewerWidget(world, log_window, **VIEWER_DEFAULTS) - -FONT = get_font('Iosevka', size=14) # Requires Tk root already set up. - -stack_window = tk.Toplevel() -stack_window.title("Stack") -stack_window.protocol("WM_DELETE_WINDOW", log_window.withdraw) -stack_viewer = StackListbox(world, stack_window, items=[], font=FONT) -stack_viewer.pack(expand=True, fill=tk.BOTH) -world.set_viewer(stack_viewer) - - -log.init('Log', LOG_FN, repo_relative_path(LOG_FN), repo, FONT) -t.init('Joy - ' + JOY_HOME, JOY_FN, repo_relative_path(JOY_FN), repo, FONT) - -for event, command in GLOBAL_COMMANDS.items(): - callback = lambda _, _command=command: world.interpret(_command) - t.bind_all(event, callback) - - -def main(): - sys.stdout, old_stdout = FileFaker(log), sys.stdout - try: - t.mainloop() - finally: - sys.stdout = old_stdout - return 0 - - -if __name__ == '__main__': - main() diff --git a/joy/gui/mousebindings.py b/joy/gui/mousebindings.py deleted file mode 100644 index db5e157..0000000 --- a/joy/gui/mousebindings.py +++ /dev/null @@ -1,211 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2014, 2015 Simon Forman -# -# This file is part of joy.py -# -# joy.py is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# joy.py is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with joy.py. If not see . -# -from builtins import object - - -#Do-nothing event handler. -nothing = lambda event: None - - -class MouseBindingsMixin(object): - """TextViewerWidget mixin class to provide mouse bindings.""" - - def __init__(self): - - #Remember our mouse button state - self.B1_DOWN = False - self.B2_DOWN = False - self.B3_DOWN = False - - #Remember our pending action. - self.dothis = nothing - - #We'll need to remember whether or not we've been moving B2. - self.beenMovingB2 = False - - #Unbind the events we're interested in. - for sequence in ( - "", "", "", - "", "", "", - "", "", "", - "", "", "", "", "" - ): - self.unbind(sequence) - self.unbind_all(sequence) - - self.event_delete('<>') #I forgot what this was for! :-P D'oh! - - #Bind our event handlers to their events. - self.bind("", self.B1d) - self.bind("", self.B1m) - self.bind("", self.B1r) - - self.bind("", self.B2d) - self.bind("", self.B2m) - self.bind("", self.B2r) - - self.bind("", self.B3d) - self.bind("", self.B3m) - self.bind("", self.B3r) - - self.bind("", self.leave) - self.bind("", self.scan_command) - - def B1d(self, event): - '''button one pressed''' - self.B1_DOWN = True - - if self.B2_DOWN: - - self.unhighlight_command() - - if self.B3_DOWN : - self.dothis = self.cancel - - else: - #copy TOS to the mouse (instead of system selection.) - self.dothis = self.copyto #middle-left-interclick - - elif self.B3_DOWN : - self.unhighlight_command() - self.dothis = self.opendoc #right-left-interclick - - else: - ##button 1 down, set insertion and begin selection. - ##Actually, do nothing. Tk Text widget defaults take care of it. - self.dothis = nothing - return - - #Prevent further event handling by returning "break". - return "break" - - def B2d(self, event): - '''button two pressed''' - self.B2_DOWN = 1 - - if self.B1_DOWN : - - if self.B3_DOWN : - self.dothis = self.cancel - - else: - #left-middle-interclick - copy selection to stack - self.dothis = self.copy_selection_to_stack - - elif self.B3_DOWN : - self.unhighlight_command() - self.dothis = self.lookup #right-middle-interclick - lookup - - else: - #middle-click - paste X selection to mouse pointer - self.set_insertion_point(event) - self.dothis = self.paste_X_selection_to_mouse_pointer - return - - return "break" - - def B3d(self, event): - '''button three pressed''' - self.B3_DOWN = 1 - - if self.B1_DOWN : - - if self.B2_DOWN : - self.dothis = self.cancel - - else: - #left-right-interclick - run selection - self.dothis = self.run_selection - - elif self.B2_DOWN : - #middle-right-interclick - Pop/Cut from TOS to insertion cursor - self.unhighlight_command() - self.dothis = self.pastecut - - else: - #right-click - self.CommandFirstDown(event) - - return "break" - - def B1m(self, event): - '''button one moved''' - if self.B2_DOWN or self.B3_DOWN: - return "break" - - def B2m(self, event): - '''button two moved''' - if self.dothis == self.paste_X_selection_to_mouse_pointer and \ - not (self.B1_DOWN or self.B3_DOWN): - - self.beenMovingB2 = True - return - - return "break" - - def B3m(self, event): - '''button three moved''' - if self.dothis == self.do_command and \ - not (self.B1_DOWN or self.B2_DOWN): - - self.update_command_word(event) - - return "break" - - def scan_command(self, event): - self.update_command_word(event) - - def B1r(self, event): - '''button one released''' - self.B1_DOWN = False - - if not (self.B2_DOWN or self.B3_DOWN): - self.dothis(event) - - return "break" - - def B2r(self, event): - '''button two released''' - self.B2_DOWN = False - - if not (self.B1_DOWN or self.B3_DOWN or self.beenMovingB2): - self.dothis(event) - - self.beenMovingB2 = False - - return "break" - - def B3r(self, event): - '''button three released''' - self.B3_DOWN = False - - if not (self.B1_DOWN or self.B2_DOWN) : - self.dothis(event) - - return "break" - - def InsertFirstDown(self, event): - self.focus() - self.dothis = nothing - self.set_insertion_point(event) - - def CommandFirstDown(self, event): - self.dothis = self.do_command - self.update_command_word(event) diff --git a/joy/gui/textwidget.py b/joy/gui/textwidget.py deleted file mode 100644 index fc1aeec..0000000 --- a/joy/gui/textwidget.py +++ /dev/null @@ -1,474 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2014, 2015, 2018 Simon Forman -# -# This file is part of joy.py -# -# joy.py is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# joy.py is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with joy.py. If not see . -# -''' - - -A Graphical User Interface for a dialect of Joy in Python. - - -The GUI - - History - Structure - Commands - Mouse Chords - Keyboard - Output from Joy - - -''' -from __future__ import print_function -from future import standard_library -standard_library.install_aliases() -from builtins import str, map, object -from past.builtins import basestring -try: - import tkinter as tk - from tkinter.font import families, Font -except ImportError: - import Tkinter as tk - from tkFont import families, Font - -from re import compile as regular_expression -from traceback import format_exc -import os, sys - -from joy.utils.stack import stack_to_string - -from .mousebindings import MouseBindingsMixin -from .utils import is_numerical -from .world import World - - -def make_gui(dictionary): - t = TextViewerWidget(World(dictionary=dictionary)) - t['font'] = get_font() - t._root().title('Joy') - t.pack(expand=True, fill=tk.BOTH) - return t - - -def get_font(family='EB Garamond', size=14): - if family not in families(): - family = 'Times' - return Font(family=family, size=size) - - -#: Define mapping between Tkinter events and functions or methods. The -#: keys are string Tk "event sequences" and the values are callables that -#: get passed the TextViewer instance (so you can bind to methods) and -#: must return the actual callable to which to bind the event sequence. -TEXT_BINDINGS = { - - #I want to ensure that these keyboard shortcuts work. - '': lambda tv: tv._control_enter, - '': lambda tv: tv._paste, - '': lambda tv: tv._paste, - '': lambda tv: tv.copy_selection_to_stack, - '': lambda tv: tv.copyto, - '': lambda tv: tv.cut, - '': lambda tv: tv.pastecut, - '': lambda tv: tv._paste, - } - - -class SavingMixin(object): - - def __init__(self, saver=None, filename=None, save_delay=2000): - self.saver = self._saver if saver is None else saver - self.filename = filename - self._save_delay = save_delay - self.tk.call(self._w, 'edit', 'modified', 0) - self.bind('<>', self._beenModified) - self._resetting_modified_flag = False - self._save = None - - def save(self): - ''' - Call _saveFunc() after a certain amount of idle time. - - Called by _beenModified(). - ''' - self._cancelSave() - if self.saver: - self._saveAfter(self._save_delay) - - def _saveAfter(self, delay): - ''' - Trigger a cancel-able call to _saveFunc() after delay milliseconds. - ''' - self._save = self.after(delay, self._saveFunc) - - def _saveFunc(self): - self._save = None - self.saver(self._get_contents()) - - def _saver(self, text): - if not self.filename: - return - with open(self.filename, 'wb') as f: - os.chmod(self.filename, 0o600) - f.write(text.encode('UTF_8')) - f.flush() - os.fsync(f.fileno()) - if hasattr(self, 'repo'): - self.repo.stage([self.repo_relative_filename]) - self.world.save() - - def _cancelSave(self): - if self._save is not None: - self.after_cancel(self._save) - self._save = None - - def _get_contents(self): - self['state'] = 'disabled' - try: - return self.get('0.0', 'end')[:-1] - finally: - self['state'] = 'normal' - - def _beenModified(self, event): - if self._resetting_modified_flag: - return - self._clearModifiedFlag() - self.save() - - def _clearModifiedFlag(self): - self._resetting_modified_flag = True - try: - self.tk.call(self._w, 'edit', 'modified', 0) - finally: - self._resetting_modified_flag = False - -## tags = self._saveTags() -## chunks = self.DUMP() -## print chunks - - -class TextViewerWidget(tk.Text, MouseBindingsMixin, SavingMixin): - """ - This class is a Tkinter Text with special mousebindings to make - it act as a Xerblin Text Viewer. - """ - - #This is a regular expression for finding commands in the text. - command_re = regular_expression(r'[-a-zA-Z0-9_\\~/.:!@#$%&*?=+<>]+') - - #These are the config tags for command text when it's highlighted. - command_tags = dict( - #underline = 1, - #bgstipple = "gray50", - borderwidth = 2, - relief=tk.RIDGE, - foreground = "green" - ) - - def __init__(self, world, master=None, **kw): - - self.world = world - if self.world.text_widget is None: - self.world.text_widget = self - - #Turn on undo, but don't override a passed-in setting. - kw.setdefault('undo', True) - - # kw.setdefault('bg', 'white') - kw.setdefault('wrap', 'word') - kw.setdefault('font', 'arial 12') - - text_bindings = kw.pop('text_bindings', TEXT_BINDINGS) - - #Create ourselves as a Tkinter Text - tk.Text.__init__(self, master, **kw) - - #Initialize our mouse mixin. - MouseBindingsMixin.__init__(self) - - #Initialize our saver mixin. - SavingMixin.__init__(self) - - #Add tag config for command highlighting. - self.tag_config('command', **self.command_tags) - self.tag_config('bzzt', foreground = "orange") - self.tag_config('huh', foreground = "grey") - self.tag_config('number', foreground = "blue") - - #Create us a command instance variable - self.command = '' - - #Activate event bindings. Modify text_bindings in your config - #file to affect the key bindings and whatnot here. - for event_sequence, callback_finder in text_bindings.items(): - callback = callback_finder(self) - self.bind(event_sequence, callback) - - ## T.protocol("WM_DELETE_WINDOW", self.on_close) - - def find_command_in_line(self, line, index): - ''' - Return the command at index in line and its begin and end indices. - find_command_in_line(line, index) => command, begin, end - ''' - for match in self.command_re.finditer(line): - b, e = match.span() - if b <= index <= e: - return match.group(), b, e - - def paste_X_selection_to_mouse_pointer(self, event): - '''Paste the X selection to the mouse pointer.''' - try: - text = self.selection_get() - except tk.TclError: - return 'break' - self.insert_it(text) - - def update_command_word(self, event): - '''Highlight the command under the mouse.''' - self.unhighlight_command() - self.command = '' - index = '@%d,%d' % (event.x, event.y) - linestart = self.index(index + 'linestart') - lineend = self.index(index + 'lineend') - line = self.get(linestart, lineend) - row, offset = self._get_index(index) - - if offset >= len(line) or line[offset].isspace(): - # The mouse is off the end of the line or on a space so there's no - # command, we're done. - return - - cmd = self.find_command_in_line(line, offset) - if cmd is None: - return - - cmd, b, e = cmd - if is_numerical(cmd): - extra_tags = 'number', - elif self.world.has(cmd): - check = self.world.check(cmd) - if check: extra_tags = () - elif check is None: extra_tags = 'huh', - else: extra_tags = 'bzzt', - else: - return - self.command = cmd - self.highlight_command( - '%d.%d' % (row, b), - '%d.%d' % (row, e), - *extra_tags) - - def highlight_command(self, from_, to, *extra_tags): - '''Apply command style from from_ to to.''' - cmdstart = self.index(from_) - cmdend = self.index(to) - self.tag_add('command', cmdstart, cmdend) - for tag in extra_tags: - self.tag_add(tag, cmdstart, cmdend) - - def do_command(self, event): - '''Do the currently highlighted command.''' - self.unhighlight_command() - if self.command: - self.run_command(self.command) - - def _control_enter(self, event): - select_indices = self.tag_ranges(tk.SEL) - if select_indices: - command = self.get(select_indices[0], select_indices[1]) - else: - linestart = self.index(tk.INSERT + ' linestart') - lineend = self.index(tk.INSERT + ' lineend') - command = self.get(linestart, lineend) - if command and not command.isspace(): - self.run_command(command) - return 'break' - - def run_command(self, command): - '''Given a string run it on the stack, report errors.''' - try: - self.world.interpret(command) - except SystemExit: - raise - except: - self.popupTB(format_exc().rstrip()) - - def unhighlight_command(self): - '''Remove any command highlighting.''' - self.tag_remove('number', 1.0, tk.END) - self.tag_remove('huh', 1.0, tk.END) - self.tag_remove('bzzt', 1.0, tk.END) - self.tag_remove('command', 1.0, tk.END) - - def set_insertion_point(self, event): - '''Set the insertion cursor to the current mouse location.''' - self.focus() - self.mark_set(tk.INSERT, '@%d,%d' % (event.x, event.y)) - - def copy_selection_to_stack(self, event): - '''Copy selection to stack.''' - select_indices = self.tag_ranges(tk.SEL) - if select_indices: - s = self.get(select_indices[0], select_indices[1]) - self.world.push(s) - - def cut(self, event): - '''Cut selection to stack.''' - self.copy_selection_to_stack(event) - # Let the pre-existing machinery take care of cutting the selection. - self.event_generate("<>") - - def copyto(self, event): - '''Actually "paste" from TOS''' - s = self.world.peek() - if s is not None: - self.insert_it(s) - - def insert_it(self, s): - if not isinstance(s, basestring): - s = stack_to_string(s) - - # When pasting from the mouse we have to remove the current selection - # to prevent destroying it by the paste operation. - select_indices = self.tag_ranges(tk.SEL) - if select_indices: - # Set two marks to remember the selection. - self.mark_set('_sel_start', select_indices[0]) - self.mark_set('_sel_end', select_indices[1]) - self.tag_remove(tk.SEL, 1.0, tk.END) - - self.insert(tk.INSERT, s) - - if select_indices: - self.tag_add(tk.SEL, '_sel_start', '_sel_end') - self.mark_unset('_sel_start') - self.mark_unset('_sel_end') - - def run_selection(self, event): - '''Run the current selection if any on the stack.''' - select_indices = self.tag_ranges(tk.SEL) - if select_indices: - selection = self.get(select_indices[0], select_indices[1]) - self.tag_remove(tk.SEL, 1.0, tk.END) - self.run_command(selection) - - def pastecut(self, event): - '''Cut the TOS item to the mouse.''' - self.copyto(event) - self.world.pop() - - def opendoc(self, event): - '''OpenDoc the current command.''' - if self.command: - self.world.do_opendoc(self.command) - - def lookup(self, event): - '''Look up the current command.''' - if self.command: - self.world.do_lookup(self.command) - - def cancel(self, event): - '''Cancel whatever we're doing.''' - self.leave(None) - self.tag_remove(tk.SEL, 1.0, tk.END) - self._sel_anchor = '0.0' - self.mark_unset(tk.INSERT) - - def leave(self, event): - '''Called when mouse leaves the Text window.''' - self.unhighlight_command() - self.command = '' - - def _get_index(self, index): - '''Get the index in (int, int) form of index.''' - return tuple(map(int, self.index(index).split('.'))) - - def _paste(self, event): - '''Paste the system selection to the current selection, replacing it.''' - - # If we're "key" pasting, we have to move the insertion point - # to the selection so the pasted text gets inserted at the - # location of the deleted selection. - - select_indices = self.tag_ranges(tk.SEL) - if select_indices: - # Mark the location of the current insertion cursor - self.mark_set('tmark', tk.INSERT) - # Put the insertion cursor at the selection - self.mark_set(tk.INSERT, select_indices[1]) - - # Paste to the current selection, or if none, to the insertion cursor. - self.event_generate("<>") - - # If we mess with the insertion cursor above, fix it now. - if select_indices: - # Put the insertion cursor back where it was. - self.mark_set(tk.INSERT, 'tmark') - # And get rid of our unneeded mark. - self.mark_unset('tmark') - - return 'break' - - def init(self, title, filename, repo_relative_filename, repo, font): - self.set_window_title(title) - if os.path.exists(filename): - with open(filename) as f: - data = f.read() - self.insert(tk.END, data) - # Prevent this from triggering a git commit. - self.update() - self._cancelSave() - self.pack(expand=True, fill=tk.BOTH) - self.filename = filename - self.repo_relative_filename = repo_relative_filename - self.repo = repo - self['font'] = font # See below. - - def set_window_title(self, title): - self.winfo_toplevel().title(title) - - def reset(self): - if os.path.exists(self.filename): - with open(self.filename) as f: - data = f.read() - if data: - self.delete('0.0', tk.END) - self.insert(tk.END, data) - - def popupTB(self, tb): - top = tk.Toplevel() - T = TextViewerWidget( - self.world, - top, - width=max(len(s) for s in tb.splitlines()) + 3, - ) - - T['background'] = 'darkgrey' - T['foreground'] = 'darkblue' - T.tag_config('err', foreground='yellow') - - T.insert(tk.END, tb) - last_line = str(int(T.index(tk.END).split('.')[0]) - 1) + '.0' - T.tag_add('err', last_line, tk.END) - T['state'] = tk.DISABLED - - top.title(T.get(last_line, tk.END).strip()) - - T.pack(expand=1, fill=tk.BOTH) - T.see(tk.END) diff --git a/joy/gui/utils.py b/joy/gui/utils.py deleted file mode 100644 index 01b95d7..0000000 --- a/joy/gui/utils.py +++ /dev/null @@ -1,98 +0,0 @@ -from __future__ import print_function -from builtins import object -import argparse, os, sys -from os import listdir, mkdir -from os.path import abspath, exists, expanduser, isfile, join - -from dulwich.errors import NotGitRepository -from dulwich.repo import Repo - - -COMMITTER = b'Joy ' -DEFAULT_JOY_HOME = expanduser(join('~', '.joypy')) - - -def is_numerical(s): - try: - float(s) - except ValueError: - return False - return True - - -def home_dir(path): - '''Return the absolute path of an existing directory.''' - - fullpath = expanduser(path) if path.startswith('~') else abspath(path) - - if not exists(fullpath): - if path == DEFAULT_JOY_HOME: - print('Creating JOY_HOME', repr(fullpath)) - mkdir(fullpath, 0o700) - else: - print(repr(fullpath), "doesn't exist.", file=sys.stderr) - raise ValueError(path) - - return fullpath - - -def init_home(fullpath): - ''' - Open or create the Repo. - If there are contents in the dir but it's not a git repo, quit. - ''' - try: - repo = Repo(fullpath) - except NotGitRepository: - print(repr(fullpath), "no repository", file=sys.stderr) - - if listdir(fullpath): - print(repr(fullpath), "has contents\nQUIT.", file=sys.stderr) - sys.exit(2) - - print('Initializing repository in', fullpath) - repo = init_repo(fullpath) - - print('Using repository in', fullpath) - return repo - - -def init_repo(repo_dir): - ''' - Create a repo, load the initial content, and make the first commit. - Return the Repo object. - ''' - repo = Repo.init(repo_dir) - import joy.gui.init_joy_home - joy.gui.init_joy_home.initialize(repo_dir) - repo.stage([fn for fn in listdir(repo_dir) if isfile(join(repo_dir, fn))]) - repo.do_commit(b'Initial commit.', committer=COMMITTER) - return repo - - -argparser = argparse.ArgumentParser( - prog='joy.gui', - description='Experimental Brutalist UI for Joy.', - ) - - -argparser.add_argument( - '-j', '--joy-home', - help='Use a directory other than %s as JOY_HOME' % DEFAULT_JOY_HOME, - default=DEFAULT_JOY_HOME, - dest='joy_home', - type=home_dir, - ) - - -class FileFaker(object): - - def __init__(self, T): - self.T = T - - def write(self, text): - self.T.insert('end', text) - self.T.see('end') - - def flush(self): - pass diff --git a/joy/gui/world.py b/joy/gui/world.py deleted file mode 100644 index 4712f86..0000000 --- a/joy/gui/world.py +++ /dev/null @@ -1,173 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2014, 2015 Simon Forman -# -# This file is part of joy.py -# -# joy.py is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# joy.py is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with joy.py. If not see . -# -from __future__ import print_function -from builtins import object -from logging import getLogger - -_log = getLogger(__name__) - -import os, pickle, sys -from inspect import getdoc - -from joy.joy import run -from joy.library import HELP_TEMPLATE -from joy.parser import Symbol -from joy.utils.stack import stack_to_string -from joy.utils.types import type_check -from .utils import is_numerical - - -class World(object): - - def __init__(self, stack=(), dictionary=None, text_widget=None): - self.stack = stack - self.dictionary = dictionary or {} - self.text_widget = text_widget - self.check_cache = {} - - def check(self, name): - try: - res = self.check_cache[name] - except KeyError: - res = self.check_cache[name] = type_check(name, self.stack) - return res - - def do_lookup(self, name): - if name in self.dictionary: - self.stack = (Symbol(name), ()), self.stack - self.print_stack() - self.check_cache.clear() - else: - assert is_numerical(name) - self.interpret(name) - - def do_opendoc(self, name): - if is_numerical(name): - doc = 'The number ' + str(name) - else: - try: - word = self.dictionary[name] - except KeyError: - doc = 'Unknown: ' + repr(name) - else: - doc = getdoc(word) - print(HELP_TEMPLATE % (name, doc, name)) - self.print_stack() - - def pop(self): - if self.stack: - self.stack = self.stack[1] - self.print_stack() - self.check_cache.clear() - - def push(self, it): - it = it.encode('utf8') - self.stack = it, self.stack - self.print_stack() - self.check_cache.clear() - - def peek(self): - if self.stack: - return self.stack[0] - - def interpret(self, command): - if self.has(command) and self.check(command) == False: # not in {True, None}: - return - old_stack = self.stack - try: - self.stack, _, self.dictionary = run( - command, - self.stack, - self.dictionary, - ) - finally: - self.print_stack() - if old_stack != self.stack: - self.check_cache.clear() - - def has(self, name): - return name in self.dictionary - - def save(self): - pass - - def print_stack(self): - stack_out_index = self.text_widget.search('<' 'STACK', 1.0) - if stack_out_index: - self.text_widget.see(stack_out_index) - s = stack_to_string(self.stack) + '\n' - self.text_widget.insert(stack_out_index, s) - - -class StackDisplayWorld(World): - - def __init__(self, repo, filename, rel_filename, dictionary=None, text_widget=None): - self.filename = filename - stack = self.load_stack() or () - World.__init__(self, stack, dictionary, text_widget) - self.repo = repo - self.relative_STACK_FN = rel_filename - - def interpret(self, command): - command = command.strip() - if self.has(command) and self.check(command) == False: # not in {True, None}: - return - # print('\njoy?', command) - self.print_command(command) - super(StackDisplayWorld, self).interpret(command) - - def print_command(self, command): - print(command) - - def print_stack(self): - print('\n%s <-' % stack_to_string(self.stack)) - - def save(self): - with open(self.filename, 'wb') as f: - os.chmod(self.filename, 0o600) - pickle.dump(self.stack, f, protocol=2) - f.flush() - os.fsync(f.fileno()) - self.repo.stage([self.relative_STACK_FN]) - commit_id = self.repo.do_commit( - b'auto-save', - committer=b'thun-auto-save ', - ) - _log.info('commit %s', commit_id) - - def load_stack(self): - if os.path.exists(self.filename): - with open(self.filename, 'rb') as f: - return pickle.load(f) - - -class StackWorld(StackDisplayWorld): - - viewer = None - - def set_viewer(self, viewer): - self.viewer = viewer - self.viewer.update_stack(self.stack) - - def print_stack(self): - print(stack_to_string(self.stack), '•', end=' ') - if self.viewer: - self.viewer.update_stack(self.stack) - diff --git a/joy/utils/brutal_hackery.py b/joy/utils/brutal_hackery.py deleted file mode 100644 index 85fb05b..0000000 --- a/joy/utils/brutal_hackery.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2018 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# -''' -I really want tracebacks to show which function was being executed when -an error in the wrapper function happens. In order to do that, you have -to do this (the function in this module.) - -Here's what it looks like when you pass too few arguments to e.g. "mul". - - >>> from joy.library import _dictionary - >>> m = _dictionary['*'] - >>> m((), (), {}) - - Traceback (most recent call last): - File "", line 1, in - m((), (), {}) - File "joy/library.py", line 185, in mul:inner - (a, (b, stack)) = stack - ValueError: need more than 0 values to unpack - >>> - - -Notice that line 185 in the library.py file is (as of this writing) in -the BinaryBuiltinWrapper's inner() function, but this hacky code has -managed to insert the name of the wrapped function ("mul") along with a -colon into the wrapper function's reported name. - -Normally I would frown on this sort of mad hackery, but... this is in -the service of ease-of-debugging! Very valuable. And note that all the -hideous patching is finished in the module-load-stage, it shouldn't cause -issues of its own at runtime. - -The main problem I see with this is that people coming to this code later -might be mystified if they just see a traceback with a ':' in the -function name! Hopefully they will discover this documentation. -''' - - -def rename_code_object(new_name): - ''' - If you want to wrap a function in another function and have the wrapped - function's name show up in the traceback when an exception occurs in - the wrapper function, you must do this brutal hackery to change the - func.__code__.co_name attribute. Just functools.wraps() is not enough. - - See: - - https://stackoverflow.com/questions/29919804/function-decorated-using-functools-wraps-raises-typeerror-with-the-name-of-the-w - - https://stackoverflow.com/questions/29488327/changing-the-name-of-a-generator/29488561#29488561 - - I'm just glad it's possible. - ''' - def inner(func): - name = new_name + ':' + func.__name__ - code_object = func.__code__ - return type(func)( - type(code_object)( - code_object.co_argcount, - code_object.co_nlocals, - code_object.co_stacksize, - code_object.co_flags, - code_object.co_code, - code_object.co_consts, - code_object.co_names, - code_object.co_varnames, - code_object.co_filename, - name, - code_object.co_firstlineno, - code_object.co_lnotab, - code_object.co_freevars, - code_object.co_cellvars - ), - func.__globals__, - name, - func.__defaults__, - func.__closure__ - ) - return inner diff --git a/joy/utils/compiler.py b/joy/utils/compiler.py deleted file mode 100644 index de442d8..0000000 --- a/joy/utils/compiler.py +++ /dev/null @@ -1,241 +0,0 @@ -''' -A crude compiler for a subset of Joy functions. - -I think I'm going about this the wrong way. - -The inference algorithm can "collapse" Yin function sequences into -single stack effects which can then be written out as Python functions. -Why not keep track of the new variables introduced as results of Yang -functions, during inference? Could I write out better code that way? - -In any event, I am proceeding with this sort of ad hoc way for now. -''' -from __future__ import print_function -from builtins import next -from builtins import str -from builtins import object -from joy.parser import text_to_expression, Symbol -from joy.utils.stack import concat, iter_stack, list_to_stack -from joy.library import SimpleFunctionWrapper, YIN_STACK_EFFECTS -from functools import reduce - - -def import_yin(): - from joy.utils.generated_library import * - return locals() - - -class InfiniteStack(tuple): - - def _names(): - n = 0 - while True: - m = yield Symbol('a' + str(n)) - n = n + 1 if m is None else m - - _NAMES = _names() - next(_NAMES) - - names = lambda: next(_NAMES) - reset = lambda _self, _n=_NAMES: _n.send(-1) - - def __init__(self, code): - self.reset() - self.code = code - - def __iter__(self): - if not self: - new_var = self.names() - self.code.append(('pop', new_var)) - return iter((new_var, self)) - - -def I(expression): - code = [] - stack = InfiniteStack(code) - - while expression: - term, expression = expression - if isinstance(term, Symbol): - func = D[term] - stack, expression, _ = func(stack, expression, code) - else: - stack = term, stack - - code.append(tuple(['ret'] + list(iter_stack(stack)))) - return code - - -strtup = lambda a, b: '(%s, %s)' % (b, a) -strstk = lambda rest: reduce(strtup, rest, 'stack') - - -def code_gen(code): - #for p in code: print p - coalesce_pops(code) - lines = [] - emit = lines.append - for t in code: - tag, rest = t[0], t[1:] - if tag == 'pop': emit(strstk(rest) + ' = stack') - elif tag == 'call': emit('%s = %s%s' % rest) - elif tag == 'ret': emit('return ' + strstk(rest[::-1])) - else: - raise ValueError(tag) - return '\n'.join(' ' + line for line in lines) - - -def coalesce_pops(code): - code.sort(key=lambda p: p[0] != 'pop') # All pops to the front. - try: index = next((i for i, t in enumerate(code) if t[0] != 'pop')) - except StopIteration: return - code[:index] = [tuple(['pop'] + [t for _, t in code[:index][::-1]])] - - -def compile_yinyang(name, text): - return ''' -def %s(stack): -%s -''' % (name, code_gen(I(text_to_expression(text)))) - - -def q(): - memo = {} - def bar(type_var): - try: - res = memo[type_var] - except KeyError: - res = memo[type_var] = InfiniteStack.names() - return res - return bar - - -def type_vars_to_labels(thing, map_): - if not thing: - return thing - if not isinstance(thing, tuple): - return map_(thing) - return tuple(type_vars_to_labels(inner, map_) for inner in thing) - - -def remap_inputs(in_, stack, code): - map_ = q() - while in_: - term, in_ = in_ - arg0, stack = stack - term = type_vars_to_labels(term, map_) - code.append(('call', term, '', arg0)) - return stack, map_ - - -class BinaryBuiltin(object): - - def __init__(self, name): - self.name = name - - def __call__(self, stack, expression, code): - in1, (in0, stack) = stack - out = InfiniteStack.names() - code.append(('call', out, self.name, (in0, in1))) - return (out, stack), expression, code - - -YIN = import_yin() - - -D = { - name: SimpleFunctionWrapper(YIN[name]) - for name in ''' - ccons - cons - dup - dupd - dupdd - over - pop - popd - popdd - popop - popopd - popopdd - rolldown - rollup - swap - swons - tuck - unit - '''.split() - } - - -for name in ''' - first - first_two - fourth - rest - rrest - second - third - uncons - unswons - '''.split(): - - def foo(stack, expression, code, name=name): - in_, out = YIN_STACK_EFFECTS[name] - stack, map_ = remap_inputs(in_, stack, code) - out = type_vars_to_labels(out, map_) - return concat(out, stack), expression, code - - foo.__name__ = name - D[name] = foo - - -for name in ''' - eq - ge - gt - le - lt - ne - xor - lshift - rshift - and_ - or_ - add - floordiv - mod - mul - pow - sub - truediv - '''.split(): - D[name.rstrip('-')] = BinaryBuiltin(name) - - -''' - stack - stuncons - stununcons - swaack -''' - -for name in sorted(D): - print(name, end=' ') -## print compile_yinyang(name, name) -print('-' * 100) - - -print(compile_yinyang('mul_', 'mul')) -print(compile_yinyang('pop', 'pop')) -print(compile_yinyang('ppm', 'popop mul')) -print(compile_yinyang('sqr', 'dup mul')) -print(compile_yinyang('foo', 'dup 23 sub mul')) -print(compile_yinyang('four_mul', 'mul mul mul mul')) -print(compile_yinyang('baz', 'mul dup sub dup')) -print(compile_yinyang('to_the_fifth_power', 'dup dup mul dup mul mul')) -print(compile_yinyang('dup3', 'dup dup dup')) -print(compile_yinyang('df2m', 'dup first_two mul')) -print(compile_yinyang('sqr_first', 'uncons swap dup mul swons')) -print(compile_yinyang('0BAD', 'uncons dup mul')) -print(compile_yinyang('uncons', 'uncons')) diff --git a/joy/utils/generated_library.py b/joy/utils/generated_library.py index 08c9285..8a4acbc 100644 --- a/joy/utils/generated_library.py +++ b/joy/utils/generated_library.py @@ -1,4 +1,6 @@ # GENERATED FILE. DO NOT EDIT. +# The code that generated these functions is in the repo history +# at the v0.4.0 tag. def _Tree_add_Ee(stack): diff --git a/joy/utils/infinite_stack.py b/joy/utils/infinite_stack.py deleted file mode 100644 index 3697939..0000000 --- a/joy/utils/infinite_stack.py +++ /dev/null @@ -1,31 +0,0 @@ -from builtins import str -from joy.parser import Symbol - - -def _names(): - n = 0 - while True: - yield Symbol('a' + str(n)) - n += 1 - - -class InfiniteStack(tuple): - - names = lambda n=_names(): next(n) - - def __iter__(self): - if not self: - return iter((self.names(), self)) - - -i = InfiniteStack() - -a, b = i - -lambda u: (lambda fu, u: fu * fu * u)( - (lambda u: (lambda fu, u: fu * fu)( - (lambda u: (lambda fu, u: fu * fu * u)( - (lambda u: 1)(u), u))(u), u))(u), - u) - -lambda u: (lambda fu, u: fu * fu * u)((lambda u: (lambda fu, u: fu * fu)((lambda u: (lambda fu, u: fu * fu * u)((lambda u: 1)(u), u))(u), u))(u), u) diff --git a/joy/utils/types.py b/joy/utils/types.py deleted file mode 100644 index c22cc3b..0000000 --- a/joy/utils/types.py +++ /dev/null @@ -1,756 +0,0 @@ -# -*- coding: utf_8 -# -# Copyright © 2018 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# -from __future__ import print_function -from builtins import str -from builtins import map -from past.builtins import basestring -from builtins import object -from logging import getLogger, addLevelName -from functools import reduce - -_log = getLogger(__name__) -addLevelName(15, 'hmm') - -from collections import Counter -from itertools import chain, product -from inspect import stack as inspect_stack -from joy.utils.stack import ( - concat, - expression_to_string, - list_to_stack, - stack_to_string, - ) -from joy.parser import Symbol, text_to_expression - - -class AnyJoyType(object): - ''' - Joy type variable. Represents any Joy value. - ''' - - accept = tuple, int, float, int, complex, str, bool, Symbol - prefix = 'a' - - def __init__(self, number): - self.number = number - - def __repr__(self): - return self.prefix + str(self.number) - - def __eq__(self, other): - return ( - isinstance(other, self.__class__) - and other.prefix == self.prefix - and other.number == self.number - ) - - def __ge__(self, other): - return ( - issubclass(other.__class__, self.__class__) - or isinstance(other, self.accept) - ) - - def __le__(self, other): - # 'a string' >= AnyJoyType() should be False. - return issubclass(self.__class__, other.__class__) - - def __add__(self, other): - return self.__class__(self.number + other) - __radd__ = __add__ - - def __hash__(self): - return hash(repr(self)) - - -class BooleanJoyType(AnyJoyType): - accept = bool - prefix = 'b' - - -class NumberJoyType(AnyJoyType): - accept = bool, int, float, complex - prefix = 'n' - - -class FloatJoyType(NumberJoyType): - accept = float - prefix = 'f' - - -class IntJoyType(FloatJoyType): - accept = int - prefix = 'i' - - -class TextJoyType(AnyJoyType): - accept = basestring - prefix = 't' - - -class StackJoyType(AnyJoyType): - - accept = tuple - prefix = 's' - - def __bool__(self): - # Imitate () at the end of cons list. - return False - - -class KleeneStar(object): - u''' - A sequence of zero or more `AnyJoyType` variables would be: - - A* - - The `A*` works by splitting the universe into two alternate histories: - - A* → ∅ - - A* → A A* - - The Kleene star variable disappears in one universe, and in the other - it turns into an `AnyJoyType` variable followed by itself again. - - We have to return all universes (represented by their substitution - dicts, the "unifiers") that don't lead to type conflicts. - ''' - - kind = AnyJoyType - - def __init__(self, number): - assert number - self.number = number - self.count = 0 - self.prefix = repr(self) - - def __repr__(self): - return '%s%i*' % (self.kind.prefix, self.number) - - def another(self): - self.count += 1 - return self.kind(10000 * self.number + self.count) - - def __eq__(self, other): - return ( - isinstance(other, self.__class__) - and other.number == self.number - ) - - def __ge__(self, other): - return self.kind >= other.kind - - def __add__(self, other): - return self.__class__(self.number + other) - __radd__ = __add__ - - def __hash__(self): - return hash(repr(self)) - - -class AnyStarJoyType(KleeneStar): kind = AnyJoyType -class NumberStarJoyType(KleeneStar): kind = NumberJoyType -class FloatStarJoyType(KleeneStar): kind = FloatJoyType -class IntStarJoyType(KleeneStar): kind = IntJoyType -class StackStarJoyType(KleeneStar): kind = StackJoyType -class TextStarJoyType(KleeneStar): kind = TextJoyType - - -class FunctionJoyType(AnyJoyType): - - def __init__(self, name, sec, number): - self.name = name - self.stack_effects = sec - self.number = number - - def __add__(self, other): - return self - __radd__ = __add__ - - def __repr__(self): - return self.name - - -class SymbolJoyType(FunctionJoyType): - ''' - Represent non-combinator functions. - - These type variables carry the stack effect comments and can - appear in expressions (as in quoted programs.) - ''' - prefix = 'F' - - -class CombinatorJoyType(FunctionJoyType): - ''' - Represent combinators. - - These type variables carry Joy functions that implement the - behaviour of Joy combinators and they can appear in expressions. - For simple combinators the implementation functions can be the - combinators themselves. - - These types can also specify a stack effect (input side only) to - guard against being used on invalid types. - ''' - - prefix = 'C' - - def __init__(self, name, sec, number, expect=None): - super(CombinatorJoyType, self).__init__(name, sec, number) - self.expect = expect - - def enter_guard(self, f): - if self.expect is None: - return f - g = self.expect, self.expect - new_f = list(poly_compose(f, g, ())) - assert len(new_f) == 1, repr(new_f) - return new_f[0][1] - - -class JoyTypeError(Exception): pass - - -def reify(meaning, name, seen=None): - ''' - Apply substitution dict to term, returning new term. - ''' - if isinstance(name, tuple): - return tuple(reify(meaning, inner) for inner in name) - safety = 101 - while name in meaning and safety: - safety -= 1 - name = meaning[name] - if not safety: - raise ValueError('Cycle in substitution dict: %s' % (meaning,)) - return name - - -def relabel(left, right): - ''' - Re-number type variables to avoid collisions between stack effects. - ''' - return left, _1000(right) - - -def _1000(right): - if isinstance(right, Symbol): - return right - if not isinstance(right, tuple): - return 1000 + right - return tuple(_1000(n) for n in right) - - -def delabel(f, seen=None, c=None): - ''' - Fix up type variable numbers after relabel(). - ''' - if seen is None: - assert c is None - seen, c = {}, Counter() - - try: - return seen[f] - except KeyError: - pass - - if not isinstance(f, tuple): - try: - seen[f] = f.__class__(c[f.prefix] + 1) - except (TypeError, # FunctionJoyTypes break this. - AttributeError): # Symbol - seen[f] = f - else: - c[f.prefix] += 1 - return seen[f] - - return tuple(delabel(inner, seen, c) for inner in f) - - -def uni_unify(u, v, s=None): - ''' - Return a substitution dict representing a unifier for u and v. - ''' - if s is None: - s = {} - elif s: - u = reify(s, u) - v = reify(s, v) - - if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType): - if u >= v: - s[u] = v - elif v >= u: - s[v] = u - else: - raise JoyTypeError('Cannot unify %r and %r.' % (u, v)) - - elif isinstance(u, tuple) and isinstance(v, tuple): - if len(u) != len(v) != 2: - raise ValueError(repr((u, v))) # Bad input. - (a, b), (c, d) = u, v - s = uni_unify(b, d, uni_unify(a, c, s)) - - elif isinstance(v, tuple): - if not _stacky(u): - raise JoyTypeError('Cannot unify %r and %r.' % (u, v)) - s[u] = v - - elif isinstance(u, tuple): - if not _stacky(v): - raise JoyTypeError('Cannot unify %r and %r.' % (v, u)) - s[v] = u - - else: - raise JoyTypeError('Cannot unify %r and %r.' % (u, v)) - - return s - - -def _log_uni(U): - def inner(u, v, s=None): - _log.debug( - '%3i %s U %s w/ %s', - len(inspect_stack()), u, v, s, - ) - res = U(u, v, s) - _log.debug( - '%3i %s U %s w/ %s => %s', - len(inspect_stack()), u, v, s, res, - ) - return res - return inner - - -@_log_uni -def unify(u, v, s=None): - ''' - Return a tuple of substitution dicts representing unifiers for u and v. - ''' - if s is None: - s = {} - elif s: - u = reify(s, u) - v = reify(s, v) - - if u == v: - res = s, - - elif isinstance(u, tuple) and isinstance(v, tuple): - if len(u) != 2 or len(v) != 2: - if _that_one_special_case(u, v): - return s, - raise ValueError(repr((u, v))) # Bad input. - - - (a, b), (c, d) = v, u - if isinstance(a, KleeneStar): - if isinstance(c, KleeneStar): - s = _lil_uni(a, c, s) # Attempt to unify the two K-stars. - res = unify(d, b, s[0]) - - else: - # Two universes, in one the Kleene star disappears and - # unification continues without it... - s0 = unify(u, b) - - # In the other it spawns a new variable. - s1 = unify(u, (a.another(), v)) - - res = s0 + s1 - for sn in res: - sn.update(s) - - elif isinstance(c, KleeneStar): - res = unify(v, d) + unify(v, (c.another(), u)) - for sn in res: - sn.update(s) - - else: - res = tuple(flatten(unify(d, b, sn) for sn in unify(c, a, s))) - - elif isinstance(v, tuple): - if not _stacky(u): - raise JoyTypeError('Cannot unify %r and %r.' % (u, v)) - s[u] = v - res = s, - - elif isinstance(u, tuple): - if not _stacky(v): - raise JoyTypeError('Cannot unify %r and %r.' % (v, u)) - s[v] = u - res = s, - - else: - res = _lil_uni(u, v, s) - - return res - - -def _that_one_special_case(u, v): - ''' - Handle e.g. ((), (n1*, s1)) when type-checking sum, product, etc... - ''' - return ( - u == () - and len(v) == 2 - and isinstance(v[0], KleeneStar) - and isinstance(v[1], StackJoyType) - ) - - -def flatten(g): - return list(chain.from_iterable(g)) - - -def _lil_uni(u, v, s): - if u >= v: - s[u] = v - return s, - if v >= u: - s[v] = u - return s, - raise JoyTypeError('Cannot unify %r and %r.' % (u, v)) - - -def _stacky(thing): - return thing.__class__ in {AnyJoyType, StackJoyType} - - -def _compose(f, g): - ''' - Return the stack effect of the composition of two stack effects. - ''' - # Relabel, unify, update, delabel. - (f_in, f_out), (g_in, g_out) = relabel(f, g) - fg = reify(uni_unify(g_in, f_out), (f_in, g_out)) - return delabel(fg) - - -def compose(*functions): - ''' - Return the stack effect of the composition of some of stack effects. - ''' - return reduce(_compose, functions) - - -def compilable(f): - ''' - Return True if a stack effect represents a function that can be - automatically compiled (to Python), False otherwise. - ''' - return isinstance(f, tuple) and all(map(compilable, f)) or _stacky(f) - - -def doc_from_stack_effect(inputs, outputs=('??', ())): - ''' - Return a crude string representation of a stack effect. - ''' - switch = [False] # Do we need to display the '...' for the rest of the main stack? - i, o = _f(inputs, switch), _f(outputs, switch) - if switch[0]: - i.append('...') - o.append('...') - return '(%s--%s)' % ( - ' '.join(reversed([''] + i)), - ' '.join(reversed(o + [''])), - ) - - -def _f(term, switch): - a = [] - while term and isinstance(term, tuple): - item, term = term - a.append(item) - assert isinstance(term, (tuple, StackJoyType)), repr(term) - a = [_to_str(i, term, switch) for i in a] - return a - - -def _to_str(term, stack, switch): - if not isinstance(term, tuple): - if term == stack: - switch[0] = True - return '[...]' - return ( - '[...%i]' % term.number - if isinstance(term, StackJoyType) - else str(term) - ) - - a = [] - while term and isinstance(term, tuple): - item, term = term - a.append(_to_str(item, stack, switch)) - assert isinstance(term, (tuple, StackJoyType)), repr(term) - if term == stack: - switch[0] = True - end = '' if term == () else '...' - #end = '...' - else: - end = '' if term == () else '...%i' % term.number - a.append(end) - return '[%s]' % ' '.join(a) - - -def compile_(name, f, doc=None): - ''' - Return a string of Python code implementing the function described - by the stack effect. If no doc string is passed doc_from_stack_effect() - is used to generate one. - ''' - i, o = f - if doc is None: - doc = doc_from_stack_effect(i, o) - return '''def %s(stack): - """ - :: - - %s - - """ - %s = stack - return %s''' % (name, doc, i, o) - - -def _poly_compose(f, g, e): - (f_in, f_out), (g_in, g_out) = f, g - for s in unify(g_in, f_out): - yield reify(s, (e, (f_in, g_out))) - - -def poly_compose(f, g, e): - ''' - Yield the stack effects of the composition of two stack effects. An - expression is carried along and updated and yielded. - ''' - f, g = relabel(f, g) - for fg in _poly_compose(f, g, e): - yield delabel(fg) - - -def _meta_compose(F, G, e): - for f, g in product(F, G): - try: - for result in poly_compose(f, g, e): yield result - except JoyTypeError: - pass - - -def meta_compose(F, G, e): - ''' - Yield the stack effects of the composition of two lists of stack - effects. An expression is carried along and updated and yielded. - ''' - res = sorted(set(_meta_compose(F, G, e))) - if not res: - raise JoyTypeError('Cannot unify %r and %r.' % (F, G)) - return res - - -_S0 = StackJoyType(0) -ID = _S0, _S0 # Identity function. - - -def _infer(e, F=ID): - if __debug__: - _log_it(e, F) - if not e: - return [F] - - n, e = e - - if isinstance(n, SymbolJoyType): - eFG = meta_compose([F], n.stack_effects, e) - res = flatten(_infer(e, Fn) for e, Fn in eFG) - - elif isinstance(n, CombinatorJoyType): - fi, fo = n.enter_guard(F) - res = flatten(_interpret(f, fi, fo, e) for f in n.stack_effects) - - elif isinstance(n, Symbol): - if n in FUNCTIONS: - res =_infer((FUNCTIONS[n], e), F) - else: - raise JoyTypeError(n) - # print n - # func = joy.library._dictionary[n] - # res = _interpret(func, F[0], F[1], e) - - else: - fi, fo = F - res = _infer(e, (fi, (n, fo))) - - return res - - -def _interpret(f, fi, fo, e): - new_fo, ee, _ = f(fo, e, {}) - ee = reify(FUNCTIONS, ee) # Fix Symbols. - new_F = fi, new_fo - return _infer(ee, new_F) - - -def _log_it(e, F): - _log.log( - 15, - u'%3i %s ∘ %s', - len(inspect_stack()), - doc_from_stack_effect(*F), - expression_to_string(e), - ) - - -def infer(*expression): - ''' - Return a list of stack effects for a Joy expression. - - For example:: - - h = infer(pop, swap, rolldown, rest, rest, cons, cons) - for fi, fo in h: - print doc_from_stack_effect(fi, fo) - - Prints:: - - ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) - - ''' - return sorted(set(_infer(list_to_stack(expression)))) - - -def infer_string(string): - e = reify(FUNCTIONS, text_to_expression(string)) # Fix Symbols. - return sorted(set(_infer(e))) - - -def infer_expression(expression): - e = reify(FUNCTIONS, expression) # Fix Symbols. - return sorted(set(_infer(e))) - - -def type_check(name, stack): - ''' - Trinary predicate. True if named function type-checks, False if it - fails, None if it's indeterminate (because I haven't entered it into - the FUNCTIONS dict yet.) - ''' - try: - func = FUNCTIONS[name] - except KeyError: - return # None, indicating unknown - if isinstance(func, SymbolJoyType): - secs = func.stack_effects - elif isinstance(func, CombinatorJoyType): - if func.expect is None: - return # None, indicating unknown - secs = [(func.expect, ())] - else: - raise TypeError(repr(func)) # wtf? - for fi, fo in secs: - try: - unify(fi, stack) - except (JoyTypeError, ValueError): - continue - except: - _log.exception( - 'Type-checking %s %s against %s', - name, - doc_from_stack_effect(fi, fo), - stack_to_string(stack), - ) - continue - return True - return False - - -FUNCTIONS = {} # Polytypes (lists of stack effects.) -_functions = {} # plain ol' stack effects. - - -def __(*seq): - stack = StackJoyType(23) - for item in seq: stack = item, stack - return stack - - -def stack_effect(*inputs): - def _stack_effect(*outputs): - def _apply_to(function): - i, o = _functions[function.name] = __(*inputs), __(*outputs) - d = doc_from_stack_effect(i, o) - function.__doc__ += ( - '\nStack effect::\n\n ' # '::' for Sphinx docs. - + d - ) - _log.info('Setting stack effect for %s := %s', function.name, d) - return function - return _apply_to - return _stack_effect - - -def ef(*inputs): - def _ef(*outputs): - return __(*inputs), __(*outputs) - return _ef - - -def combinator_effect(number, *expect): - def _combinator_effect(c): - e = __(*expect) if expect else None - FUNCTIONS[c.name] = CombinatorJoyType(c.name, [c], number, e) - if e: - sec = doc_from_stack_effect(e) - _log.info('Setting stack EXPECT for combinator %s := %s', c.name, sec) - return c - return _combinator_effect - - -def show(DEFS): - for name, stack_effect_comment in sorted(DEFS.items()): - t = ' *'[compilable(stack_effect_comment)] - print(name, '=', doc_from_stack_effect(*stack_effect_comment), t) - - -def generate_library_code(DEFS, f=None): - if f is None: - import sys - f = sys.stdout - print('# GENERATED FILE. DO NOT EDIT.\n', file=f) - for name, stack_effect_comment in sorted(DEFS.items()): - if not compilable(stack_effect_comment): - continue - print(file=f) - print(compile_(name, stack_effect_comment), file=f) - print(file=f) - - -def poly_combinator_effect(number, effect_funcs, *expect): - def _poly_combinator_effect(c): - e = __(*expect) if expect else None - FUNCTIONS[c.name] = CombinatorJoyType(c.name, effect_funcs, number, e) - if e: - _log.info('Setting stack EXPECT for combinator %s := %s', c.name, e) - return c - return _poly_combinator_effect - -#FUNCTIONS['branch'].expect = s7, (s6, (b1, s5)) - diff --git a/joy/vui/Iosevka12.BMP b/joy/vui/Iosevka12.BMP deleted file mode 100644 index 755eca1..0000000 Binary files a/joy/vui/Iosevka12.BMP and /dev/null differ diff --git a/joy/vui/README.txt b/joy/vui/README.txt deleted file mode 100644 index 8451dda..0000000 --- a/joy/vui/README.txt +++ /dev/null @@ -1,163 +0,0 @@ -What is it? - -A simple Graphical User Interface for the Joy programming language, -written using Pygame to bypass X11 et. al., modeled on the Oberon OS, and -intended to be just functional enough to support bootstrapping further Joy -development. - -It's basic functionality is more-or-less as a crude text editor along with -a simple Joy runtime (interpreter, stack, and dictionary.) It auto- saves -any named files (in a versioned home directory) and you can write new Joy -primitives in Python and Joy definitions and immediately install and use -them, as well as recording them for reuse (after restarts.) - -How it works now. - -The only dependencies are Pygame and Dulwich (a Python Git library.) - -When the main.py script starts it checks for an environment var "JOY_HOME" -which should point to a directory where you want the system to store the -files ("resources") it will edit and save, this directory defaults to -'~/.joypy'. The first time you run it, it will create some default files -as content. Right click on see_resources to open a viewer with the list -of resources (files), copy a name to the stack and right click on -open_resource_at_good_location to open a viewer on that resource. - -Right now the screen size defaults to windowed 1024x768, but if you pass -the '-f' option to the main.py script the UI will take up the full screen -at the highest available resolution. The window is divided into two (or -three in fullscreen) vertical "tracks", and the number and width of the -tracks are fixed at start up. (Feel free to edit the values in main.py to -play around with different track configurations.) Each track gets divided -horizontally into zero or more "viewers" (like windows in a windowed GUI, -cf. Chapter 4 of "Project Oberon") for a kind of tiled layout. - -Currently, there are only two kinds of (interesting) viewers: TextViewers -and StackViewer. The TextViewers are crude text editors. They provide -just enough functionality to let the user write text and code (Python and -Joy) and execute Joy functions. One important thing they do is -automatically save their content after changes. No more lost work. - -The StackViewer is a specialized TextViewer that shows the contents of the -Joy stack one line per stack item. It's a very handy visual aid to keep -track of what's going on. There's also a log.txt file that gets written -to when commands are executed, and so records the log of user actions and -system events. It tends to fill up quickly so there's a reset_log command -that clears it out. - -Viewers have "grow" and "close" in their menu bars. These are buttons. -When you right-click on grow a viewer a copy is created that covers that -viewer's entire track. If you grow a viewer that already takes up its -whole track then a copy is created that takes up an additional track, up -to the whole screen. Closing a viewer just deletes that viewer, and when -a track has no more viewers, it is deleted and that exposes any previous -tracks and viewers that were hidden. - -(Note: if you ever close all the viewers and are sitting at a blank screen -with nowhere to type and execute commands, press the Pause/Break key. -This will open a new "trap" viewer which you can then use to recover.) - -Copies of a viewer all share the same model and update their display as it -changes. (If you have two viewers open on the same named resource and edit -one you'll see the other update as you type.) - -UI Guide - -left mouse sets cursor in text, in menu bar resizes viewer interactively -(this is a little buggy in that you can move the mouse quickly and get -outside the menu, leaving the viewer in the "resizing" state. Until I fix -this, the workaround is to just grab the menu bar again and wiggle it a -few pixels and let go. This will reset the machinery.) - -Right mouse executes Joy command (functions), and you can drag with the -right button to highlight (well, underline) commands. Words that aren't -names of Joy commands won't be underlined. Release the button to execute -the command. - -The middle mouse button (usually a wheel these days) scrolls the text but -you can also click and drag any viewer with it to move that viewer to -another track or to a different location in the same track. There's no -direct visual feedback for this (yet) but that dosen't seem to impair its -usefulness. - -F1, F2 - set selection begin and end markers (crude but usable.) - -F3 - copy selected text to the top of the stack. - -Shift-F3 - as copy then run "parse" command on the string. - -F4 - cut selected text to the top of the stack. - -Shift-F4 - as cut then run "pop" (delete selection.) - -Joy - -Pretty much all of the rest of the functionality of the system is provided -by executing Joy commands (aka functions, aka "words" in Forth) by right- -clicking on their names in any text. - -To get help on a Joy function select the name of the function in a -TextViewer using F1 and F2, then press shift-F3 to parse the selection. -The function (really its Symbol) will appear on the stack in brackets (a -"quoted program" such as "[pop]".) Then right-click on the word help in -any TextViewer (if it's not already there, just type it in somewhere.) -This will print the docstring or definition of the word (function) to -stdout. At some point I'll write a thing to send that to the log.txt file -instead, but for now look for output in the terminal. - -I have pre-defined some system-specific commands, like see_stack to open a -StackViewer, and I should really go and add docstrings to those (so they -work with the help command.) - -... inscribe and evaluate for making new Joy and Python, respectively, -commands... - ----- - - -Still to do: -* Return key can orphan a line at the bottom of a viewer. -* Calculator buttons on the numpad? -* System query for most recent selection -* Home/End keys -* Vertical scrolling w/ scrollbar? -* Shift-scroll changes viewer height? -* Horizontal scrolling w/ keys -* Horizontal scrolling w/ scrollbar? -* Pgup/down keys? -* Tab key? -* When moving viewers sometimes a command gets executed from the underlying - viewer. This shouldn't happen. - -Done: -- Redirect stdout to "print" to the log. -- Initial contents for JOY_HOME. -- Pause/Break to open a trap viewer (in case you close them all.) -- "shutdown" signal to tell PT to commit outstanding changes. -- Local library auto-loaded at start-time - - library.py, primitives in Python - - definitions.txt -- Can name and persist a viewer on an unstored string(list). -- Inscribe function -- Reverse video, well, grey background, menu bars -- PT scans JOY_HOME for resource lists -- Capture and display tracebacks -- StackViewer -- Update log when stack changes -- Open a resource list -- Open a viewer on a (unstored) string -- Selecting text -- Copy and Cut -- Paste -- Menu text, commands and name or title -- "print" to e.g. log -- Command evaluation -- Joy integration -- Persistance of data -- Content change notification -- Vertical scrolling w/ keys -- Vertical scrolling w/ mouse wheel -- Enter/return key -- Arrow keys wrap at line ends -- Backspace/delete wrap at line ends - diff --git a/joy/vui/__init__.py b/joy/vui/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/joy/vui/__main__.py b/joy/vui/__main__.py deleted file mode 100644 index 4e027c3..0000000 --- a/joy/vui/__main__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2019 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# - -import joy.vui.main - - -joy.vui.main.main(*joy.vui.main.init()) diff --git a/joy/vui/core.py b/joy/vui/core.py deleted file mode 100644 index ca61961..0000000 --- a/joy/vui/core.py +++ /dev/null @@ -1,282 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2019 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# -''' - -Core -===================== - -The core module defines a bunch of system-wide "constants" (some colors -and PyGame event groups), the message classes for Oberon-style message -passing, a "world" class that holds the main context for the system, and -a mainloop class that manages the, uh, main loop (the PyGame event queue.) - -''' -from __future__ import print_function -from builtins import object, str, range -from sys import stderr -from traceback import format_exc -import pygame -from joy.joy import run -from joy.utils.stack import stack_to_string - - -COMMITTER = 'Joy ' - - -BLACK = FOREGROUND = 0, 0, 0 -GREY = 127, 127, 127 -WHITE = BACKGROUND = 255, 255, 255 -BLUE = 100, 100, 255 -GREEN = 70, 200, 70 - - -MOUSE_EVENTS = frozenset({ - pygame.MOUSEMOTION, - pygame.MOUSEBUTTONDOWN, - pygame.MOUSEBUTTONUP - }) -'PyGame mouse events.' - -ARROW_KEYS = frozenset({ - pygame.K_UP, - pygame.K_DOWN, - pygame.K_LEFT, - pygame.K_RIGHT - }) -'PyGame arrow key events.' - - -TASK_EVENTS = tuple(range(pygame.USEREVENT, pygame.NUMEVENTS)) -'Keep track of all possible task events.' - -AVAILABLE_TASK_EVENTS = set(TASK_EVENTS) -'Task IDs that have not been assigned to a task.' - -ALLOWED_EVENTS = [pygame.QUIT, pygame.KEYUP, pygame.KEYDOWN] -ALLOWED_EVENTS.extend(MOUSE_EVENTS) -ALLOWED_EVENTS.extend(TASK_EVENTS) -'Event "mask" for PyGame event queue, we are only interested in these event types.' - - -ERROR = -1 -PENDING = 0 -SUCCESS = 1 -# 'Message status codes... dunno if this is a good idea or not... - - -class Message(object): - '''Message base class. Contains ``sender`` field.''' - def __init__(self, sender): - self.sender = sender - - -class CommandMessage(Message): - '''For commands, adds ``command`` field.''' - def __init__(self, sender, command): - Message.__init__(self, sender) - self.command = command - - -class ModifyMessage(Message): - ''' - For when resources are modified, adds ``subject`` and ``details`` - fields. - ''' - def __init__(self, sender, subject, **details): - Message.__init__(self, sender) - self.subject = subject - self.details = details - - -class OpenMessage(Message): - ''' - For when resources are modified, adds ``name``, content_id``, - ``status``, and ``traceback`` fields. - ''' - def __init__(self, sender, name): - Message.__init__(self, sender) - self.name = name - self.content_id = self.thing = None - self.status = PENDING - self.traceback = None - - -class PersistMessage(Message): - ''' - For when resources are modified, adds ``content_id`` and ``details`` - fields. - ''' - def __init__(self, sender, content_id, **details): - Message.__init__(self, sender) - self.content_id = content_id - self.details = details - - -class ShutdownMessage(Message): - '''Signals that the system is shutting down.''' - - -# Joy Interpreter & Context - - -class World(object): - ''' - This object contains the system context, the stack, dictionary, a - reference to the display broadcast method, and the log. - ''' - - def __init__(self, stack_id, stack_holder, dictionary, notify, log): - self.stack_holder = stack_holder - self.dictionary = dictionary - self.notify = notify - self.stack_id = stack_id - self.log = log.lines - self.log_id = log.content_id - - def handle(self, message): - ''' - Deal with updates to the stack and commands. - ''' - if (isinstance(message, ModifyMessage) - and message.subject is self.stack_holder - ): - self._log_lines('', '%s <-' % self.format_stack()) - if not isinstance(message, CommandMessage): - return - c, s, d = message.command, self.stack_holder[0], self.dictionary - self._log_lines('', '-> %s' % (c,)) - self.stack_holder[0], _, self.dictionary = run(c, s, d) - mm = ModifyMessage(self, self.stack_holder, content_id=self.stack_id) - self.notify(mm) - - def _log_lines(self, *lines): - self.log.extend(lines) - self.notify(ModifyMessage(self, self.log, content_id=self.log_id)) - - def format_stack(self): - try: - return stack_to_string(self.stack_holder[0]) - except: - print(format_exc(), file=stderr) - return str(self.stack_holder[0]) - - -def push(sender, item, notify, stack_name='stack.pickle'): - ''' - Helper function to push an item onto the system stack with message. - ''' - om = OpenMessage(sender, stack_name) - notify(om) - if om.status == SUCCESS: - om.thing[0] = item, om.thing[0] - notify(ModifyMessage(sender, om.thing, content_id=om.content_id)) - return om.status - - -def open_viewer_on_string(sender, content, notify): - ''' - Helper function to open a text viewer on a string. - Typically used to show tracebacks. - ''' - push(sender, content, notify) - notify(CommandMessage(sender, 'good_viewer_location open_viewer')) - - -# main loop - - -class TheLoop(object): - ''' - The main loop manages tasks and the PyGame event queue - and framerate clock. - ''' - - FRAME_RATE = 24 - - def __init__(self, display, clock): - self.display = display - self.clock = clock - self.tasks = {} - self.running = False - - def install_task(self, F, milliseconds): - ''' - Install a task to run every so many milliseconds. - ''' - try: - task_event_id = AVAILABLE_TASK_EVENTS.pop() - except KeyError: - raise RuntimeError('out of task ids') - self.tasks[task_event_id] = F - pygame.time.set_timer(task_event_id, milliseconds) - return task_event_id - - def remove_task(self, task_event_id): - ''' - Remove an installed task. - ''' - assert task_event_id in self.tasks, repr(task_event_id) - pygame.time.set_timer(task_event_id, 0) - del self.tasks[task_event_id] - AVAILABLE_TASK_EVENTS.add(task_event_id) - - def __del__(self): - # Best effort to cancel all running tasks. - for task_event_id in self.tasks: - pygame.time.set_timer(task_event_id, 0) - - def run_task(self, task_event_id): - ''' - Give a task its time to shine. - ''' - task = self.tasks[task_event_id] - try: - task() - except: - traceback = format_exc() - self.remove_task(task_event_id) - print(traceback, file=stderr) - print('TASK removed due to ERROR', task, file=stderr) - open_viewer_on_string(self, traceback, self.display.broadcast) - - def loop(self): - ''' - The actual main loop machinery. - - Maintain a ``running`` flag, pump the PyGame event queue and - handle the events (dispatching to the display), tick the clock. - - When the loop is exited (by clicking the window close button or - pressing the ``escape`` key) it broadcasts a ``ShutdownMessage``. - ''' - self.running = True - while self.running: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - self.running = False - elif event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: - self.running = False - elif event.type in self.tasks: - self.run_task(event.type) - else: - self.display.dispatch_event(event) - pygame.display.update() - self.clock.tick(self.FRAME_RATE) - self.display.broadcast(ShutdownMessage(self)) diff --git a/joy/vui/debug_main.py b/joy/vui/debug_main.py deleted file mode 100644 index 3235b35..0000000 --- a/joy/vui/debug_main.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import absolute_import -import sys, traceback - -# To enable "hot" reloading in the IDLE shell. -for name in 'core main display viewer text_viewer stack_viewer persist_task'.split(): - try: - del sys.modules[name] - except KeyError: - pass - -from . import main - -try: - A = A # (screen, clock, pt), three things that we DON'T want to recreate - # each time we restart main(). -except NameError: - A = main.init() - -d = main.main(*A) diff --git a/joy/vui/default_joy_home/definitions.txt b/joy/vui/default_joy_home/definitions.txt deleted file mode 100644 index 3c3bca2..0000000 --- a/joy/vui/default_joy_home/definitions.txt +++ /dev/null @@ -1,17 +0,0 @@ -see_stack == good_viewer_location open_stack -see_resources == list_resources good_viewer_location open_viewer -open_resource_at_good_location == good_viewer_location open_resource -see_log == "log.txt" open_resource_at_good_location -see_definitions == "definitions.txt" open_resource_at_good_location -round_to_cents == 100 * ++ floor 100 / -reset_log == "del log.lines[1:] ; log.at_line = 0" evaluate -see_menu == "menu.txt" good_viewer_location open_resource - -# Ordered Binary Tree datastructure functions. -BTree-new == swap [[] []] cons cons - _BTree-P == over [popop popop first] nullary - _BTree-T> == [cons cons dipdd] cons cons cons infra - _BTree-T< == [cons cons dipd] cons cons cons infra - _BTree-E == pop swap roll< rest rest cons cons - _BTree-recur == _BTree-P [_BTree-T>] [_BTree-E] [_BTree-T<] cmp -BTree-add == [popop not] [[pop] dipd BTree-new] [] [_BTree-recur] genrec diff --git a/joy/vui/default_joy_home/library.py b/joy/vui/default_joy_home/library.py deleted file mode 100644 index 7f0cabb..0000000 --- a/joy/vui/default_joy_home/library.py +++ /dev/null @@ -1,206 +0,0 @@ -''' -This file is execfile()'d with a namespace containing: - - D - the Joy dictionary - d - the Display object - pt - the PersistTask object - log - the log.txt viewer - loop - the TheLoop main loop object - stack_holder - the Python list object that holds the Joy stack tuple - world - the Joy environment - -''' -from joy.library import ( - DefinitionWrapper, - FunctionWrapper, - SimpleFunctionWrapper, - ) -from joy.utils.stack import list_to_stack, concat -from joy.vui import core, text_viewer, stack_viewer - - -def install(command): D[command.name] = command - - -@install -@SimpleFunctionWrapper -def list_resources(stack): - ''' - Put a string on the stack with the names of all the known resources - one-per-line. - ''' - return '\n'.join(pt.scan()), stack - - -@install -@SimpleFunctionWrapper -def open_stack(stack): - ''' - Given a coordinate pair [x y] (in pixels) open a StackViewer there. - ''' - (x, (y, _)), stack = stack - V = d.open_viewer(x, y, stack_viewer.StackViewer) - V.draw() - return stack - - -@install -@SimpleFunctionWrapper -def open_resource(stack): - ''' - Given a coordinate pair [x y] (in pixels) and the name of a resource - (from list_resources command) open a viewer on that resource at that - location. - ''' - ((x, (y, _)), (name, stack)) = stack - om = core.OpenMessage(world, name) - d.broadcast(om) - if om.status == core.SUCCESS: - V = d.open_viewer(x, y, text_viewer.TextViewer) - V.content_id, V.lines = om.content_id, om.thing - V.draw() - return stack - - -@install -@SimpleFunctionWrapper -def name_viewer(stack): - ''' - Given a string name on the stack, if the currently focused viewer is - anonymous, name the viewer and persist it in the resource store under - that name. - ''' - name, stack = stack - assert isinstance(name, str), repr(name) - if d.focused_viewer and not d.focused_viewer.content_id: - d.focused_viewer.content_id = name - pm = core.PersistMessage(world, name, thing=d.focused_viewer.lines) - d.broadcast(pm) - d.focused_viewer.draw_menu() - return stack - - -##@install -##@SimpleFunctionWrapper -##def persist_viewer(stack): -## if self.focused_viewer: -## -## self.focused_viewer.content_id = name -## self.focused_viewer.draw_menu() -## return stack - - -@install -@SimpleFunctionWrapper -def inscribe(stack): - ''' - Create a new Joy function definition in the Joy dictionary. A - definition is given as a string with a name followed by a double - equal sign then one or more Joy functions, the body. for example: - - sqr == dup mul - - If you want the definition to persist over restarts, enter it into - the definitions.txt resource. - ''' - definition, stack = stack - DefinitionWrapper.add_def(definition, D) - return stack - - -@install -@SimpleFunctionWrapper -def open_viewer(stack): - ''' - Given a coordinate pair [x y] (in pixels) and a string, open a new - unnamed viewer on that string at that location. - ''' - ((x, (y, _)), (content, stack)) = stack - V = d.open_viewer(x, y, text_viewer.TextViewer) - V.lines = content.splitlines() - V.draw() - return stack - - -@install -@SimpleFunctionWrapper -def good_viewer_location(stack): - ''' - Leave a coordinate pair [x y] (in pixels) on the stack that would - be a good location at which to open a new viewer. (The heuristic - employed is to take up the bottom half of the currently open viewer - with the greatest area.) - ''' - viewers = list(d.iter_viewers()) - if viewers: - viewers.sort(key=lambda (V, x, y): V.w * V.h) - V, x, y = viewers[-1] - coords = (x + 1, (y + V.h / 2, ())) - else: - coords = (0, (0, ())) - return coords, stack - - -@install -@FunctionWrapper -def cmp_(stack, expression, dictionary): - ''' - The cmp combinator takes two values and three quoted programs on the - stack and runs one of the three depending on the results of comparing - the two values: - - a b [G] [E] [L] cmp - ------------------------- a > b - G - - a b [G] [E] [L] cmp - ------------------------- a = b - E - - a b [G] [E] [L] cmp - ------------------------- a < b - L - - ''' - L, (E, (G, (b, (a, stack)))) = stack - expression = concat(G if a > b else L if a < b else E, expression) - return stack, expression, dictionary - - -@install -@SimpleFunctionWrapper -def list_viewers(stack): - ''' - Put a string on the stack with some information about the currently - open viewers, one-per-line. This is kind of a demo function, rather - than something really useful. - ''' - lines = [] - for x, T in d.tracks: - #lines.append('x: %i, w: %i, %r' % (x, T.w, T)) - for y, V in T.viewers: - lines.append('x: %i y: %i h: %i %r %r' % (x, y, V.h, V.content_id, V)) - return '\n'.join(lines), stack - - -@install -@SimpleFunctionWrapper -def splitlines(stack): - ''' - Given a string on the stack replace it with a list of the lines in - the string. - ''' - text, stack = stack - assert isinstance(text, str), repr(text) - return list_to_stack(text.splitlines()), stack - - -@install -@SimpleFunctionWrapper -def hiya(stack): - ''' - Demo function to insert "Hi World!" into the current viewer, if any. - ''' - if d.focused_viewer: - d.focused_viewer.insert('Hi World!') - return stack diff --git a/joy/vui/default_joy_home/log.txt b/joy/vui/default_joy_home/log.txt deleted file mode 100644 index 92f9c3c..0000000 --- a/joy/vui/default_joy_home/log.txt +++ /dev/null @@ -1 +0,0 @@ -Joypy log diff --git a/joy/vui/default_joy_home/menu.txt b/joy/vui/default_joy_home/menu.txt deleted file mode 100644 index 930390c..0000000 --- a/joy/vui/default_joy_home/menu.txt +++ /dev/null @@ -1,51 +0,0 @@ - name_viewer - list_resources - open_resource_at_good_location - good_viewer_location - open_viewer - see_stack - see_resources - see_definitions - see_log - reset_log - - inscribe - evaluate - - pop clear dup swap - - add sub mul div truediv modulus divmod - pm ++ -- sum product pow sqr sqrt - < <= = >= > <> - & << >> - - i dupdip - -!= % & * *fraction *fraction0 + ++ - -- / < << <= <> = > >= >> ? ^ -abs add anamorphism and app1 app2 app3 at average -b binary branch -choice clear cleave concat cons -dinfrirst dip dipd dipdd disenstacken div divmod down_to_zero drop -dudipd dup dupd dupdip -enstacken eq -first flatten floor floordiv -gcd ge genrec getitem grand_reset gt -help -i id ifte infra inscribe -key_bindings -le least_fraction loop lshift lt -map max min mod modulus mouse_bindings mul -ne neg not nullary -of or over -pam parse pick pm pop popd popdd popop pow pred primrec product -quoted -range range_to_zero rem remainder remove reset_log rest reverse -roll< roll> rolldown rollup rshift run -second select sharing show_log shunt size sort sqr sqrt stack step -step_zero sub succ sum swaack swap swoncat swons -take ternary third times truediv truthy tuck -unary uncons unique unit unquoted unstack -void -warranty while words -x xor -zip diff --git a/joy/vui/default_joy_home/scratch.txt b/joy/vui/default_joy_home/scratch.txt deleted file mode 100644 index e9f404d..0000000 --- a/joy/vui/default_joy_home/scratch.txt +++ /dev/null @@ -1,85 +0,0 @@ -What is it? - -A simple Graphical User Interface for the Joy programming language, -written using Pygame to bypass X11 et. al., modeled on the Oberon OS, and -intended to be just functional enough to support bootstrapping further Joy -development. - -It's basic functionality is more-or-less as a crude text editor along with -a simple Joy runtime (interpreter, stack, and dictionary.) It auto- saves -any named files (in a versioned home directory) and you can write new Joy -primitives in Python and Joy definitions and immediately install and use -them, as well as recording them for reuse (after restarts.) - -Currently, there are only two kinds of (interesting) viewers: TextViewers -and StackViewer. The TextViewers are crude text editors. They provide -just enough functionality to let the user write text and code (Python and -Joy) and execute Joy functions. One important thing they do is -automatically save their content after changes. No more lost work. - -The StackViewer is a specialized TextViewer that shows the contents of the -Joy stack one line per stack item. It's a very handy visual aid to keep -track of what's going on. There's also a log.txt file that gets written -to when commands are executed, and so records the log of user actions and -system events. It tends to fill up quickly so there's a reset_log command -that clears it out. - -Viewers have "grow" and "close" in their menu bars. These are buttons. -When you right-click on grow a viewer a copy is created that covers that -viewer's entire track. If you grow a viewer that already takes up its -whole track then a copy is created that takes up an additional track, up -to the whole screen. Closing a viewer just deletes that viewer, and when -a track has no more viewers, it is deleted and that exposes any previous -tracks and viewers that were hidden. - -(Note: if you ever close all the viewers and are sitting at a blank screen -with nowhere to type and execute commands, press the Pause/Break key. -This will open a new "trap" viewer which you can then use to recover.) - -Copies of a viewer all share the same model and update their display as it -changes. (If you have two viewers open on the same named resource and edit -one you'll see the other update as you type.) - -UI Guide - -left mouse sets cursor in text, in menu bar resizes viewer interactively -(this is a little buggy in that you can move the mouse quickly and get -outside the menu, leaving the viewer in the "resizing" state. Until I fix -this, the workaround is to just grab the menu bar again and wiggle it a -few pixels and let go. This will reset the machinery.) - -Right mouse executes Joy command (functions), and you can drag with the -right button to highlight (well, underline) commands. Words that aren't -names of Joy commands won't be underlined. Release the button to execute -the command. - -The middle mouse button (usually a wheel these days) scrolls the text but -you can also click and drag any viewer with it to move that viewer to -another track or to a different location in the same track. There's no -direct visual feedback for this (yet) but that dosen't seem to impair its -usefulness. - -F1, F2 - set selection begin and end markers (crude but usable.) - -F3 - copy selected text to the top of the stack. - -Shift-F3 - as copy then run "parse" command on the string. - -F4 - cut selected text to the top of the stack. - -Shift-F4 - as cut then run "pop" (delete selection.) - -Joy - -Pretty much all of the rest of the functionality of the system is provided -by executing Joy commands (aka functions, aka "words" in Forth) by right- -clicking on their names in any text. - -To get help on a Joy function select the name of the function in a -TextViewer using F1 and F2, then press shift-F3 to parse the selection. -The function (really its Symbol) will appear on the stack in brackets (a -"quoted program" such as "[pop]".) Then right-click on the word help in -any TextViewer (if it's not already there, just type it in somewhere.) -This will print the docstring or definition of the word (function) to -stdout. At some point I'll write a thing to send that to the log.txt file -instead, but for now look for output in the terminal. diff --git a/joy/vui/default_joy_home/stack.pickle b/joy/vui/default_joy_home/stack.pickle deleted file mode 100644 index 4b4aaa9..0000000 --- a/joy/vui/default_joy_home/stack.pickle +++ /dev/null @@ -1 +0,0 @@ -(t. \ No newline at end of file diff --git a/joy/vui/display.py b/joy/vui/display.py deleted file mode 100644 index fefc5dd..0000000 --- a/joy/vui/display.py +++ /dev/null @@ -1,510 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2019 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# -''' - -Display -================= - -This module implements a simple visual display system modeled on Oberon. - -Refer to Chapter 4 of the Project Oberon book for more information. - -There is a Display object that manages a pygame surface and N vertical -tracks each of which manages zero or more viewers. -''' -from __future__ import print_function -from __future__ import division -from builtins import next, object -from past.utils import old_div -from copy import copy -from sys import stderr -from traceback import format_exc -import pygame -from .core import ( - open_viewer_on_string, - GREY, - MOUSE_EVENTS, - ) -from .viewer import Viewer -from joy.vui import text_viewer - - -class Display(object): - ''' - Manage tracks and viewers on a screen (Pygame surface.) - - The size and number of tracks are defined by passing in at least two - ratios, e.g. Display(screen, 1, 4, 4) would create three tracks, one - small one on the left and two larger ones of the same size, each four - times wider than the left one. - - All tracks take up the whole height of the display screen. Tracks - manage zero or more Viewers. When you "grow" a viewer a new track is - created that overlays or hides one or two existing tracks, and when - the last viewer in an overlay track is closed the track closes too - and reveals the hidden tracks (and their viewers, if any.) - - In order to facilitate command underlining while mouse dragging the - lookup parameter must be a function that accepts a string and returns - a Boolean indicating whether that string is a valid Joy function name. - Typically you pass in the __contains__ method of the Joy dict. This - is a case of breaking "loose coupling" to gain efficiency, as otherwise - we would have to e.g. send some sort of lookup message to the - World context object, going through the whole Display.broadcast() - machinery, etc. Not something you want to do on each MOUSEMOTION - event. - ''' - - def __init__(self, screen, lookup, *track_ratios): - self.screen = screen - self.w, self.h = screen.get_width(), screen.get_height() - self.lookup = lookup - self.focused_viewer = None - self.tracks = [] # (x, track) - self.handlers = [] # Non-viewers that should receive messages. - # Create the tracks. - if not track_ratios: track_ratios = 1, 4 - x, total = 0, sum(track_ratios) - for ratio in track_ratios[:-1]: - track_width = old_div(self.w * ratio, total) - assert track_width >= 10 # minimum width 10 pixels - self._open_track(x, track_width) - x += track_width - self._open_track(x, self.w - x) - - def _open_track(self, x, w): - '''Helper function to create the pygame surface and Track.''' - track_surface = self.screen.subsurface((x, 0, w, self.h)) - self.tracks.append((x, Track(track_surface))) - - def open_viewer(self, x, y, class_): - ''' - Open a viewer of class_ at the x, y location on the display, - return the viewer. - ''' - track = self._track_at(x)[0] - V = track.open_viewer(y, class_) - V.focus(self) - return V - - def close_viewer(self, viewer): - '''Close the viewer.''' - for x, track in self.tracks: - if track.close_viewer(viewer): - if not track.viewers and track.hiding: - i = self.tracks.index((x, track)) - self.tracks[i:i + 1] = track.hiding - assert sorted(self.tracks) == self.tracks - for _, exposed_track in track.hiding: - exposed_track.redraw() - if viewer is self.focused_viewer: - self.focused_viewer = None - break - - def change_viewer(self, viewer, y, relative=False): - ''' - Adjust the top of the viewer to a new y within the boundaries of - its neighbors. - - If relative is False new_y should be in screen coords, else new_y - should be relative to the top of the viewer. - ''' - for _, track in self.tracks: - if track.change_viewer(viewer, y, relative): - break - - def grow_viewer(self, viewer): - ''' - Cause the viewer to take up its whole track or, if it does - already, take up another track, up to the whole screen. - - This is the inverse of closing a viewer. "Growing" a viewer - actually creates a new copy and a new track to hold it. The old - tracks and viewers are retained, and they get restored when the - covering track closes, which happens automatically when the last - viewer in the covering track is closed. - ''' - for x, track in self.tracks: - for _, V in track.viewers: - if V is viewer: - return self._grow_viewer(x, track, viewer) - - def _grow_viewer(self, x, track, viewer): - '''Helper function to "grow" a viewer.''' - new_viewer = None - - if viewer.h < self.h: - # replace the track with a new track that contains - # a copy of the viewer at full height. - new_track = Track(track.surface) # Reuse it, why not? - new_viewer = copy(viewer) - new_track._grow_by(new_viewer, 0, self.h - viewer.h) - new_track.viewers.append((0, new_viewer)) - new_track.hiding = [(x, track)] - self.tracks[self.tracks.index((x, track))] = x, new_track - - elif viewer.w < self.w: - # replace two tracks - i = self.tracks.index((x, track)) - try: # prefer the one on the right - xx, xtrack = self.tracks[i + 1] - except IndexError: - i -= 1 # okay, the one on the left - xx, xtrack = self.tracks[i] - hiding = [(xx, xtrack), (x, track)] - else: - hiding = [(x, track), (xx, xtrack)] - # We know there has to be at least one other track because it - # there weren't then that implies that the one track takes up - # the whole display screen (the only way you can get just one - # track is by growing a viewer to cover the whole screen.) - # Ergo, viewer.w == self.w, so this branch doesn't run. - new_x = min(x, xx) - new_w = track.w + xtrack.w - r = new_x, 0, new_w, self.h - new_track = Track(self.screen.subsurface(r)) - new_viewer = copy(viewer) - r = 0, 0, new_w, self.h - new_viewer.resurface(new_track.surface.subsurface(r)) - new_track.viewers.append((0, new_viewer)) - new_track.hiding = hiding - self.tracks[i:i + 2] = [(new_x, new_track)] - new_viewer.draw() - - return new_viewer - - def _move_viewer(self, to, rel_y, viewer, _x, y): - ''' - Helper function to move (really copy) a viewer to a new location. - ''' - h = to.split(rel_y) - new_viewer = copy(viewer) - if not isinstance(to, Track): - to = next(T for _, T in self.tracks - for _, V in T.viewers - if V is to) - new_viewer.resurface(to.surface.subsurface((0, y, to.w, h))) - to.viewers.append((y, new_viewer)) - to.viewers.sort() # bisect.insort() would be overkill here. - new_viewer.draw() - self.close_viewer(viewer) - - def _track_at(self, x): - ''' - Return the track at x along with the track-relative x coordinate, - raise ValueError if x is off-screen. - ''' - for track_x, track in self.tracks: - if x < track_x + track.w: - return track, x - track_x - raise ValueError('x outside display: %r' % (x,)) - - def at(self, x, y): - ''' - Return the viewer (which can be a Track) at the x, y location, - along with the relative-to-viewer-surface x and y coordinates. - If there is no viewer at the location the Track will be returned - instead. - ''' - track, x = self._track_at(x) - viewer, y = track.viewer_at(y) - return viewer, x, y - - def iter_viewers(self): - ''' - Iterate through all viewers yielding (viewer, x, y) three-tuples. - The x and y coordinates are screen pixels of the top-left corner - of the viewer. - ''' - for x, T in self.tracks: - for y, V in T.viewers: - yield V, x, y - - def done_resizing(self): - ''' - Helper method called directly by ``MenuViewer.mouse_up()`` to (hackily) - update the display when done resizing a viewer. - ''' - for _, track in self.tracks: # This should be done by a Message? - if track.resizing_viewer: - track.resizing_viewer.draw() - track.resizing_viewer = None - break - - def broadcast(self, message): - ''' - Broadcast a message to all viewers (except the sender) and all - registered handlers. - ''' - for _, track in self.tracks: - track.broadcast(message) - for handler in self.handlers: - handler(message) - - def redraw(self): - ''' - Redraw all tracks (which will redraw all viewers.) - ''' - for _, track in self.tracks: - track.redraw() - - def focus(self, viewer): - ''' - Set system focus to a given viewer (or no viewer if a track.) - ''' - if isinstance(viewer, Track): - if self.focused_viewer: self.focused_viewer.unfocus() - self.focused_viewer = None - elif viewer is not self.focused_viewer: - if self.focused_viewer: self.focused_viewer.unfocus() - self.focused_viewer = viewer - viewer.focus(self) - - def dispatch_event(self, event): - ''' - Display event handling. - ''' - try: - if event.type in {pygame.KEYUP, pygame.KEYDOWN}: - self._keyboard_event(event) - elif event.type in MOUSE_EVENTS: - self._mouse_event(event) - else: - print(( - 'received event %s Use pygame.event.set_allowed().' - % pygame.event.event_name(event.type) - ), file=stderr) - # Catch all exceptions and open a viewer. - except: - err = format_exc() - print(err, file=stderr) # To be safe just print it right away. - open_viewer_on_string(self, err, self.broadcast) - - def _keyboard_event(self, event): - if event.key == pygame.K_PAUSE and event.type == pygame.KEYUP: - # At least on my keyboard the break/pause key sends K_PAUSE. - # The main use of this is to open a TextViewer if you - # accidentally close all the viewers, so you can recover. - raise KeyboardInterrupt('break') - if not self.focused_viewer: - return - if event.type == pygame.KEYUP: - self.focused_viewer.key_up(self, event.key, event.mod) - elif event.type == pygame.KEYDOWN: - self.focused_viewer.key_down( - self, event.unicode, event.key, event.mod) - # This is not UnicodeType. TODO does this need to be fixed? - # self, event.str, event.key, event.mod) - - def _mouse_event(self, event): - V, x, y = self.at(*event.pos) - - if event.type == pygame.MOUSEMOTION: - if not isinstance(V, Track): - V.mouse_motion(self, x, y, *(event.rel + event.buttons)) - - elif event.type == pygame.MOUSEBUTTONDOWN: - if event.button == 1: - self.focus(V) - V.mouse_down(self, x, y, event.button) - - else: - assert event.type == pygame.MOUSEBUTTONUP - - # Check for moving viewer. - if (event.button == 2 - and self.focused_viewer - and V is not self.focused_viewer - and V.MINIMUM_HEIGHT < y < V.h - self.focused_viewer.MINIMUM_HEIGHT - ): - self._move_viewer(V, y, self.focused_viewer, *event.pos) - - else: - V.mouse_up(self, x, y, event.button) - - def init_text(self, pt, x, y, filename): - ''' - Open and return a ``TextViewer`` on a given file (which must be present - in the ``JOYHOME`` directory.) - ''' - viewer = self.open_viewer(x, y, text_viewer.TextViewer) - viewer.content_id, viewer.lines = pt.open(filename) - viewer.draw() - return viewer - - -class Track(Viewer): - ''' - Manage a vertical strip of the display, and the viewers on it. - ''' - - def __init__(self, surface): - Viewer.__init__(self, surface) - self.viewers = [] # (y, viewer) - self.hiding = None - self.resizing_viewer = None - self.draw() - - def split(self, y): - ''' - Split the Track at the y coordinate and return the height - available for a new viewer. Tracks manage a vertical strip of - the display screen so they don't resize their surface when split. - ''' - h = self.viewers[0][0] if self.viewers else self.h - assert h > y - return h - y - - def draw(self, rect=None): - '''Draw the track onto its surface, clearing all content. - - If rect is passed only draw to that area. This supports e.g. - closing a viewer that then exposes part of the track. - ''' - self.surface.fill(GREY, rect=rect) - - def viewer_at(self, y): - ''' - Return the viewer at y along with the viewer-relative y coordinate, - if there's no viewer at y return this track and y. - ''' - for viewer_y, viewer in self.viewers: - if viewer_y < y <= viewer_y + viewer.h: - return viewer, y - viewer_y - return self, y - - def open_viewer(self, y, class_): - '''Open and return a viewer of class at y.''' - # Todo: if y coincides with some other viewer's y replace it. - viewer, viewer_y = self.viewer_at(y) - h = viewer.split(viewer_y) - new_viewer = class_(self.surface.subsurface((0, y, self.w, h))) - new_viewer.draw() - self.viewers.append((y, new_viewer)) - self.viewers.sort() # Could use bisect module but how many - # viewers will you ever have? - return new_viewer - - def close_viewer(self, viewer): - '''Close the viewer, reuse the freed space.''' - for y, V in self.viewers: - if V is viewer: - self._close_viewer(y, V) - return True - return False - - def _close_viewer(self, y, viewer): - '''Helper function to do the actual closing.''' - i = self.viewers.index((y, viewer)) - del self.viewers[i] - if i: # The previous viewer gets the space. - previous_y, previous_viewer = self.viewers[i - 1] - self._grow_by(previous_viewer, previous_y, viewer.h) - else: # This track gets the space. - self.draw((0, y, self.w, viewer.surface.get_height())) - viewer.close() - - def _grow_by(self, viewer, y, h): - '''Grow a viewer (located at y) by height h. - - This might seem like it should be a method of the viewer, but - the viewer knows nothing of its own y location on the screen nor - the parent track's surface (to make a new subsurface) so it has - to be a method of the track, which has both. - ''' - h = viewer.surface.get_height() + h - try: - surface = self.surface.subsurface((0, y, self.w, h)) - except ValueError: # subsurface rectangle outside surface area - pass - else: - viewer.resurface(surface) - if h <= viewer.last_touch[1]: viewer.last_touch = 0, 0 - viewer.draw() - - def change_viewer(self, viewer, new_y, relative=False): - ''' - Adjust the top of the viewer to a new y within the boundaries of - its neighbors. - - If relative is False new_y should be in screen coords, else new_y - should be relative to the top of the viewer. - ''' - for old_y, V in self.viewers: - if V is viewer: - if relative: new_y += old_y - if new_y != old_y: self._change_viewer(new_y, old_y, V) - return True - return False - - def _change_viewer(self, new_y, old_y, viewer): - new_y = max(0, min(self.h, new_y)) - i = self.viewers.index((old_y, viewer)) - if new_y < old_y: # Enlarge self, shrink upper neighbor. - if i: - previous_y, previous_viewer = self.viewers[i - 1] - if new_y - previous_y < self.MINIMUM_HEIGHT: - return - previous_viewer.resizing = 1 - h = previous_viewer.split(new_y - previous_y) - previous_viewer.resizing = 0 - self.resizing_viewer = previous_viewer - else: - h = old_y - new_y - self._grow_by(viewer, new_y, h) - - else: # Shink self, enlarge upper neighbor. - # Enforce invariant. - try: - h, _ = self.viewers[i + 1] - except IndexError: # No next viewer. - h = self.h - if h - new_y < self.MINIMUM_HEIGHT: - return - - # Change the viewer and adjust the upper viewer or track. - h = new_y - old_y - self._grow_by(viewer, new_y, -h) # grow by negative height! - if i: - previous_y, previous_viewer = self.viewers[i - 1] - previous_viewer.resizing = 1 - self._grow_by(previous_viewer, previous_y, h) - previous_viewer.resizing = 0 - self.resizing_viewer = previous_viewer - else: - self.draw((0, old_y, self.w, h)) - - self.viewers[i] = new_y, viewer - # self.viewers.sort() # Not necessary, invariant holds. - assert sorted(self.viewers) == self.viewers - - def broadcast(self, message): - ''' - Broadcast a message to all viewers on this track (except the sender.) - ''' - for _, viewer in self.viewers: - if viewer is not message.sender: - viewer.handle(message) - - def redraw(self): - '''Redraw the track and all of its viewers.''' - self.draw() - for _, viewer in self.viewers: - viewer.draw() diff --git a/joy/vui/font_data.py b/joy/vui/font_data.py deleted file mode 100644 index a719b2b..0000000 --- a/joy/vui/font_data.py +++ /dev/null @@ -1,189 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2019 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# -from __future__ import print_function -from future import standard_library -standard_library.install_aliases() -from io import StringIO -import base64, zlib - - -def create(fn='Iosevka12.BMP'): - with open(fn, 'rb') as f: - data = f.read() - return base64.encodestring(zlib.compress(data)) - - -data = StringIO(zlib.decompress(base64.decodestring('''\ -eJztnWdwVceSx/1qt7Zq98N+2dqqrbLJSWQJESQQIHLOiAwGk3MOItjknDOYZEBkm5yDQWCTbIKw -wUQHgsnJGMfnuz/dNv3Gc+45XAkEMqjrQJ3bd+6cnp7/dJhwVLpao61v+Gks/wby7zj/qvDvH2/8 -n59/Yssbb+z/b/n3L/I9ufwfSleo3XNw/I8hzbel/9+MI279Izo8/H8Gt2mTPbpNm/9YNGfOf0b9 -15l/y9pkUgGzhn9/46/022+/Zc+Ra/2GjT5P2rZ9R+Ys2X/66SfvYgFpwcJFb76VQa86desJv1Hj -piZ/1uw55q/u37/fqXPXDBmzmOX52L59x7t377o966OP1lasVOX333//448/qlStvnzFyoDFfvnl -l8jIqOnTZwbZhMuXr2TKnC0+fn+Q5dMoICWC1ud7u/k7PXv29i4ZGzugYcMmyXsKeCtarMRvTwgw -CP+f//ynMkuVLmfhrWmz5vzqk08+/fHHH4Xz+PHjQ4cOFy8RXb9Bo4APWrZ8BYBcvHipfARsfFz0 -weLAUi1YWLhIZPCt6Bfbv179hsGXTyMnCd7QfMFCEd4l6XoLD8GT4M27jIW3W7duY/EAm7Pk0aOf -8dXVq9cs/rlz57NmC6EtJnPp0jjs0unTZ6zCWL8xY8ZRzzfffBNkK3bv3pMufaYHDx4EWT6NnCR4 -u3DhIpqnv9yKffvddxRw9lqQlAy8yRPPnj3rLAlC+Or8+QsWv3mLljH1GjjLN27SrFEj2zJTszjx -w0eOmPwffniEJCVKlsKbm/ybN28CZsp//vmxYMpjunHrZcpWwHQHw39NSPAGRUQUmzdvvlsxPFRY -gULJfkoy8IbPzZ0nf0CRliyJyxGS69dffzWZ165deytdxoDxFYhy2rGHP/wQHV0mqnj0vXv3TP5X -X30lODyZkGDyv/32W+pPHALnzgVTHtefMVNWvLmFQzf+a0KKt959+jVp+rZbsZYtW3ft1iPgV/vi -46tWq8Hwv3PnDjd79nzsLJMMvEGdu3Rr0LCxs2Szt1u0bdfBYuI38+QNxXo4y+M6GSyWn3UjCs+Z -+/6MmbOcVYHbgwcPBV8+IeHUiRMnnI9w478OpHjbtGkz/oKszVkGyx+SMw95n8W/cuVqq9ZtGaoD -B71HVINnGTJkGB/xa3hDs2Ty8IYdCxhVFosq6bR7ffvFgkO3ypGze/ee3gK8MCJ6sYzk60OKNwCT -PkPmAwc+cZY5cuQoroQAXjnActLkKVmy5iBPtEIswqpGjZtmzpJ93LgJOnmSPLwNGzaibLkKzpKV -q1QfOPBdi0nu/N7gIW6Vjxw1unbtGG8BnjsxBLp1D+AUhg4dXjem/gsWJpWQ4g3CG44YOdpZZvz4 -iRUqVtaPmLvIosWJ97Zs2epW7fYdOwBYkYiiArmk4g0MT5s2A1MZ0AnGxS0jTwTwZ878K3+pUrX6 -hImT3CqfPn1mufIVvQV47gTY2rfv6OST59K0S5cuvWB5UgOZeLNwpWThkEA9U+ZsTZs1J4R2q/by -5SstWrQiMMbJ+pKON5kHBtKPHj1yliTkJs435419fqM3ecpUt8pnzppNSugtgDcRp82dOw8JrTjN -je9zxxs/QXuYbp1XfH3IxJvTb/pc/Cy53tvN3wF1o0aPsZQGGMAtrrZxk2YXL/45hJOKNyDNE0PD -Cvbq3ddZEmeaL3/Y3r37zBQ1pl6D4cNHulWOc69Rs7a3AN7kloe68X3uePP5tYqP8AgAXlUy8fb7 -77878wLJI6zJByH8AqF7eMEi+pMNGzYWLhIZGRm1bfsOs2Ty4jfyvkKFA+QLGDe8rcWkc9u0be9W -eafOXTt06OQtgDdhqEuXKV8yurQ1j+HG93niDVq1ak2OkFzYumeR6m9HJt58geY9vOdJwCGhESjF -lJGT5syVl7Dq559/toolD2/EYwGDLvw7dtViAk78r1vlJUqWmjp1urcAz50svBEbkEFjD+Xj1q3b -8CYBB/IrTBbenPO6xPwe88BCGmUFDLd8ycVbqVJlx4wZ5ywJpJ21yXrBl1+edpYnZQ7o71KanPat -UuVqDJa9++I3b97CECCKe8EivXSy8GatWz11nStISgbebty4waMTEk45S549d46vrCk+nz9l6NK1 -u7M8QWDAeZWUJiferl69hgcJCcmNI2jXvqMVKr8OZOHN99d1+WDW8YOhZODt+vXrgMpjfcqZHe+L -j0+XPpO1wLF//wGYO3fuSqboafRcyYk3c99RMPuUgiHwRuT/xRdfyvX1118LH8wo07n/hGgnNDQ8 -Lm6ZTiljaZevWEmG4rYfafCQoXnyhpJoy8djx47nDy3Qv//AZ29CGj0XcuJt67btsq9S9mFueNo+ -zGAoefstHz9+TPxGNkox4bRo0YqMeMTI0W6BIjIPHPguNln2W0YWLd6nb+zruRMjdZITb68AXbly -1bpJo1RCryTe/qbkPV/3atBrizfy319//ZWwwdwnzMeTJ0/KjndurKWTlMZDGt5eVZoxcxbhYu06 -MTVr1eFGZ49JW/h48+bNBw8eOLfyBokH4kZNgvTSIxse9PrgjYHcq3ffkJx5QkJy9+jRSxbZlUgn -Ub4mlegzQ8YsZpzPJbv6b9263aFDJ6mndZt2169ftx738cd7KawfyQgSn+ufjxowYJDuvuOGjzC5 -yC7NBYtSpcuNHGVvYsFY8TjqyRGSq2XL1teu/WmysGADB72HPLnz5B8+fKQmDlS7ePHSxk2alSlb -4cMPPyI/ktV2N7yRnkyYMCmsQKHQsILTps1QOR8+fNi1Ww9pb8dOXRo1atK3XyzSWspR/XhTyuEt -OrqMJukyxF7WKQzBG52eP7QAqeimTZsLhBe2Zk0tvEFofvSYsScNkvFbu3YMTduxY+euXbsBRpWq -1a3HWXijdwoXieS5a9euCw0NHzJkmPCHDh0OJEDC2nXr8+QNHfTuYP3JpMlTIiOjrGrRIcjZuXPX -7t17KlaqUqlSVa0HUdet37B69RogMX78RJ8fzMjw6acHgXSzt1sAKj6CHJ873iiGnJWrVC9brgJy -6tbNNm3bF4koSka/bfuOiIhi/GTZsuU+f5psUTB9kXJ4mz1nLvqUvWEvHW+Mx0yZs61atUY4aA/z -ZU44OPGGMXEujt++fadkdGndk3bp0iV+RQ+aZUy80Qt0om6iW7Z8hZxKkO3EeqZv5arV5mkFqfbY -seNap8wMHzp8WD6eOHFCVh+oByXrXoLJU6bmyx/GuBD7Y+EN/ZPMAnvu9+7dx7fc8OjvLl/G2oP5 -vfviZf8k6EU/VA5E06XPBF/qX/TB4oCz0MFTyuGNrkFmxq8vFeANFSFApcrVxE2gdmsNy4k3uiN9 -hsyAx6NmPJR0B9VqGCOdovGMeRb14sVL0l94Q/Nkljzd7EcsmLmT5/79+2+ly6gnC4Ci2Ciff98U -Llv4JxMS4H///fdueANOTj9obtAVvAHC7DkS93WIomRnOA8Ck89yhM2XwvEbJkKmPUeMGEWrPbbe -pWj8Cd5kORuTIksJ9JRll5x4g2bMmInanedHlPBujCkiOqn/qfGM4krwr3iT03/m6aqZs2bj9M39 -jW3bdQCED7FEjx5Vq16zRYtWZs3Yuu/9JAv6bnijQsXk3bt3uTly5Kj5FPCGS8WfxsYO8PkHFGKg -BwoXLxFN8Oa05yYRY/Tu08/nH2X0fsFCEdapmRTFm3iWYDYVp2j8qXgjcsOrLlkSFyTefP5Vg2zZ -c1rrlTi+Q4cOz5o9B182Z+77wiHIWbPmQ58jfuNxmzdvkXsKAGAKY/wpExe3TPh4Aev0H4YFg8ZT -lAPSYuo1KFqsRImSpWrVqqtb0YBu+QqVRGMEpdIuN7z5PPNT4gQiUpgdO3ZWm4nMKI2gDhzieb3x -dvnyFRKTCxcuTp06vVz5inPnzosqHm2GdimKN0YH0Ysz1Qqe3Oye8pu3aNmocVNve6h4Q13LV6zM -mCkroW+QeIOI59HhZ599rhxROxd5rjKJzeR9DhbeYGIuNm7cRNBYqHAEuaS0K2u2EPgwie6wA+++ -Z++DrV6jlhgZJbBNeEb+aO5zq10npmq1GohEX0vcQruA7pv+k/vUECTeMOM0E+U48YCGGVlkr4QN -mHSQH1DPQsOGjQC0ZC4JCacAQLGokihQv03p+RDSJfST7NU9N7uXJHto4o2PffrGor3g8ebzL5Fb -px6IDQjbSHjHjh0vHNqIbsndnHjD/uTOkx9vTu/rvAdwKlWqLKkl/IED33WeUpw/f4EE//KRDJfw -CZ8Lrngu2ajPH9fxLPX4gitpV3jBIohNGhsk3rBg5Ed4Q+u8FVFulqw5rl691qBhY+eWYyeBMYbe -0aOfycfjx09InCmU0nhDOUTU1tZrJzHeTzpI422PvNspP9GUDn8Cjxs3bmi+IGcNGPsYhDf/eorc -G28ojW+du6nJ4/C2Gv/gFrHn23fssPCmeahJkyZPwQV77LWmm8zcsEbN2jLXAdFAYjkVWwM/Ce9x -Zz5/Ds6wwvqZeCNPWb9hI/f79x8g2+UGd8mvEAP3vXXrNskXcPfz5s2X/B17JbEi1Uqw6iZwMJRU -vIF/a+YKs4nYuHvUzo0AG1S8806roUOHc0+QidfzrvY5xm+Ei8RCIAHt4bMAlc6HwJQyku//ea5q -wULwYOENa0P/0inyEZNFd4j+e/Xuu2PHTuHjXMhhdQigAUzW283fCQZvDAT8l07RBCQCNnXZBEJ6 -OItsQk49YGYRAIQLH8FopoZeSsHkp9HRZTp36Sb2bdToMThEMcW6/Z5noYSAp3eDJze84YCID509 -3r17T4JJkyO5OT5d5hglxBX8yJwkjgCdyDy84FD7i8HbtFnzZ9nfTr7ZsVMXi8kQxuOQWInTkfle -SsIkjiJe4qtOnbtKYQY4uq1UuZpl34BNZGQUoT5ZBjeoXTVAuEWjwDMYUL4Q9UsnKge80X1qtMX4 -COExSR/MHrTsvMwJC56J/In31j+Zr+7Vq4/8hO5DHuSUOFD5dIcOBHnbkowvN3+KucPpgyg6Cweq -Y3PMmHH4cboM78xXJLZJ6iCLAuINYSIiikliaxFDwHqvBQk1Yt+7dw/8cyPaM/EGnPLmC1Mfh9jo -jfya9qKf57tRkGft3buPcEhCXyontTTXs+g+53oWTh9LYuENCWkppjJxHadjZ33lCz8EcgRdfNXO -8VZAAENeZuHNNCbmeVIIKGJpNQj0sPM0DSzJc+k1jQMfPnyIx0FIvqLLZNIJsIEZwC9lsKIUkHuP -/JQ6cb71GzQyZ8JhMqKpjYBw5arVSe+Tv5ATbzyL2LhK1eoB37NBYWtEyzT1zVu3RH662/dXvPn8 -GEPtEqsw6AiV6UqgS4GAT0k24dwZpOCtVeu2OHGSPsZmKl+v3xcf/9TTOskgQILO6Q5MMQMc8yj8 -57Jen2xy1o9djSxaXJeDLWrdph2OxuTEx++X+cM7dxLnlHbt2v3Uh5LsAANMjfM8yLOTABjIiX3G -LKRyvKUQYfeIGTCGuXLnQxUa1JE0McwxyxgWbvTsnhBZBv465aQKiGeP6QtSb+t9jMS95GWYcWwa -N25AfcGE68F+yv3ribfUSa/PfqQ0Sj2Egwv+Fa9/O0rDW+ohwpuWrdoQd7mdPnsFKA1vqYcWL15K -Hm2+ZOzVozS8pRJat35D6TLlQ8MKysaGV5VkfUH2SwhH59vN+a78oQUGDBikm6bI4Dp26pI4rxWS -mxCX7NtnzI+lS58pIqLY3Lnz9ClDhw4POG8GP6DvuHfvHvkjg508vW+/WNmY6ian3uulZRISTlWt -ViNT5myRRYvr/JhVz7lz5/koJwedcpr7SQLqR/myv1fkUflFP7dv35EyCDNhQoCXIk6aPCVDxix9 -+sb2i+2fMVPW0WPGOuXU/YE+/9pcixatEuc/c+bp3r2ntfTgzDv+3Lfvl4fy1uldpCpfoZIlUnjB -It9dvkzCmzdfmHDIlGWxTz7K3LI5VWs9N+B8qfx9GW72xf+5FilLh4gk5ZcsiTt58qTMU+m6Q9Nm -zSMjo9Zv2Ai/WFRJOY+s5Y8fP7Fg4aIsWXPMn79AytOPVapWd67/uuFN1i+of+269bRX9pN74I2B -QJ38qlGjJtyIEmAiM8y9e/eNGTPurXQZZR+LVc/q1Wt4hKzzOuUE6sHg7dSpL8xxpPKjn6ji0frW -64B4I2wDBjrNiAKzZgtxPjcublm+/GEyTyt75nfv3oNVLBJRtHWbdmaFTrxhK7AYFEaesAKFzLfq -ydJhtuw5L1++okyZvtu6dRuP4EbPoWB+ZcO8z7/2lCt3Po/nJp43j4xq3KSZqU/xp9lz5Jo2bYbs -XJo9Zy4GgcJWe2U9FH3KflrFJzivWauOzPmY5SdPmVqocIToxw1XAflW/TQQK+fzxFvA9oKBcuUr -6gahWrXqyq5gq542bdvr7FBAeaS8tX/Ywtv48RMLhBcWviW/jN+bt275XPAm7wjSdzPKvoLz5y+Y -9cvSjLxQEVOAkLROym/bvsNcp3bqwec/H6T7CcEJeNavUG+duvUYp+Zf4cGIgaVx4yZMmTqNG1An -/I4dO+tfsmjeomWr1m3NpzifS0QKlsxjU4K3suUqmEavZHRpZ7+A/zf9+8zlpUnO6Wir/OnTZ3Ro -JAlvVv1it9XeBo83i7p26yGr22Y9/ByF6MZ4D7whxsmEBEw3g9SJtzJlK/Tu00/4lvzyoid5UVhA -vJn7wXzG/mqz/sRUIiS3+mWTNm3arOfLAupB9/vJR4y8rOnLRzAzcdLkGTNmmksVGNu27TrAwXJy -M3PWbOHLWDt85MiJEyesLa8B9f/LL78wDAcPGaocwRuOUld+GexyFsbqX0BOaIGcln6sftHyomfZ -z58kvFn1u8VLScWbfiv1yL6RBQsWEqhoZ3ngDQ0n7l9t1ETGkcqD3ZM/BSJbreC74cfnxxvhKPem -9rzxhv3B2mCR8LPORmEMixYrYb1TKGAcFVBvRDWYPiww4wgfp0YyNnbA9OkzK1SszIW/M+vv0KET -1qlS5WqWE/f5rV/LVm0s5py57yO8RPi+J3gj0CpeIlo4DNUZM2epnLSXtm/ZshXfLeeCg8SbqWcr -LtJ14YB8s37MAvbf7F+Rh0v5bnq2yMIbYQwmiFabb5n2wBuSEAIRQcnb51Qexjg9QivkXNhT8aZO -hBBdbKA33vQiezV9Ch4WBGL0CA6t+D94vGGxyVPk3UTmPm3qXLo0jrC8bkx98ixCEa0N8cg7AKe1 -WHbr1m2CQCqxDh0TaOXJG6rvjRS88VxGKDKQyBAMmHG1Xmpvk4c3syrdahKQb9aPMBqHP3UfYJLw -RphNmoB+dOj5PPG2ceMm1F6vfsMN/j2Z/8Lb4cPwiX61H73xJv4Uu1S9Rq3adWKc+gzoT83yPn++ -SXfQvzi+p74X3QNv2BnZm+rz76lWv0mOQzNHjhqNKyQ+NP+KIrgioiM1tnA1ZMiwUqXLYQ9184MS -2TcQFQ8ueENmKiGMwcurXVU5GUq4bH4iZ1uS50/pKecm5ID8IOt/dn8aHV0Gv2CW8cDbsGEjxo4d -j+q4MfFGd6RLn4mwNkl48z2JSwnJgsGbWd7n33FBLua24zp4vBFHqa/Eh+qZYjkGxbNA14EDn2AD -tbYuXbuTuaA38wAy2VCWrDmAB0klQZe1D5BnYYdlv73O9+KOMXroU+2YJScPknhb4uGn4uEZ84WU -xhv10F8MLk3w3eSR8iRxss8cF2PijTShRMlSpjyW/G75guZfcoJbD9jK8e0zZ8645Wvc030e08LB -441ITG0aplLyRII6M78QnMsUKGEefvDo0c/EIWq+QMaBDcRqYZqKRZWU+UOTMJWEIphlxRtqr1Gz -dky9BpoXW3ICSNktL+dQ9E2nPB07/3znQ8z6iZf69x+IqM8dbz7/oXjstkxWuMkj5QlC0Lnsj5W/ -gqpxoPwxFJXHkl/e/irnYky87dq1m2jh4cPEU7Pc6F41UE1X3r1712qvlkel5NT6HsizZ882bNjE -Qw8eemO46b5TDHXAeTCzfOI7Uox3P+p8CE5Z3/kD9nCslg4xlWQNQFrxhkKwhMQz+o4+nb8lEiYk -xqjqWdHGTZpFFi1OJk4eAZ7l/avmfC81U5X+NSKP+d6AfK0fr8cYJLTw1lvA+V4lHJZ868Qb6sU1 -6PtJPPCmMTMBgBVPyrZMU57E+fAn+iEW0r8KDd6whwiD3ylYKKLdE1Tgmxib8t6VyMgoOdJizrdb -5XE02JP1GzaC6mrVa5Li/eEn0aHqQfTppjd7nv9Q4jyh026Y7XKb7wU5erCRJjMe5Vyq2bPgM7xg -EevvZ5kn+8z4nJKStAoRYye+B8n/PqK27TpIUGGuZ6G099//175cj/WsgHyzflJsccrJWM/Sdgnf -iTeff96eB+n6ghvedFs7IYeJtwLhhcWGm/L8Kb9/fztYUvupkvBEnIVOgvGrzl26yXoTP5T9+ab+ -rfJYuR49euXMlRcDpX9Yyvt86FPX457Kd1vPkrM59vzew4du61m+NEqjF0VpeEujF0lpeEujF0lp -eEuj50KkmfoKPg8Cb49/+jm1XYcOH42p1yBb9pxctevE7D/waTIqefjDo169+xFR58tfYOq0GS+9 -UffuJ54x/HhvvHexTw8eSpy3vHHzpQucpGvJ0rjQsPCnFkuFePv++o0cIbmbt2i5a/fHez7e17Zd -x6zZQr7+5tuk1jN12vTcefKvW79h5qw5pMzU9nLb9Wrj7ag/LT195qx3sVSIt13+PX63bt+Rjz88 -+jFDxixr161Paj2r13wUt2yF3GMtY/sPernterXxxlW4SOTESVO8ywjedu/ZGxEZlTlL9ph6DVet -XiPtFf1gJytXqZ4pc7ZGjZt+d/mK/Oruvfs9eyW+/yFH4rxQD8XG1WvfN23WgnoqVqqybPlK1dv9 -Bw/lOD+WigKXvv7GQ73nL1wCYJTnq08+PTh8xKi30mU8fiLB6i/zh0hoTvKUKVvBambXbj2wkwH7 -/Zj//U7ffPudWz1ffHma+/MXLspOrW+/S1xX+vzYcQ957ty916Nnb//8W24ezUd9bkB9uumN/xOn -wg4espqDME2aNidU4GrQsPGpL740v926bQe9iap59IOHP4g8LVu1cdYvV6nSZYtFlfjx8U/K4T5v -vjAafu78BVrx6MfHwsyVO9/78xZImeUrVgEA+UqumrXqlitfST9Ke53zb/Cps1Xrttt37Fq4aHER -/z58xRsfqXnNh2vzh4bj46Sq3n36hRUotGLlavgFwgtrV7Zt1wFQrVr9IaCVd4NIu7AtiLo0btn6 -DZsqVKxMP6qcAYdzbP+BIl76DJlLRpdBRU6cmD9EM4ePfIZ6qZmbhFNfWB3UrXtPoBIQbyNGjkYk -uQ9YTzLwhn78elgjeqNCfS7qwurCJ6pUfbrpLSDe6PfoUmWrVK0BrrjoZdCi3964eYugt1/sgA0b -N1PnhImTYQ4eMgwmz6XLChaKMBV+4JODiEQvE7poJScTTqF5oPXB4qWJ+4U+PyZ8jEChwpE0BKdT -vESpQe8O1p8wdmQzz5mvzqqcwA9R0aReie8b9K8va50rV6028TZ5yjThf/jROiq8fecuQ4axAwiF -v2XrdqTFgnFlzJRV+URNUo9VHsGGDhshQ94NbzVq1uk/YBABv8n06F9FTvUatSykeePtZuLumryC -Z7d6koo3q73oDWtGe6W8AOCx392LPt305oY3ri9PnyHKlfsdO3dRRvVJvMrTRXWjRo9t177TY7+n -0+dOnzHL1BuNAjb0iBoNrgULF2F+MYntO3Rq2KjJ7DlzhX/t++uExCNHjQEVGBDMsv5k7vvzCxcp -yjVp8lQTtxjV+QsWKge8gVXGFMOEwQLq1N6KfjB6j5/YcD6ifLmhyQpjs4Dy9+6Ll3qEj2Wjj/TC -I3vgjZain7PnzuNbUwhvogQGPuMUDTxHvFl60I9Sftv2ncI/59+G5NSn6s0Db4+fmLJ9/vVTbIgy -MUo4U7MYjQPY+lwENuMcPP7BQ4fp98RduE9Ai7rI6MuWq4idB2wdOnbW2jCSDJ8sWXMsXhJnPgUT -MXDQexjA8hUqm/xp02dSsxo9id/oWTSJ+SVSEkemeFN9qp5V/1bzLb7qX/jWRT0eeFv0wRIjiCr/ -1dlzzx1vtBT9YFjwO1bhZ8SbpQe38m76NNvlhrcLFy/JS/neTPxDBlUxI/rVnLnzIosWNwt76I22 -E6dJbINXxctLGerE7HTq3JX2wixdppxZIUYsNKygGe99/U3ijvr9B6g7cdFf+kvRXqt2TNVqNWVQ -O/NTlSdI+6aXt33jh+a4/vL0V26wYdDh4zDyuAzsGwOnbkx91Zs1TmEmD28UJty1uiYZeMOdSbF9 -/ndhwQxo36hEyu/ctVsxE6R90y7Qi4CTyJ8sz5nGJglvvXr3I3QUfucu3Un95J54fsvWbSdOniKZ -2rV7D9ZMawN+so+IaFyZs2bPBYGCWwK8KVOn/xUYl7Ci4tDBG7AjviVulG8JJNKlz0QAYMVvH61d -HzB+Qxu4Y2f8hgxmPKPiERUjLf6U59Jr4r7j9x/gXqyu6J/YUsoTD0g8bMU/xCGE4h448cYb+scs -hIaFE40EgzdkI5h5p2Ubkms+khJKPYRbUgwHLfJY+kFvqEXjN42FiHsDxm+qN8Xb+AmT5CsxKRgK -mJs2bxEmIag59pOENxyxyj9v/kL6UevX9AFgaHyIB0djo8eMGzd+IvHblavXpEz9Bo279+gl9337 -9a9dJ8ZSKVl5hoxZ6GKxb+TUUcWjid82b9mKtWzcpJnKyUeSGpTmzE/JLOCHFyyiXWnkWR/SanMc -IR5MgmcMeI+evR8HypcxvNJe6mQIL1j4AcqnQnofEy3leS4QJY9jDJJTyHMvXvpa8kon3iTlfLv5 -OwHzhWPHT4INy6UGxBuZO70D8pfGLU98NfTtO1IPfYQT4RFETSoP7RU90F70JnbjiT4j6UE0j8ID -5ad/0ZvgjYgIkCAkX2EVH/tnMJCQkY7xQWnIgNKoHzHeGzwM7UkyePnKVW+8MfAVtzv854ulHrfy -aIZmim3hJrb/QCmDp9CciyajUhkdZmYquargjZyRkZvD/95R2i64lecSFuLNEQwM63wRaDfn3xhi -widhAasURkUEliqnzEclvq81Zx5uNC597BK/AQPGCGIrFBm2pjyErE2btdDn0tFSzIk3nVJzmw8Z -7//Df+Y8UkC8ETkXLBRBYAkwhg0fqfUgGF9Z8mh7Zf4NI2aVt/TppjfBGyCsUrVGtuw51RSfPnOW -8lQOk/xR/ALuzxq/Yrvc8ANmnHwsmAfe8uUvgAaE/8Hipdlz5AKf2HMK4NxNe6jj8U3H/JvVQW52 -OKlXkPPkIJ9iklnTs2a/J1UeGi7TmwG/Cr4eD7+c+i+nP01V10vHGwOKcT102AgJ5A4dPppseUij -rKkAuQAzdoDo66n1ePjlv8uVhrenlly3fgPZDd7Be/XtqfLE1GsYECfIQEijwZVHPR5++e9y/X3x -lnalXc/9SsNb2vUirzS8pV0v8gJv/w/2vRht'''))) - - -if __name__ == '__main__': - print(create()) diff --git a/joy/vui/init_joy_home.py b/joy/vui/init_joy_home.py deleted file mode 100644 index 1dd23c5..0000000 --- a/joy/vui/init_joy_home.py +++ /dev/null @@ -1,278 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2019 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# -''' -Utility module to help with setting up the initial contents of the -JOY_HOME directory. - -These contents are kept in this Python module as a base64-encoded zip -file, so you can just do, e.g.: - - import init_joy_home - init_joy_home.initialize(JOY_HOME) - -''' -from __future__ import print_function -from future import standard_library -standard_library.install_aliases() -import base64, os, io, zipfile - - -def initialize(joy_home): - Z.extractall(joy_home) - - -def create_data(from_dir='./default_joy_home'): - f = io.StringIO() - z = zipfile.ZipFile(f, mode='w') - for fn in os.listdir(from_dir): - from_fn = os.path.join(from_dir, fn) - z.write(from_fn, fn) - z.close() - return base64.encodestring(f.getvalue()) - - -Z = zipfile.ZipFile(io.StringIO(base64.decodestring('''\ -UEsDBBQAAAAAAORmeE794BlRfgMAAH4DAAAPAAAAZGVmaW5pdGlvbnMudHh0c2VlX3N0YWNrID09 -IGdvb2Rfdmlld2VyX2xvY2F0aW9uIG9wZW5fc3RhY2sNCnNlZV9yZXNvdXJjZXMgPT0gbGlzdF9y -ZXNvdXJjZXMgZ29vZF92aWV3ZXJfbG9jYXRpb24gb3Blbl92aWV3ZXINCm9wZW5fcmVzb3VyY2Vf -YXRfZ29vZF9sb2NhdGlvbiA9PSBnb29kX3ZpZXdlcl9sb2NhdGlvbiBvcGVuX3Jlc291cmNlDQpz -ZWVfbG9nID09ICJsb2cudHh0IiBvcGVuX3Jlc291cmNlX2F0X2dvb2RfbG9jYXRpb24NCnNlZV9k -ZWZpbml0aW9ucyA9PSAiZGVmaW5pdGlvbnMudHh0IiBvcGVuX3Jlc291cmNlX2F0X2dvb2RfbG9j -YXRpb24NCnJvdW5kX3RvX2NlbnRzID09IDEwMCAqICsrIGZsb29yIDEwMCAvDQpyZXNldF9sb2cg -PT0gImRlbCBsb2cubGluZXNbMTpdIDsgbG9nLmF0X2xpbmUgPSAwIiBldmFsdWF0ZQ0Kc2VlX21l -bnUgPT0gIm1lbnUudHh0IiBnb29kX3ZpZXdlcl9sb2NhdGlvbiBvcGVuX3Jlc291cmNlDQoNCiMg -T3JkZXJlZCBCaW5hcnkgVHJlZSBkYXRhc3RydWN0dXJlIGZ1bmN0aW9ucy4NCkJUcmVlLW5ldyA9 -PSBzd2FwIFtbXSBbXV0gY29ucyBjb25zDQogX0JUcmVlLVAgPT0gb3ZlciBbcG9wb3AgcG9wb3Ag -Zmlyc3RdIG51bGxhcnkNCiBfQlRyZWUtVD4gPT0gW2NvbnMgY29ucyBkaXBkZF0gY29ucyBjb25z -IGNvbnMgaW5mcmENCiBfQlRyZWUtVDwgPT0gW2NvbnMgY29ucyBkaXBkXSBjb25zIGNvbnMgY29u -cyBpbmZyYQ0KIF9CVHJlZS1FID09IHBvcCBzd2FwIHJvbGw8IHJlc3QgcmVzdCBjb25zIGNvbnMN -CiBfQlRyZWUtcmVjdXIgPT0gX0JUcmVlLVAgW19CVHJlZS1UPl0gW19CVHJlZS1FXSBbX0JUcmVl -LVQ8XSBjbXANCkJUcmVlLWFkZCA9PSBbcG9wb3Agbm90XSBbW3BvcF0gZGlwZCBCVHJlZS1uZXdd -IFtdIFtfQlRyZWUtcmVjdXJdIGdlbnJlYw0KUEsDBBQAAAAAACFrpk7/HHjxGBYAABgWAAAKAAAA -bGlicmFyeS5weScnJw0KVGhpcyBmaWxlIGlzIGV4ZWNmaWxlKCknZCB3aXRoIGEgbmFtZXNwYWNl -IGNvbnRhaW5pbmc6DQoNCiAgRCAtIHRoZSBKb3kgZGljdGlvbmFyeQ0KICBkIC0gdGhlIERpc3Bs -YXkgb2JqZWN0DQogIHB0IC0gdGhlIFBlcnNpc3RUYXNrIG9iamVjdA0KICBsb2cgLSB0aGUgbG9n -LnR4dCB2aWV3ZXINCiAgbG9vcCAtIHRoZSBUaGVMb29wIG1haW4gbG9vcCBvYmplY3QNCiAgc3Rh -Y2tfaG9sZGVyIC0gdGhlIFB5dGhvbiBsaXN0IG9iamVjdCB0aGF0IGhvbGRzIHRoZSBKb3kgc3Rh -Y2sgdHVwbGUNCiAgd29ybGQgLSB0aGUgSm95IGVudmlyb25tZW50DQoNCicnJw0KZnJvbSBqb3ku -bGlicmFyeSBpbXBvcnQgKA0KICAgIERlZmluaXRpb25XcmFwcGVyLA0KICAgIEZ1bmN0aW9uV3Jh -cHBlciwNCiAgICBTaW1wbGVGdW5jdGlvbldyYXBwZXIsDQogICAgKQ0KZnJvbSBqb3kudXRpbHMu -c3RhY2sgaW1wb3J0IGxpc3RfdG9fc3RhY2ssIGNvbmNhdA0KZnJvbSBqb3kudnVpIGltcG9ydCBj -b3JlLCB0ZXh0X3ZpZXdlciwgc3RhY2tfdmlld2VyDQoNCg0KZGVmIGluc3RhbGwoY29tbWFuZCk6 -IERbY29tbWFuZC5uYW1lXSA9IGNvbW1hbmQNCg0KDQpAaW5zdGFsbA0KQFNpbXBsZUZ1bmN0aW9u -V3JhcHBlcg0KZGVmIGxpc3RfcmVzb3VyY2VzKHN0YWNrKToNCiAgICAnJycNCiAgICBQdXQgYSBz -dHJpbmcgb24gdGhlIHN0YWNrIHdpdGggdGhlIG5hbWVzIG9mIGFsbCB0aGUga25vd24gcmVzb3Vy -Y2VzDQogICAgb25lLXBlci1saW5lLg0KICAgICcnJw0KICAgIHJldHVybiAnXG4nLmpvaW4ocHQu -c2NhbigpKSwgc3RhY2sNCg0KDQpAaW5zdGFsbA0KQFNpbXBsZUZ1bmN0aW9uV3JhcHBlcg0KZGVm -IG9wZW5fc3RhY2soc3RhY2spOg0KICAgICcnJw0KICAgIEdpdmVuIGEgY29vcmRpbmF0ZSBwYWly -IFt4IHldIChpbiBwaXhlbHMpIG9wZW4gYSBTdGFja1ZpZXdlciB0aGVyZS4NCiAgICAnJycNCiAg -ICAoeCwgKHksIF8pKSwgc3RhY2sgPSBzdGFjaw0KICAgIFYgPSBkLm9wZW5fdmlld2VyKHgsIHks -IHN0YWNrX3ZpZXdlci5TdGFja1ZpZXdlcikNCiAgICBWLmRyYXcoKQ0KICAgIHJldHVybiBzdGFj -aw0KDQoNCkBpbnN0YWxsDQpAU2ltcGxlRnVuY3Rpb25XcmFwcGVyDQpkZWYgb3Blbl9yZXNvdXJj -ZShzdGFjayk6DQogICAgJycnDQogICAgR2l2ZW4gYSBjb29yZGluYXRlIHBhaXIgW3ggeV0gKGlu -IHBpeGVscykgYW5kIHRoZSBuYW1lIG9mIGEgcmVzb3VyY2UNCiAgICAoZnJvbSBsaXN0X3Jlc291 -cmNlcyBjb21tYW5kKSBvcGVuIGEgdmlld2VyIG9uIHRoYXQgcmVzb3VyY2UgYXQgdGhhdA0KICAg -IGxvY2F0aW9uLg0KICAgICcnJw0KICAgICgoeCwgKHksIF8pKSwgKG5hbWUsIHN0YWNrKSkgPSBz -dGFjaw0KICAgIG9tID0gY29yZS5PcGVuTWVzc2FnZSh3b3JsZCwgbmFtZSkNCiAgICBkLmJyb2Fk -Y2FzdChvbSkNCiAgICBpZiBvbS5zdGF0dXMgPT0gY29yZS5TVUNDRVNTOg0KICAgICAgICBWID0g -ZC5vcGVuX3ZpZXdlcih4LCB5LCB0ZXh0X3ZpZXdlci5UZXh0Vmlld2VyKQ0KICAgICAgICBWLmNv -bnRlbnRfaWQsIFYubGluZXMgPSBvbS5jb250ZW50X2lkLCBvbS50aGluZw0KICAgICAgICBWLmRy -YXcoKQ0KICAgIHJldHVybiBzdGFjaw0KDQoNCkBpbnN0YWxsDQpAU2ltcGxlRnVuY3Rpb25XcmFw -cGVyDQpkZWYgbmFtZV92aWV3ZXIoc3RhY2spOg0KICAgICcnJw0KICAgIEdpdmVuIGEgc3RyaW5n -IG5hbWUgb24gdGhlIHN0YWNrLCBpZiB0aGUgY3VycmVudGx5IGZvY3VzZWQgdmlld2VyIGlzDQog -ICAgYW5vbnltb3VzLCBuYW1lIHRoZSB2aWV3ZXIgYW5kIHBlcnNpc3QgaXQgaW4gdGhlIHJlc291 -cmNlIHN0b3JlIHVuZGVyDQogICAgdGhhdCBuYW1lLg0KICAgICcnJw0KICAgIG5hbWUsIHN0YWNr -ID0gc3RhY2sNCiAgICBhc3NlcnQgaXNpbnN0YW5jZShuYW1lLCBzdHIpLCByZXByKG5hbWUpDQog -ICAgaWYgZC5mb2N1c2VkX3ZpZXdlciBhbmQgbm90IGQuZm9jdXNlZF92aWV3ZXIuY29udGVudF9p -ZDoNCiAgICAgICAgZC5mb2N1c2VkX3ZpZXdlci5jb250ZW50X2lkID0gbmFtZQ0KICAgICAgICBw -bSA9IGNvcmUuUGVyc2lzdE1lc3NhZ2Uod29ybGQsIG5hbWUsIHRoaW5nPWQuZm9jdXNlZF92aWV3 -ZXIubGluZXMpDQogICAgICAgIGQuYnJvYWRjYXN0KHBtKQ0KICAgICAgICBkLmZvY3VzZWRfdmll -d2VyLmRyYXdfbWVudSgpDQogICAgcmV0dXJuIHN0YWNrDQoNCg0KIyNAaW5zdGFsbA0KIyNAU2lt -cGxlRnVuY3Rpb25XcmFwcGVyDQojI2RlZiBwZXJzaXN0X3ZpZXdlcihzdGFjayk6DQojIyAgICBp -ZiBzZWxmLmZvY3VzZWRfdmlld2VyOg0KIyMgICAgICAgIA0KIyMgICAgICAgIHNlbGYuZm9jdXNl -ZF92aWV3ZXIuY29udGVudF9pZCA9IG5hbWUNCiMjICAgICAgICBzZWxmLmZvY3VzZWRfdmlld2Vy -LmRyYXdfbWVudSgpDQojIyAgICByZXR1cm4gc3RhY2sNCg0KDQpAaW5zdGFsbA0KQFNpbXBsZUZ1 -bmN0aW9uV3JhcHBlcg0KZGVmIGluc2NyaWJlKHN0YWNrKToNCiAgICAnJycNCiAgICBDcmVhdGUg -YSBuZXcgSm95IGZ1bmN0aW9uIGRlZmluaXRpb24gaW4gdGhlIEpveSBkaWN0aW9uYXJ5LiAgQQ0K -ICAgIGRlZmluaXRpb24gaXMgZ2l2ZW4gYXMgYSBzdHJpbmcgd2l0aCBhIG5hbWUgZm9sbG93ZWQg -YnkgYSBkb3VibGUNCiAgICBlcXVhbCBzaWduIHRoZW4gb25lIG9yIG1vcmUgSm95IGZ1bmN0aW9u -cywgdGhlIGJvZHkuIGZvciBleGFtcGxlOg0KDQogICAgICAgIHNxciA9PSBkdXAgbXVsDQoNCiAg -ICBJZiB5b3Ugd2FudCB0aGUgZGVmaW5pdGlvbiB0byBwZXJzaXN0IG92ZXIgcmVzdGFydHMsIGVu -dGVyIGl0IGludG8NCiAgICB0aGUgZGVmaW5pdGlvbnMudHh0IHJlc291cmNlLg0KICAgICcnJw0K -ICAgIGRlZmluaXRpb24sIHN0YWNrID0gc3RhY2sNCiAgICBEZWZpbml0aW9uV3JhcHBlci5hZGRf -ZGVmKGRlZmluaXRpb24sIEQpDQogICAgcmV0dXJuIHN0YWNrDQoNCg0KQGluc3RhbGwNCkBTaW1w -bGVGdW5jdGlvbldyYXBwZXINCmRlZiBvcGVuX3ZpZXdlcihzdGFjayk6DQogICAgJycnDQogICAg -R2l2ZW4gYSBjb29yZGluYXRlIHBhaXIgW3ggeV0gKGluIHBpeGVscykgYW5kIGEgc3RyaW5nLCBv -cGVuIGEgbmV3DQogICAgdW5uYW1lZCB2aWV3ZXIgb24gdGhhdCBzdHJpbmcgYXQgdGhhdCBsb2Nh -dGlvbi4NCiAgICAnJycNCiAgICAoKHgsICh5LCBfKSksIChjb250ZW50LCBzdGFjaykpID0gc3Rh -Y2sNCiAgICBWID0gZC5vcGVuX3ZpZXdlcih4LCB5LCB0ZXh0X3ZpZXdlci5UZXh0Vmlld2VyKQ0K -ICAgIFYubGluZXMgPSBjb250ZW50LnNwbGl0bGluZXMoKQ0KICAgIFYuZHJhdygpDQogICAgcmV0 -dXJuIHN0YWNrDQoNCg0KQGluc3RhbGwNCkBTaW1wbGVGdW5jdGlvbldyYXBwZXINCmRlZiBnb29k -X3ZpZXdlcl9sb2NhdGlvbihzdGFjayk6DQogICAgJycnDQogICAgTGVhdmUgYSBjb29yZGluYXRl -IHBhaXIgW3ggeV0gKGluIHBpeGVscykgb24gdGhlIHN0YWNrIHRoYXQgd291bGQNCiAgICBiZSBh -IGdvb2QgbG9jYXRpb24gYXQgd2hpY2ggdG8gb3BlbiBhIG5ldyB2aWV3ZXIuICAoVGhlIGhldXJp -c3RpYw0KICAgIGVtcGxveWVkIGlzIHRvIHRha2UgdXAgdGhlIGJvdHRvbSBoYWxmIG9mIHRoZSBj -dXJyZW50bHkgb3BlbiB2aWV3ZXINCiAgICB3aXRoIHRoZSBncmVhdGVzdCBhcmVhLikNCiAgICAn -JycNCiAgICB2aWV3ZXJzID0gbGlzdChkLml0ZXJfdmlld2VycygpKQ0KICAgIGlmIHZpZXdlcnM6 -DQogICAgICAgIHZpZXdlcnMuc29ydChrZXk9bGFtYmRhIChWLCB4LCB5KTogVi53ICogVi5oKQ0K -ICAgICAgICBWLCB4LCB5ID0gdmlld2Vyc1stMV0NCiAgICAgICAgY29vcmRzID0gKHggKyAxLCAo -eSArIFYuaCAvIDIsICgpKSkNCiAgICBlbHNlOg0KICAgICAgICBjb29yZHMgPSAoMCwgKDAsICgp -KSkNCiAgICByZXR1cm4gY29vcmRzLCBzdGFjaw0KDQoNCkBpbnN0YWxsDQpARnVuY3Rpb25XcmFw -cGVyDQpkZWYgY21wXyhzdGFjaywgZXhwcmVzc2lvbiwgZGljdGlvbmFyeSk6DQogICAgJycnDQog -ICAgVGhlIGNtcCBjb21iaW5hdG9yIHRha2VzIHR3byB2YWx1ZXMgYW5kIHRocmVlIHF1b3RlZCBw -cm9ncmFtcyBvbiB0aGUNCiAgICBzdGFjayBhbmQgcnVucyBvbmUgb2YgdGhlIHRocmVlIGRlcGVu -ZGluZyBvbiB0aGUgcmVzdWx0cyBvZiBjb21wYXJpbmcNCiAgICB0aGUgdHdvIHZhbHVlczoNCg0K -ICAgICAgICAgICBhIGIgW0ddIFtFXSBbTF0gY21wDQogICAgICAgIC0tLS0tLS0tLS0tLS0tLS0t -LS0tLS0tLS0gYSA+IGINCiAgICAgICAgICAgICAgICBHDQoNCiAgICAgICAgICAgYSBiIFtHXSBb -RV0gW0xdIGNtcA0KICAgICAgICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIGEgPSBiDQogICAg -ICAgICAgICAgICAgICAgIEUNCg0KICAgICAgICAgICBhIGIgW0ddIFtFXSBbTF0gY21wDQogICAg -ICAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gYSA8IGINCiAgICAgICAgICAgICAgICAgICAg -ICAgIEwNCg0KICAgICcnJw0KICAgIEwsIChFLCAoRywgKGIsIChhLCBzdGFjaykpKSkgPSBzdGFj -aw0KICAgIGV4cHJlc3Npb24gPSBjb25jYXQoRyBpZiBhID4gYiBlbHNlIEwgaWYgYSA8IGIgZWxz -ZSBFLCBleHByZXNzaW9uKQ0KICAgIHJldHVybiBzdGFjaywgZXhwcmVzc2lvbiwgZGljdGlvbmFy -eQ0KDQoNCkBpbnN0YWxsDQpAU2ltcGxlRnVuY3Rpb25XcmFwcGVyDQpkZWYgbGlzdF92aWV3ZXJz -KHN0YWNrKToNCiAgICAnJycNCiAgICBQdXQgYSBzdHJpbmcgb24gdGhlIHN0YWNrIHdpdGggc29t -ZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudGx5DQogICAgb3BlbiB2aWV3ZXJzLCBvbmUt -cGVyLWxpbmUuICBUaGlzIGlzIGtpbmQgb2YgYSBkZW1vIGZ1bmN0aW9uLCByYXRoZXINCiAgICB0 -aGFuIHNvbWV0aGluZyByZWFsbHkgdXNlZnVsLg0KICAgICcnJw0KICAgIGxpbmVzID0gW10NCiAg -ICBmb3IgeCwgVCBpbiBkLnRyYWNrczoNCiAgICAgICAgI2xpbmVzLmFwcGVuZCgneDogJWksIHc6 -ICVpLCAlcicgJSAoeCwgVC53LCBUKSkNCiAgICAgICAgZm9yIHksIFYgaW4gVC52aWV3ZXJzOg0K -ICAgICAgICAgICAgbGluZXMuYXBwZW5kKCd4OiAlaSB5OiAlaSBoOiAlaSAlciAlcicgJSAoeCwg -eSwgVi5oLCBWLmNvbnRlbnRfaWQsIFYpKQ0KICAgIHJldHVybiAnXG4nLmpvaW4obGluZXMpLCBz -dGFjaw0KDQoNCkBpbnN0YWxsDQpAU2ltcGxlRnVuY3Rpb25XcmFwcGVyDQpkZWYgc3BsaXRsaW5l -cyhzdGFjayk6DQogICAgJycnDQogICAgR2l2ZW4gYSBzdHJpbmcgb24gdGhlIHN0YWNrIHJlcGxh -Y2UgaXQgd2l0aCBhIGxpc3Qgb2YgdGhlIGxpbmVzIGluDQogICAgdGhlIHN0cmluZy4NCiAgICAn -JycNCiAgICB0ZXh0LCBzdGFjayA9IHN0YWNrDQogICAgYXNzZXJ0IGlzaW5zdGFuY2UodGV4dCwg -c3RyKSwgcmVwcih0ZXh0KQ0KICAgIHJldHVybiBsaXN0X3RvX3N0YWNrKHRleHQuc3BsaXRsaW5l -cygpKSwgc3RhY2sNCg0KDQpAaW5zdGFsbA0KQFNpbXBsZUZ1bmN0aW9uV3JhcHBlcg0KZGVmIGhp -eWEoc3RhY2spOg0KICAgICcnJw0KICAgIERlbW8gZnVuY3Rpb24gdG8gaW5zZXJ0ICJIaSBXb3Js -ZCEiIGludG8gdGhlIGN1cnJlbnQgdmlld2VyLCBpZiBhbnkuDQogICAgJycnDQogICAgaWYgZC5m -b2N1c2VkX3ZpZXdlcjoNCiAgICAgICAgZC5mb2N1c2VkX3ZpZXdlci5pbnNlcnQoJ0hpIFdvcmxk -IScpDQogICAgcmV0dXJuIHN0YWNrDQpQSwMEFAAAAAAA5GZ4TkXs5NYLAAAACwAAAAcAAABsb2cu -dHh0Sm95cHkgbG9nDQpQSwMEFAAAAAAA5GZ4Tmf2u80CBQAAAgUAAAgAAABtZW51LnR4dCAgbmFt -ZV92aWV3ZXINCiAgbGlzdF9yZXNvdXJjZXMNCiAgb3Blbl9yZXNvdXJjZV9hdF9nb29kX2xvY2F0 -aW9uDQogIGdvb2Rfdmlld2VyX2xvY2F0aW9uDQogIG9wZW5fdmlld2VyDQogIHNlZV9zdGFjaw0K -ICBzZWVfcmVzb3VyY2VzDQogIHNlZV9kZWZpbml0aW9ucw0KICBzZWVfbG9nDQogIHJlc2V0X2xv -Zw0KDQogIGluc2NyaWJlDQogIGV2YWx1YXRlDQoNCiAgcG9wIGNsZWFyICAgIGR1cCBzd2FwDQoN -CiAgYWRkIHN1YiBtdWwgZGl2IHRydWVkaXYgbW9kdWx1cyBkaXZtb2QNCiAgcG0gKysgLS0gc3Vt -IHByb2R1Y3QgcG93IHNxciBzcXJ0DQogIDwgPD0gPSA+PSA+IDw+DQogICYgPDwgPj4NCg0KICBp -IGR1cGRpcA0KDQohPSAlICYgKiAqZnJhY3Rpb24gKmZyYWN0aW9uMCArICsrIC0gLS0gLyA8IDw8 -IDw9IDw+ID0gPiA+PSA+PiA/IF4NCmFicyBhZGQgYW5hbW9ycGhpc20gYW5kIGFwcDEgYXBwMiBh -cHAzIGF0IGF2ZXJhZ2UNCmIgYmluYXJ5IGJyYW5jaA0KY2hvaWNlIGNsZWFyIGNsZWF2ZSBjb25j -YXQgY29ucw0KZGluZnJpcnN0IGRpcCBkaXBkIGRpcGRkIGRpc2Vuc3RhY2tlbiBkaXYgZGl2bW9k -IGRvd25fdG9femVybyBkcm9wDQpkdWRpcGQgZHVwIGR1cGQgZHVwZGlwDQplbnN0YWNrZW4gZXEN -CmZpcnN0IGZsYXR0ZW4gZmxvb3IgZmxvb3JkaXYNCmdjZCBnZSBnZW5yZWMgZ2V0aXRlbSBncmFu -ZF9yZXNldCBndA0KaGVscA0KaSBpZCBpZnRlIGluZnJhIGluc2NyaWJlDQprZXlfYmluZGluZ3MN -CmxlIGxlYXN0X2ZyYWN0aW9uIGxvb3AgbHNoaWZ0IGx0DQptYXAgbWF4IG1pbiBtb2QgbW9kdWx1 -cyBtb3VzZV9iaW5kaW5ncyBtdWwNCm5lIG5lZyBub3QgbnVsbGFyeQ0Kb2Ygb3Igb3Zlcg0KcGFt -IHBhcnNlIHBpY2sgcG0gcG9wIHBvcGQgcG9wZGQgcG9wb3AgcG93IHByZWQgcHJpbXJlYyBwcm9k -dWN0DQpxdW90ZWQNCnJhbmdlIHJhbmdlX3RvX3plcm8gcmVtIHJlbWFpbmRlciByZW1vdmUgcmVz -ZXRfbG9nIHJlc3QgcmV2ZXJzZQ0Kcm9sbDwgcm9sbD4gcm9sbGRvd24gcm9sbHVwIHJzaGlmdCBy -dW4NCnNlY29uZCBzZWxlY3Qgc2hhcmluZyBzaG93X2xvZyBzaHVudCBzaXplIHNvcnQgc3FyIHNx -cnQgc3RhY2sgc3RlcA0Kc3RlcF96ZXJvIHN1YiBzdWNjIHN1bSBzd2FhY2sgc3dhcCBzd29uY2F0 -IHN3b25zDQp0YWtlIHRlcm5hcnkgdGhpcmQgdGltZXMgdHJ1ZWRpdiB0cnV0aHkgdHVjaw0KdW5h -cnkgdW5jb25zIHVuaXF1ZSB1bml0IHVucXVvdGVkIHVuc3RhY2sNCnZvaWQNCndhcnJhbnR5IHdo -aWxlIHdvcmRzDQp4IHhvcg0KemlwDQpQSwMEFAAAAAAA5GZ4TgCrPcaOEAAAjhAAAAsAAABzY3Jh -dGNoLnR4dFdoYXQgaXMgaXQ/DQoNCkEgc2ltcGxlIEdyYXBoaWNhbCBVc2VyIEludGVyZmFjZSBm -b3IgdGhlIEpveSBwcm9ncmFtbWluZyBsYW5ndWFnZSwNCndyaXR0ZW4gdXNpbmcgUHlnYW1lIHRv -IGJ5cGFzcyBYMTEgZXQuIGFsLiwgbW9kZWxlZCBvbiB0aGUgT2Jlcm9uIE9TLCBhbmQNCmludGVu -ZGVkIHRvIGJlIGp1c3QgZnVuY3Rpb25hbCBlbm91Z2ggdG8gc3VwcG9ydCBib290c3RyYXBwaW5n -IGZ1cnRoZXIgSm95DQpkZXZlbG9wbWVudC4NCg0KSXQncyBiYXNpYyBmdW5jdGlvbmFsaXR5IGlz -IG1vcmUtb3ItbGVzcyBhcyBhIGNydWRlIHRleHQgZWRpdG9yIGFsb25nIHdpdGgNCmEgc2ltcGxl -IEpveSBydW50aW1lIChpbnRlcnByZXRlciwgc3RhY2ssIGFuZCBkaWN0aW9uYXJ5LikgIEl0IGF1 -dG8tIHNhdmVzDQphbnkgbmFtZWQgZmlsZXMgKGluIGEgdmVyc2lvbmVkIGhvbWUgZGlyZWN0b3J5 -KSBhbmQgeW91IGNhbiB3cml0ZSBuZXcgSm95DQpwcmltaXRpdmVzIGluIFB5dGhvbiBhbmQgSm95 -IGRlZmluaXRpb25zIGFuZCBpbW1lZGlhdGVseSBpbnN0YWxsIGFuZCB1c2UNCnRoZW0sIGFzIHdl -bGwgYXMgcmVjb3JkaW5nIHRoZW0gZm9yIHJldXNlIChhZnRlciByZXN0YXJ0cy4pDQoNCkN1cnJl -bnRseSwgdGhlcmUgYXJlIG9ubHkgdHdvIGtpbmRzIG9mIChpbnRlcmVzdGluZykgdmlld2Vyczog -VGV4dFZpZXdlcnMNCmFuZCBTdGFja1ZpZXdlci4gVGhlIFRleHRWaWV3ZXJzIGFyZSBjcnVkZSB0 -ZXh0IGVkaXRvcnMuICBUaGV5IHByb3ZpZGUNCmp1c3QgZW5vdWdoIGZ1bmN0aW9uYWxpdHkgdG8g -bGV0IHRoZSB1c2VyIHdyaXRlIHRleHQgYW5kIGNvZGUgKFB5dGhvbiBhbmQNCkpveSkgYW5kIGV4 -ZWN1dGUgSm95IGZ1bmN0aW9ucy4gIE9uZSBpbXBvcnRhbnQgdGhpbmcgdGhleSBkbyBpcw0KYXV0 -b21hdGljYWxseSBzYXZlIHRoZWlyIGNvbnRlbnQgYWZ0ZXIgY2hhbmdlcy4gIE5vIG1vcmUgbG9z -dCB3b3JrLg0KDQpUaGUgU3RhY2tWaWV3ZXIgaXMgYSBzcGVjaWFsaXplZCBUZXh0Vmlld2VyIHRo -YXQgc2hvd3MgdGhlIGNvbnRlbnRzIG9mIHRoZQ0KSm95IHN0YWNrIG9uZSBsaW5lIHBlciBzdGFj -ayBpdGVtLiAgSXQncyBhIHZlcnkgaGFuZHkgdmlzdWFsIGFpZCB0byBrZWVwDQp0cmFjayBvZiB3 -aGF0J3MgZ29pbmcgb24uICBUaGVyZSdzIGFsc28gYSBsb2cudHh0IGZpbGUgdGhhdCBnZXRzIHdy -aXR0ZW4NCnRvIHdoZW4gY29tbWFuZHMgYXJlIGV4ZWN1dGVkLCBhbmQgc28gcmVjb3JkcyB0aGUg -bG9nIG9mIHVzZXIgYWN0aW9ucyBhbmQNCnN5c3RlbSBldmVudHMuICBJdCB0ZW5kcyB0byBmaWxs -IHVwIHF1aWNrbHkgc28gdGhlcmUncyBhIHJlc2V0X2xvZyBjb21tYW5kDQp0aGF0IGNsZWFycyBp -dCBvdXQuDQoNClZpZXdlcnMgaGF2ZSAiZ3JvdyIgYW5kICJjbG9zZSIgaW4gdGhlaXIgbWVudSBi -YXJzLiAgVGhlc2UgYXJlIGJ1dHRvbnMuDQpXaGVuIHlvdSByaWdodC1jbGljayBvbiBncm93IGEg -dmlld2VyIGEgY29weSBpcyBjcmVhdGVkIHRoYXQgY292ZXJzIHRoYXQNCnZpZXdlcidzIGVudGly -ZSB0cmFjay4gIElmIHlvdSBncm93IGEgdmlld2VyIHRoYXQgYWxyZWFkeSB0YWtlcyB1cCBpdHMN -Cndob2xlIHRyYWNrIHRoZW4gYSBjb3B5IGlzIGNyZWF0ZWQgdGhhdCB0YWtlcyB1cCBhbiBhZGRp -dGlvbmFsIHRyYWNrLCB1cA0KdG8gdGhlIHdob2xlIHNjcmVlbi4gIENsb3NpbmcgYSB2aWV3ZXIg -anVzdCBkZWxldGVzIHRoYXQgdmlld2VyLCBhbmQgd2hlbg0KYSB0cmFjayBoYXMgbm8gbW9yZSB2 -aWV3ZXJzLCBpdCBpcyBkZWxldGVkIGFuZCB0aGF0IGV4cG9zZXMgYW55IHByZXZpb3VzDQp0cmFj -a3MgYW5kIHZpZXdlcnMgdGhhdCB3ZXJlIGhpZGRlbi4NCg0KKE5vdGU6IGlmIHlvdSBldmVyIGNs -b3NlIGFsbCB0aGUgdmlld2VycyBhbmQgYXJlIHNpdHRpbmcgYXQgYSBibGFuayBzY3JlZW4NCndp -dGggIG5vd2hlcmUgdG8gdHlwZSBhbmQgZXhlY3V0ZSBjb21tYW5kcywgcHJlc3MgdGhlIFBhdXNl -L0JyZWFrIGtleS4NClRoaXMgd2lsbCBvcGVuIGEgbmV3ICJ0cmFwIiB2aWV3ZXIgd2hpY2ggeW91 -IGNhbiB0aGVuIHVzZSB0byByZWNvdmVyLikNCg0KQ29waWVzIG9mIGEgdmlld2VyIGFsbCBzaGFy -ZSB0aGUgc2FtZSBtb2RlbCBhbmQgdXBkYXRlIHRoZWlyIGRpc3BsYXkgYXMgaXQNCmNoYW5nZXMu -IChJZiB5b3UgaGF2ZSB0d28gdmlld2VycyBvcGVuIG9uIHRoZSBzYW1lIG5hbWVkIHJlc291cmNl -IGFuZCBlZGl0DQpvbmUgeW91J2xsIHNlZSB0aGUgb3RoZXIgdXBkYXRlIGFzIHlvdSB0eXBlLikN -Cg0KVUkgR3VpZGUNCg0KbGVmdCBtb3VzZSBzZXRzIGN1cnNvciBpbiB0ZXh0LCBpbiBtZW51IGJh -ciByZXNpemVzIHZpZXdlciBpbnRlcmFjdGl2ZWx5DQoodGhpcyBpcyBhIGxpdHRsZSBidWdneSBp -biB0aGF0IHlvdSBjYW4gbW92ZSB0aGUgbW91c2UgcXVpY2tseSBhbmQgZ2V0DQpvdXRzaWRlIHRo -ZSBtZW51LCBsZWF2aW5nIHRoZSB2aWV3ZXIgaW4gdGhlICJyZXNpemluZyIgc3RhdGUuIFVudGls -IEkgZml4DQp0aGlzLCB0aGUgd29ya2Fyb3VuZCBpcyB0byBqdXN0IGdyYWIgdGhlIG1lbnUgYmFy -IGFnYWluIGFuZCB3aWdnbGUgaXQgYQ0KZmV3IHBpeGVscyBhbmQgbGV0IGdvLiAgVGhpcyB3aWxs -IHJlc2V0IHRoZSBtYWNoaW5lcnkuKQ0KDQpSaWdodCBtb3VzZSBleGVjdXRlcyBKb3kgY29tbWFu -ZCAoZnVuY3Rpb25zKSwgYW5kIHlvdSBjYW4gZHJhZyB3aXRoIHRoZQ0KcmlnaHQgYnV0dG9uIHRv -IGhpZ2hsaWdodCAod2VsbCwgdW5kZXJsaW5lKSBjb21tYW5kcy4gIFdvcmRzIHRoYXQgYXJlbid0 -DQpuYW1lcyBvZiBKb3kgY29tbWFuZHMgd29uJ3QgYmUgdW5kZXJsaW5lZC4gIFJlbGVhc2UgdGhl -IGJ1dHRvbiB0byBleGVjdXRlDQp0aGUgY29tbWFuZC4NCg0KVGhlIG1pZGRsZSBtb3VzZSBidXR0 -b24gKHVzdWFsbHkgYSB3aGVlbCB0aGVzZSBkYXlzKSBzY3JvbGxzIHRoZSB0ZXh0IGJ1dA0KeW91 -IGNhbiBhbHNvIGNsaWNrIGFuZCBkcmFnIGFueSB2aWV3ZXIgd2l0aCBpdCB0byBtb3ZlIHRoYXQg -dmlld2VyIHRvDQphbm90aGVyIHRyYWNrIG9yIHRvIGEgZGlmZmVyZW50IGxvY2F0aW9uIGluIHRo -ZSBzYW1lIHRyYWNrLiAgVGhlcmUncyBubw0KZGlyZWN0IHZpc3VhbCBmZWVkYmFjayBmb3IgdGhp -cyAoeWV0KSBidXQgdGhhdCBkb3Nlbid0IHNlZW0gdG8gaW1wYWlyIGl0cw0KdXNlZnVsbmVzcy4N -Cg0KRjEsIEYyIC0gc2V0IHNlbGVjdGlvbiBiZWdpbiBhbmQgZW5kIG1hcmtlcnMgKGNydWRlIGJ1 -dCB1c2FibGUuKQ0KDQpGMyAtIGNvcHkgc2VsZWN0ZWQgdGV4dCB0byB0aGUgdG9wIG9mIHRoZSBz -dGFjay4NCg0KU2hpZnQtRjMgLSBhcyBjb3B5IHRoZW4gcnVuICJwYXJzZSIgY29tbWFuZCBvbiB0 -aGUgc3RyaW5nLg0KDQpGNCAtIGN1dCBzZWxlY3RlZCB0ZXh0IHRvIHRoZSB0b3Agb2YgdGhlIHN0 -YWNrLg0KDQpTaGlmdC1GNCAtIGFzIGN1dCB0aGVuIHJ1biAicG9wIiAoZGVsZXRlIHNlbGVjdGlv -bi4pDQoNCkpveQ0KDQpQcmV0dHkgbXVjaCBhbGwgb2YgdGhlIHJlc3Qgb2YgdGhlIGZ1bmN0aW9u -YWxpdHkgb2YgdGhlIHN5c3RlbSBpcyBwcm92aWRlZA0KYnkgZXhlY3V0aW5nIEpveSBjb21tYW5k -cyAoYWthIGZ1bmN0aW9ucywgYWthICJ3b3JkcyIgaW4gRm9ydGgpIGJ5IHJpZ2h0LQ0KY2xpY2tp -bmcgb24gdGhlaXIgbmFtZXMgaW4gYW55IHRleHQuDQoNClRvIGdldCBoZWxwIG9uIGEgSm95IGZ1 -bmN0aW9uIHNlbGVjdCB0aGUgbmFtZSBvZiB0aGUgZnVuY3Rpb24gaW4gYQ0KVGV4dFZpZXdlciB1 -c2luZyBGMSBhbmQgRjIsIHRoZW4gcHJlc3Mgc2hpZnQtRjMgdG8gcGFyc2UgdGhlIHNlbGVjdGlv -bi4NClRoZSBmdW5jdGlvbiAocmVhbGx5IGl0cyBTeW1ib2wpIHdpbGwgYXBwZWFyIG9uIHRoZSBz -dGFjayBpbiBicmFja2V0cyAoYQ0KInF1b3RlZCBwcm9ncmFtIiBzdWNoIGFzICJbcG9wXSIuKSAg -VGhlbiByaWdodC1jbGljayBvbiB0aGUgd29yZCBoZWxwIGluDQphbnkgVGV4dFZpZXdlciAoaWYg -aXQncyBub3QgYWxyZWFkeSB0aGVyZSwganVzdCB0eXBlIGl0IGluIHNvbWV3aGVyZS4pDQpUaGlz -IHdpbGwgcHJpbnQgdGhlIGRvY3N0cmluZyBvciBkZWZpbml0aW9uIG9mIHRoZSB3b3JkIChmdW5j -dGlvbikgdG8NCnN0ZG91dC4gIEF0IHNvbWUgcG9pbnQgSSdsbCB3cml0ZSBhIHRoaW5nIHRvIHNl -bmQgdGhhdCB0byB0aGUgbG9nLnR4dCBmaWxlDQppbnN0ZWFkLCBidXQgZm9yIG5vdyBsb29rIGZv -ciBvdXRwdXQgaW4gdGhlIHRlcm1pbmFsLg0KUEsDBBQAAAAAAORmeE53f5peAwAAAAMAAAAMAAAA -c3RhY2sucGlja2xlKHQuUEsBAhQAFAAAAAAA5GZ4Tv3gGVF+AwAAfgMAAA8AAAAAAAAAAAAAALaB -AAAAAGRlZmluaXRpb25zLnR4dFBLAQIUABQAAAAAACFrpk7/HHjxGBYAABgWAAAKAAAAAAAAAAAA -AAC2gasDAABsaWJyYXJ5LnB5UEsBAhQAFAAAAAAA5GZ4TkXs5NYLAAAACwAAAAcAAAAAAAAAAAAA -ALaB6xkAAGxvZy50eHRQSwECFAAUAAAAAADkZnhOZ/a7zQIFAAACBQAACAAAAAAAAAAAAAAAtoEb -GgAAbWVudS50eHRQSwECFAAUAAAAAADkZnhOAKs9xo4QAACOEAAACwAAAAAAAAAAAAAAtoFDHwAA -c2NyYXRjaC50eHRQSwECFAAUAAAAAADkZnhOd3+aXgMAAAADAAAADAAAAAAAAAAAAAAAtoH6LwAA -c3RhY2sucGlja2xlUEsFBgAAAAAGAAYAUwEAACcwAAAAAA=='''))) - - -if __name__ == '__main__': - print(create_data()) diff --git a/joy/vui/main.py b/joy/vui/main.py deleted file mode 100644 index 76daad6..0000000 --- a/joy/vui/main.py +++ /dev/null @@ -1,179 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2019 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# -''' - -Main Module -====================================== - -Pulls everything together. - -''' -from __future__ import print_function -from __future__ import division -from past.builtins import execfile -from builtins import object -from past.utils import old_div -import os, sys, traceback -import pygame -from joy.library import initialize, DefinitionWrapper, SimpleFunctionWrapper -from joy.vui import core, display, persist_task - - -FULLSCREEN = '-f' in sys.argv - - -JOY_HOME = os.environ.get('JOY_HOME') -if JOY_HOME is None: - JOY_HOME = os.path.expanduser('~/.thun') - if not os.path.isabs(JOY_HOME): - raise ValueError('what directory?') - - -def load_definitions(pt, dictionary): - '''Load definitions from ``definitions.txt``.''' - lines = pt.open('definitions.txt')[1] - for line in lines: - if '==' in line: - DefinitionWrapper.add_def(line, dictionary) - - -def load_primitives(home, name_space): - '''Load primitives from ``library.py``.''' - fn = os.path.join(home, 'library.py') - if os.path.exists(fn): - execfile(fn, name_space) - - -def init(): - ''' - Initialize the system. - - * Init PyGame - * Create main window - * Start the PyGame clock - * Set the event mask - * Create the PersistTask - - ''' - print('Initializing Pygame...') - pygame.init() - print('Creating window...') - if FULLSCREEN: - screen = pygame.display.set_mode() - else: - screen = pygame.display.set_mode((1024, 768)) - clock = pygame.time.Clock() - pygame.event.set_allowed(None) - pygame.event.set_allowed(core.ALLOWED_EVENTS) - pt = persist_task.PersistTask(JOY_HOME) - return screen, clock, pt - - -def init_context(screen, clock, pt): - ''' - More initialization - - * Create the Joy dictionary - * Create the Display - * Open the log, menu, and scratch text viewers, and the stack pickle - * Start the main loop - * Create the World object - * Register PersistTask and World message handlers with the Display - * Load user function definitions. - - ''' - D = initialize() - d = display.Display( - screen, - D.__contains__, - *((144 - 89, 144, 89) if FULLSCREEN else (89, 144)) - ) - log = d.init_text(pt, 0, 0, 'log.txt') - tho = d.init_text(pt, 0, old_div(d.h, 3), 'menu.txt') - t = d.init_text(pt, old_div(d.w, 2), 0, 'scratch.txt') - loop = core.TheLoop(d, clock) - stack_id, stack_holder = pt.open('stack.pickle') - world = core.World(stack_id, stack_holder, D, d.broadcast, log) - loop.install_task(pt.task_run, 10000) # save files every ten seconds - d.handlers.append(pt.handle) - d.handlers.append(world.handle) - load_definitions(pt, D) - return locals() - - -def error_guard(loop, n=10): - ''' - Run a loop function, retry for ``n`` exceptions. - Prints tracebacks on ``sys.stderr``. - ''' - error_count = 0 - while error_count < n: - try: - loop() - break - except: - traceback.print_exc(file=sys.stderr) - error_count += 1 - - -class FileFaker(object): - '''Pretends to be a file object but writes to log instead.''' - - def __init__(self, log): - self.log = log - - def write(self, text): - '''Write text to log.''' - self.log.append(text) - - def flush(self): - pass - - -def main(screen, clock, pt): - ''' - Main function. - - * Call ``init_context()`` - * Load primitives - * Create an ``evaluate`` function that lets you just eval some Python code - * Redirect ``stdout`` to the log using a ``FileFaker`` object, and... - * Start the main loop. - ''' - name_space = init_context(screen, clock, pt) - load_primitives(pt.home, name_space.copy()) - - @SimpleFunctionWrapper - def evaluate(stack): - '''Evaluate the Python code text on the top of the stack.''' - code, stack = stack - exec(code, name_space.copy()) - return stack - - name_space['D']['evaluate'] = evaluate - - - sys.stdout, old_stdout = FileFaker(name_space['log']), sys.stdout - try: - error_guard(name_space['loop'].loop) - finally: - sys.stdout = old_stdout - - return name_space['d'] diff --git a/joy/vui/persist_task.py b/joy/vui/persist_task.py deleted file mode 100644 index 8fb11f4..0000000 --- a/joy/vui/persist_task.py +++ /dev/null @@ -1,274 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2019 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# -''' - -Persist Task -=========================== - -This module deals with persisting the "resources" (text files and the -stack) to the git repo in the ``JOY_HOME`` directory. - -''' -from __future__ import print_function -from builtins import object -import os, pickle, traceback -from collections import Counter -from dulwich.errors import NotGitRepository -from dulwich.repo import Repo -from joy.vui import core, init_joy_home - - -def open_repo(repo_dir=None, initialize=False): - ''' - Open, or create, and return a Dulwich git repo object for the given - directory. If the dir path doesn't exist it will be created. If it - does exist but isn't a repo the result depends on the ``initialize`` - argument. If it is ``False`` (the default) a ``NotGitRepository`` - exception is raised, otherwise ``git init`` is effected in the dir. - ''' - if not os.path.exists(repo_dir): - os.makedirs(repo_dir, 0o700) - return init_repo(repo_dir) - try: - return Repo(repo_dir) - except NotGitRepository: - if initialize: - return init_repo(repo_dir) - raise - - -def init_repo(repo_dir): - ''' - Initialize a git repository in the directory. Stage and commit all - files (toplevel, not those in subdirectories if any) in the dir. - ''' - repo = Repo.init(repo_dir) - init_joy_home.initialize(repo_dir) - repo.stage([ - fn - for fn in os.listdir(repo_dir) - if os.path.isfile(os.path.join(repo_dir, fn)) - ]) - repo.do_commit('Initial commit.', committer=core.COMMITTER) - return repo - - -def make_repo_relative_path_maker(repo): - ''' - Helper function to return a function that returns a path given a path, - that's relative to the repository. - ''' - c = repo.controldir() - def repo_relative_path(path): - return os.path.relpath(path, os.path.commonprefix((c, path))) - return repo_relative_path - - -class Resource(object): - ''' - Handle the content of a text files as a list of lines, deal with - saving it and staging the changes to a repo. - ''' - - def __init__(self, filename, repo_relative_filename, thing=None): - self.filename = filename - self.repo_relative_filename = repo_relative_filename - self.thing = thing or self._from_file(open(filename)) - - def _from_file(self, f): - return f.read().splitlines() - - def _to_file(self, f): - for line in self.thing: - print(line, file=f) - - def persist(self, repo): - ''' - Save the lines to the file and stage the file in the repo. - ''' - with open(self.filename, 'w') as f: - os.chmod(self.filename, 0o600) - self._to_file(f) - f.flush() - os.fsync(f.fileno()) - # For goodness's sake, write it to the disk already! - repo.stage([self.repo_relative_filename]) - - -class PickledResource(Resource): - ''' - A ``Resource`` subclass that uses ``pickle`` on its file/thing. - ''' - - def _from_file(self, f): - return [pickle.load(f)] - - def _to_file(self, f): - pickle.dump(self.thing[0], f, protocol=2) - - -class PersistTask(object): - ''' - This class deals with saving changes to the git repo. - ''' - - LIMIT = 10 - MAX_SAVE = 10 - - def __init__(self, home): - self.home = home - self.repo = open_repo(home) - self._r = make_repo_relative_path_maker(self.repo) - self.counter = Counter() - self.store = {} - - def open(self, name): - ''' - Look up the named file in home and return its content_id and data. - ''' - fn = os.path.join(self.home, name) - content_id = name # hash(fn) - try: - resource = self.store[content_id] - except KeyError: - R = PickledResource if name.endswith('.pickle') else Resource - resource = self.store[content_id] = R(fn, self._r(fn)) - return content_id, resource.thing - - def handle(self, message): - ''' - Handle messages, dispatch to ``handle_FOO()`` methods. - ''' - if isinstance(message, core.OpenMessage): - self.handle_open(message) - elif isinstance(message, core.ModifyMessage): - self.handle_modify(message) - elif isinstance(message, core.PersistMessage): - self.handle_persist(message) - elif isinstance(message, core.ShutdownMessage): - for content_id in self.counter: - self.store[content_id].persist(self.repo) - self.commit('shutdown') - - def handle_open(self, message): - ''' - Foo. - ''' - try: - message.content_id, message.thing = self.open(message.name) - except: - message.traceback = traceback.format_exc() - message.status = core.ERROR - else: - message.status = core.SUCCESS - - def handle_modify(self, message): - ''' - Foo. - ''' - try: - content_id = message.details['content_id'] - except KeyError: - return - if not content_id: - return - self.counter[content_id] += 1 - if self.counter[content_id] > self.LIMIT: - self.persist(content_id) - self.commit('due to activity') - - def handle_persist(self, message): - ''' - Foo. - ''' - try: - resource = self.store[message.content_id] - except KeyError: - resource = self.handle_persist_new(message) - resource.persist(self.repo) - self.commit('by request from %r' % (message.sender,)) - - def handle_persist_new(self, message): - ''' - Foo. - ''' - name = message.content_id - check_filename(name) - fn = os.path.join(self.home, name) - thing = message.details['thing'] - R = PickledResource if name.endswith('.pickle') else Resource # !!! refactor! - resource = self.store[name] = R(fn, self._r(fn), thing) - return resource - - def persist(self, content_id): - ''' - Persist a resource. - ''' - del self.counter[content_id] - self.store[content_id].persist(self.repo) - - def task_run(self): - ''' - Stage any outstanding changes. - ''' - if not self.counter: - return - for content_id, _ in self.counter.most_common(self.MAX_SAVE): - self.persist(content_id) - self.commit() - - def commit(self, message='auto-commit'): - ''' - Commit. - ''' - return self.repo.do_commit(message, committer=core.COMMITTER) - - def scan(self): - ''' - Return a sorted list of all the files in the home dir. - ''' - return sorted([ - fn - for fn in os.listdir(self.home) - if os.path.isfile(os.path.join(self.home, fn)) - ]) - - -def check_filename(name): - ''' - Sanity checks for filename. - ''' - # TODO: improve this... - if len(name) > 64: - raise ValueError('bad name %r' % (name,)) - left, dot, right = name.partition('.') - if not left.isalnum() or dot and not right.isalnum(): - raise ValueError('bad name %r' % (name,)) - - -if __name__ == '__main__': - JOY_HOME = os.path.expanduser('~/.thun') - pt = PersistTask(JOY_HOME) - content_id, thing = pt.open('stack.pickle') - pt.persist(content_id) - print(pt.counter) - mm = core.ModifyMessage(None, None, content_id=content_id) - pt.handle(mm) - print(pt.counter) diff --git a/joy/vui/stack_viewer.py b/joy/vui/stack_viewer.py deleted file mode 100644 index 0ac7928..0000000 --- a/joy/vui/stack_viewer.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2019 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# -''' - -Stack Viewer -================= - -''' -from builtins import map, str -from joy.utils.stack import expression_to_string, iter_stack -from joy.vui import core, text_viewer - - -MAX_WIDTH = 64 - - -def fsi(item): - '''Format Stack Item''' - if isinstance(item, tuple): - res = '[%s]' % expression_to_string(item) - elif isinstance(item, str): - res = '"%s"' % item - else: - res = str(item) - if len(res) > MAX_WIDTH: - return res[:MAX_WIDTH - 3] + '...' - return res - - -class StackViewer(text_viewer.TextViewer): - - def __init__(self, surface): - super(StackViewer, self).__init__(surface) - self.stack_holder = None - self.content_id = 'stack viewer' - - def _attach(self, display): - if self.stack_holder: - return - om = core.OpenMessage(self, 'stack.pickle') - display.broadcast(om) - if om.status != core.SUCCESS: - raise RuntimeError('stack unavailable') - self.stack_holder = om.thing - - def _update(self): - self.lines[:] = list(map(fsi, iter_stack(self.stack_holder[0]))) or [''] - - def focus(self, display): - self._attach(display) - super(StackViewer, self).focus(display) - - def handle(self, message): - if (isinstance(message, core.ModifyMessage) - and message.subject is self.stack_holder - ): - self._update() - self.draw_body() diff --git a/joy/vui/text_viewer.py b/joy/vui/text_viewer.py deleted file mode 100644 index 70ebe90..0000000 --- a/joy/vui/text_viewer.py +++ /dev/null @@ -1,704 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2019 Simon Forman -# -# This file is part of Thun -# -# Thun is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Thun is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Thun. If not see . -# -''' - -Text Viewer -================= - -''' -from __future__ import print_function -from __future__ import division -from builtins import object, range, str, zip -from past.builtins import basestring -from past.utils import old_div -import string -import pygame -from joy.utils.stack import expression_to_string -from joy.vui.core import ( - ARROW_KEYS, - BACKGROUND as BG, - FOREGROUND as FG, - CommandMessage, - ModifyMessage, - OpenMessage, - SUCCESS, - push, - ) -from joy.vui import viewer, font_data -#reload(viewer) - - -MenuViewer = viewer.MenuViewer - - -SELECTION_COLOR = 235, 255, 0, 32 -SELECTION_KEYS = { - pygame.K_F1, - pygame.K_F2, - pygame.K_F3, - pygame.K_F4, - } -STACK_CHATTER_KEYS = { - pygame.K_F5, - pygame.K_F6, - pygame.K_F7, - pygame.K_F8, - } - - -def _is_command(display, word): - return display.lookup(word) or word.isdigit() or all( - not s or s.isdigit() for s in word.split('.', 1) - ) and len(word) > 1 - - -def format_stack_item(content): - if isinstance(content, tuple): - return '[%s]' % expression_to_string(content) - return str(content) - - -class Font(object): - - IMAGE = pygame.image.load(font_data.data, 'Iosevka12.BMP') - LOOKUP = (string.ascii_letters + - string.digits + - '''@#$&_~|`'"%^=-+*/\\<>[]{}(),.;:!?''') - - def __init__(self, char_w=8, char_h=19, line_h=19): - self.char_w = char_w - self.char_h = char_h - self.line_h = line_h - - def size(self, text): - return self.char_w * len(text), self.line_h - - def render(self, text): - surface = pygame.Surface(self.size(text)) - surface.fill(BG) - x = 0 - for ch in text: - if not ch.isspace(): - try: - i = self.LOOKUP.index(ch) - except ValueError: - # render a lil box... - r = (x + 1, old_div(self.line_h, 2) - 3, - self.char_w - 2, old_div(self.line_h, 2)) - pygame.draw.rect(surface, FG, r, 1) - else: - iy, ix = divmod(i, 26) - ix *= self.char_w - iy *= self.char_h - area = ix, iy, self.char_w, self.char_h - surface.blit(self.IMAGE, (x, 0), area) - x += self.char_w - return surface - - def __contains__(self, char): - assert len(char) == 1, repr(char) - return char in self.LOOKUP - - -FONT = Font() - - -class TextViewer(MenuViewer): - - MINIMUM_HEIGHT = FONT.line_h + 3 - CLOSE_TEXT = FONT.render('close') - GROW_TEXT = FONT.render('grow') - - class Cursor(object): - - def __init__(self, viewer): - self.v = viewer - self.x = self.y = 0 - self.w, self.h = 2, FONT.line_h - self.mem = pygame.Surface((self.w, self.h)) - self.can_fade = False - - def set_to(self, x, y): - self.fade() - self.x, self.y = x, y - self.draw() - - def draw(self): - r = self.x * FONT.char_w, self.screen_y(), self.w, self.h - self.mem.blit(self.v.body_surface, (0, 0), r) - self.v.body_surface.fill(FG, r) - self.can_fade = True - - def fade(self): - if self.can_fade: - dest = self.x * FONT.char_w, self.screen_y() - self.v.body_surface.blit(self.mem, dest) - self.can_fade = False - - def screen_y(self, row=None): - if row is None: row = self.y - return (row - self.v.at_line) * FONT.line_h - - def up(self, _mod): - if self.y: - self.fade() - self.y -= 1 - self.x = min(self.x, len(self.v.lines[self.y])) - self.draw() - - def down(self, _mod): - if self.y < len(self.v.lines) - 1: - self.fade() - self.y += 1 - self.x = min(self.x, len(self.v.lines[self.y])) - self.draw() - self._check_scroll() - - def left(self, _mod): - if self.x: - self.fade() - self.x -= 1 - self.draw() - elif self.y: - self.fade() - self.y -= 1 - self.x = len(self.v.lines[self.y]) - self.draw() - self._check_scroll() - - def right(self, _mod): - if self.x < len(self.v.lines[self.y]): - self.fade() - self.x += 1 - self.draw() - elif self.y < len(self.v.lines) - 1: - self.fade() - self.y += 1 - self.x = 0 - self.draw() - self._check_scroll() - - def _check_scroll(self): - if self.y < self.v.at_line: - self.v.scroll_down() - elif self.y > self.v.at_line + self.v.h_in_lines: - self.v.scroll_up() - - def __init__(self, surface): - self.cursor = self.Cursor(self) - MenuViewer.__init__(self, surface) - self.lines = [''] - self.content_id = None - self.at_line = 0 - self.bg = BG - self.command = self.command_rect = None - self._sel_start = self._sel_end = None - - def resurface(self, surface): - self.cursor.fade() - MenuViewer.resurface(self, surface) - - w, h = self.CLOSE_TEXT.get_size() - self.close_rect = pygame.rect.Rect(self.w - 2 - w, 1, w, h) - w, h = self.GROW_TEXT.get_size() - self.grow_rect = pygame.rect.Rect(1, 1, w, h) - - self.body_surface = surface.subsurface(self.body_rect) - self.line_w = old_div(self.body_rect.w, FONT.char_w) + 1 - self.h_in_lines = old_div(self.body_rect.h, FONT.line_h) - 1 - self.command_rect = self.command = None - self._sel_start = self._sel_end = None - - def handle(self, message): - if super(TextViewer, self).handle(message): - return - if (isinstance(message, ModifyMessage) - and message.subject is self.lines - ): - # TODO: check self.at_line - self.draw_body() - - # Drawing - - def draw_menu(self): - #MenuViewer.draw_menu(self) - self.surface.blit(self.GROW_TEXT, (1, 1)) - self.surface.blit(self.CLOSE_TEXT, - (self.w - 2 - self.close_rect.w, 1)) - if self.content_id: - self.surface.blit(FONT.render('| ' + self.content_id), - (self.grow_rect.w + FONT.char_w + 3, 1)) - self.surface.fill( # light grey background - (196, 196, 196), - (0, 0, self.w - 1, self.MINIMUM_HEIGHT), - pygame.BLEND_MULT - ) - - def draw_body(self): - MenuViewer.draw_body(self) - ys = range(0, self.body_rect.height, FONT.line_h) - ls = self.lines[self.at_line:self.at_line + self.h_in_lines + 2] - for y, line in zip(ys, ls): - self.draw_line(y, line) - - def draw_line(self, y, line): - surface = FONT.render(line[:self.line_w]) - self.body_surface.blit(surface, (0, y)) - - def _redraw_line(self, row): - try: line = self.lines[row] - except IndexError: line = ' ' * self.line_w - else: - n = self.line_w - len(line) - if n > 0: line = line + ' ' * n - self.draw_line(self.cursor.screen_y(row), line) - - # General Functionality - - def focus(self, display): - self.cursor.v = self - self.cursor.draw() - - def unfocus(self): - self.cursor.fade() - - def scroll_up(self): - if self.at_line < len(self.lines) - 1: - self._fade_command() - self._deselect() - self._sel_start = self._sel_end = None - self.at_line += 1 - self.body_surface.scroll(0, -FONT.line_h) - row = self.h_in_lines + self.at_line - self._redraw_line(row) - self._redraw_line(row + 1) - self.cursor.draw() - - def scroll_down(self): - if self.at_line: - self._fade_command() - self._deselect() - self._sel_start = self._sel_end = None - self.at_line -= 1 - self.body_surface.scroll(0, FONT.line_h) - self._redraw_line(self.at_line) - self.cursor.draw() - - def command_down(self, display, x, y): - if self.command_rect and self.command_rect.collidepoint(x, y): - return - self._fade_command() - line, column, _row = self.at(x, y) - word_start = line.rfind(' ', 0, column) + 1 - word_end = line.find(' ', column) - if word_end == -1: word_end = len(line) - word = line[word_start:word_end] - if not _is_command(display, word): - return - r = self.command_rect = pygame.Rect( - word_start * FONT.char_w, # x - old_div(y, FONT.line_h) * FONT.line_h, # y - len(word) * FONT.char_w, # w - FONT.line_h # h - ) - pygame.draw.line(self.body_surface, FG, r.bottomleft, r.bottomright) - self.command = word - - def command_up(self, display): - if self.command: - command = self.command - self._fade_command() - display.broadcast(CommandMessage(self, command)) - - def _fade_command(self): - self.command = None - r, self.command_rect = self.command_rect, None - if r: - pygame.draw.line(self.body_surface, BG, r.bottomleft, r.bottomright) - - def at(self, x, y): - ''' - Given screen coordinates return the line, row, and column of the - character there. - ''' - row = self.at_line + old_div(y, FONT.line_h) - try: - line = self.lines[row] - except IndexError: - row = len(self.lines) - 1 - line = self.lines[row] - column = len(line) - else: - column = min(old_div(x, FONT.char_w), len(line)) - return line, column, row - - # Event Processing - - def body_click(self, display, x, y, button): - if button == 1: - _line, column, row = self.at(x, y) - self.cursor.set_to(column, row) - elif button == 2: - if pygame.KMOD_SHIFT & pygame.key.get_mods(): - self.scroll_up() - else: - self.scroll_down() - elif button == 3: - self.command_down(display, x, y) - elif button == 4: self.scroll_down() - elif button == 5: self.scroll_up() - - def menu_click(self, display, x, y, button): - if MenuViewer.menu_click(self, display, x, y, button): - return True - - def mouse_up(self, display, x, y, button): - if MenuViewer.mouse_up(self, display, x, y, button): - return True - elif button == 3 and self.body_rect.collidepoint(x, y): - self.command_up(display) - - def mouse_motion(self, display, x, y, rel_x, rel_y, button0, button1, button2): - if MenuViewer.mouse_motion(self, display, x, y, rel_x, rel_y, - button0, button1, button2): - return True - if (button0 - and display.focused_viewer is self - and self.body_rect.collidepoint(x, y) - ): - bx, by = self.body_rect.topleft - _line, column, row = self.at(x - bx, y - by) - self.cursor.set_to(column, row) - elif button2 and self.body_rect.collidepoint(x, y): - bx, by = self.body_rect.topleft - self.command_down(display, x - bx, y - by) - - def close(self): - self._sel_start = self._sel_end = None - - def key_down(self, display, uch, key, mod): - - if key in SELECTION_KEYS: - self._selection_key(display, key, mod) - return - if key in STACK_CHATTER_KEYS: - self._stack_chatter_key(display, key, mod) - return - if key in ARROW_KEYS: - self._arrow_key(key, mod) - return - - line, i = self.lines[self.cursor.y], self.cursor.x - modified = () - if key == pygame.K_RETURN: - self._return_key(mod, line, i) - modified = True - elif key == pygame.K_BACKSPACE: - modified = self._backspace_key(mod, line, i) - elif key == pygame.K_DELETE: - modified = self._delete_key(mod, line, i) - elif key == pygame.K_INSERT: - modified = self._insert_key(display, mod, line, i) - elif uch and uch in FONT or uch == ' ': - self._printable_key(uch, mod, line, i) - modified = True - else: - print('%r %i %s' % (uch, key, bin(mod))) - - if modified: - # The selection is fragile. - self._deselect() - self._sel_start = self._sel_end = None - message = ModifyMessage( - self, self.lines, content_id=self.content_id) - display.broadcast(message) - - def _stack_chatter_key(self, display, key, mod): - if key == pygame.K_F5: - if mod & pygame.KMOD_SHIFT: - command = 'roll<' - else: - command = 'swap' - elif key == pygame.K_F6: - if mod & pygame.KMOD_SHIFT: - command = 'roll>' - else: - command = 'dup' - elif key == pygame.K_F7: - if mod & pygame.KMOD_SHIFT: - command = 'tuck' - else: - command = 'over' -## elif key == pygame.K_F8: -## if mod & pygame.KMOD_SHIFT: -## command = '' -## else: -## command = '' - else: - return - display.broadcast(CommandMessage(self, command)) - - # Selection Handling - - def _selection_key(self, display, key, mod): - self.cursor.fade() - self._deselect() - if key == pygame.K_F1: # set sel start - self._sel_start = self.cursor.y, self.cursor.x - self._update_selection() - elif key == pygame.K_F2: # set sel end - self._sel_end = self.cursor.y, self.cursor.x - self._update_selection() - elif key == pygame.K_F3: # copy - if mod & pygame.KMOD_SHIFT: - self._parse_selection(display) - else: - self._copy_selection(display) - self._update_selection() - elif key == pygame.K_F4: # cut or delete - if mod & pygame.KMOD_SHIFT: - self._delete_selection(display) - else: - self._cut_selection(display) - self.cursor.draw() - - def _deselect(self): - if self._has_selection(): - srow, erow = self._sel_start[0], self._sel_end[0] - # Just erase the whole selection. - for r in range(min(srow, erow), max(srow, erow) + 1): - self._redraw_line(r) - - def _copy_selection(self, display): - if push(self, self._get_selection(), display.broadcast) == SUCCESS: - return True -## om = OpenMessage(self, 'stack.pickle') -## display.broadcast(om) -## if om.status == SUCCESS: -## selection = self._get_selection() -## om.thing[0] = selection, om.thing[0] -## display.broadcast(ModifyMessage( -## self, om.thing, content_id=om.content_id)) - - def _parse_selection(self, display): - if self._has_selection(): - if self._copy_selection(display): - display.broadcast(CommandMessage(self, 'parse')) - - def _cut_selection(self, display): - if self._has_selection(): - if self._copy_selection(display): - self._delete_selection(display) - - def _delete_selection(self, display): - if not self._has_selection(): - return - self.cursor.fade() - srow, scolumn, erow, ecolumn = self._selection_coords() - if srow == erow: - line = self.lines[srow] - self.lines[srow] = line[:scolumn] + line[ecolumn:] - else: - left = self.lines[srow][:scolumn] - right = self.lines[erow][ecolumn:] - self.lines[srow:erow + 1] = [left + right] - self.draw_body() - self.cursor.set_to(srow, scolumn) - display.broadcast(ModifyMessage( - self, self.lines, content_id=self.content_id)) - - def _has_selection(self): - return (self._sel_start - and self._sel_end - and self._sel_start != self._sel_end) - - def _get_selection(self): - '''Return the current selection if any as a single string.''' - if not self._has_selection(): - return '' - srow, scolumn, erow, ecolumn = self._selection_coords() - if srow == erow: - return str(self.lines[srow][scolumn:ecolumn]) - lines = [] - assert srow < erow - while srow <= erow: - line = self.lines[srow] - e = ecolumn if srow == erow else len(line) - lines.append(line[scolumn:e]) - scolumn = 0 - srow += 1 - return str('\n'.join(lines)) - - def _selection_coords(self): - (srow, scolumn), (erow, ecolumn) = ( - min(self._sel_start, self._sel_end), - max(self._sel_start, self._sel_end) - ) - return srow, scolumn, erow, ecolumn - - def _update_selection(self): - if self._sel_start is None and self._sel_end: - self._sel_start = self._sel_end - elif self._sel_end is None and self._sel_start: - self._sel_end = self._sel_start - assert self._sel_start and self._sel_end - if self._sel_start != self._sel_end: - for rect in self._iter_selection_rectangles(): - self.body_surface.fill( - SELECTION_COLOR, - rect, - pygame.BLEND_RGBA_MULT - ) - - def _iter_selection_rectangles(self, ): - srow, scolumn, erow, ecolumn = self._selection_coords() - if srow == erow: - yield ( - scolumn * FONT.char_w, - self.cursor.screen_y(srow), - (ecolumn - scolumn) * FONT.char_w, - FONT.line_h - ) - return - lines = self.lines[srow:erow + 1] - assert len(lines) >= 2 - first_line = lines[0] - yield ( - scolumn * FONT.char_w, - self.cursor.screen_y(srow), - (len(first_line) - scolumn) * FONT.char_w, - FONT.line_h - ) - yield ( - 0, - self.cursor.screen_y(erow), - ecolumn * FONT.char_w, - FONT.line_h - ) - if len(lines) > 2: - for line in lines[1:-1]: - srow += 1 - yield ( - 0, - self.cursor.screen_y(srow), - len(line) * FONT.char_w, - FONT.line_h - ) - - # Key Handlers - - def _printable_key(self, uch, _mod, line, i): - line = line[:i] + uch + line[i:] - self.lines[self.cursor.y] = line - self.cursor.fade() - self.cursor.x += 1 - self.draw_line(self.cursor.screen_y(), line) - self.cursor.draw() - - def _backspace_key(self, _mod, line, i): - res = False - if i: - line = line[:i - 1] + line[i:] - self.lines[self.cursor.y] = line - self.cursor.fade() - self.cursor.x -= 1 - self.draw_line(self.cursor.screen_y(), line + ' ') - self.cursor.draw() - res = True - elif self.cursor.y: - y = self.cursor.y - left, right = self.lines[y - 1:y + 1] - self.lines[y - 1:y + 1] = [left + right] - self.cursor.x = len(left) - self.cursor.y -= 1 - self.draw_body() - self.cursor.draw() - res = True - return res - - def _delete_key(self, _mod, line, i): - res = False - if i < len(line): - line = line[:i] + line[i + 1:] - self.lines[self.cursor.y] = line - self.cursor.fade() - self.draw_line(self.cursor.screen_y(), line + ' ') - self.cursor.draw() - res = True - elif self.cursor.y < len(self.lines) - 1: - y = self.cursor.y - left, right = self.lines[y:y + 2] - self.lines[y:y + 2] = [left + right] - self.draw_body() - self.cursor.draw() - res = True - return res - - def _arrow_key(self, key, mod): - if key == pygame.K_UP: self.cursor.up(mod) - elif key == pygame.K_DOWN: self.cursor.down(mod) - elif key == pygame.K_LEFT: self.cursor.left(mod) - elif key == pygame.K_RIGHT: self.cursor.right(mod) - - def _return_key(self, _mod, line, i): - self.cursor.fade() - # Ignore the mods for now. - n = self.cursor.y - self.lines[n:n + 1] = [line[:i], line[i:]] - self.cursor.y += 1 - self.cursor.x = 0 - if self.cursor.y > self.at_line + self.h_in_lines: - self.scroll_up() - else: - self.draw_body() - self.cursor.draw() - - def _insert_key(self, display, mod, _line, _i): - om = OpenMessage(self, 'stack.pickle') - display.broadcast(om) - if om.status != SUCCESS: - return - stack = om.thing[0] - if stack: - content = format_stack_item(stack[0]) - if self.insert(content): - if mod & pygame.KMOD_SHIFT: - display.broadcast(CommandMessage(self, 'pop')) - return True - - def insert(self, content): - assert isinstance(content, basestring), repr(content) - if content: - self.cursor.fade() - row, column = self.cursor.y, self.cursor.x - line = self.lines[row] - lines = (line[:column] + content + line[column:]).splitlines() - self.lines[row:row + 1] = lines - self.draw_body() - self.cursor.y = row + len(lines) - 1 - self.cursor.x = len(lines[-1]) - len(line) + column - self.cursor.draw() - return True - - def append(self, content): - self.cursor.fade() - self.cursor.y = len(self.lines) - 1 - self.cursor.x = len(self.lines[self.cursor.y]) - self.insert(content) diff --git a/joy/vui/viewer.py b/joy/vui/viewer.py deleted file mode 100644 index d769d36..0000000 --- a/joy/vui/viewer.py +++ /dev/null @@ -1,249 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright © 2019 Simon Forman -# -# This file is part of joy.py -# -# joy.py is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# joy.py is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with joy.py. If not see . -# -''' - -Viewer -================= - -''' -from __future__ import print_function -from __future__ import division -from builtins import chr, object -from past.utils import old_div -import pygame -from joy.vui.core import BACKGROUND, FOREGROUND - - -class Viewer(object): - ''' - Base Viewer class - ''' - - MINIMUM_HEIGHT = 11 - - def __init__(self, surface): - self.resurface(surface) - self.last_touch = 0, 0 - - def resurface(self, surface): - self.w, self.h = surface.get_width(), surface.get_height() - self.surface = surface - - def split(self, y): - ''' - Split the viewer at the y coordinate (which is relative to the - viewer's surface and must be inside it somewhere) and return the - remaining height. The upper part of the viewer remains (and gets - redrawn on a new surface) and the lower space is now available - for e.g. a new viewer. - ''' - assert y >= self.MINIMUM_HEIGHT - new_viewer_h = self.h - y - self.resurface(self.surface.subsurface((0, 0, self.w, y))) - if y <= self.last_touch[1]: self.last_touch = 0, 0 - self.draw() - return new_viewer_h - - def handle(self, message): - assert self is not message.sender - pass - - def draw(self): - '''Draw the viewer onto its surface.''' - self.surface.fill(BACKGROUND) - x, y, h = self.w - 1, self.MINIMUM_HEIGHT, self.h - 1 - # Right-hand side. - pygame.draw.line(self.surface, FOREGROUND, (x, 0), (x, h)) - # Between header and body. - pygame.draw.line(self.surface, FOREGROUND, (0, y), (x, y)) - # Bottom. - pygame.draw.line(self.surface, FOREGROUND, (0, h), (x, h)) - - def close(self): - '''Close the viewer and release any resources, etc...''' - - def focus(self, display): - pass - - def unfocus(self): - pass - - # Event handling. - - def mouse_down(self, display, x, y, button): - self.last_touch = x, y - - def mouse_up(self, display, x, y, button): - pass - - def mouse_motion(self, display, x, y, dx, dy, button0, button1, button2): - pass - - def key_up(self, display, key, mod): - if key == pygame.K_q and mod & pygame.KMOD_CTRL: # Ctrl-q - display.close_viewer(self) - return True - if key == pygame.K_g and mod & pygame.KMOD_CTRL: # Ctrl-g - display.grow_viewer(self) - return True - - def key_down(self, display, uch, key, mod): - pass - - -class MenuViewer(Viewer): - - ''' - MenuViewer class - ''' - - MINIMUM_HEIGHT = 26 - - def __init__(self, surface): - Viewer.__init__(self, surface) - self.resizing = 0 - self.bg = 100, 150, 100 - - def resurface(self, surface): - Viewer.resurface(self, surface) - n = self.MINIMUM_HEIGHT - 2 - self.close_rect = pygame.rect.Rect(self.w - 2 - n, 1, n, n) - self.grow_rect = pygame.rect.Rect(1, 1, n, n) - self.body_rect = pygame.rect.Rect( - 0, self.MINIMUM_HEIGHT + 1, - self.w - 1, self.h - self.MINIMUM_HEIGHT - 2) - - def draw(self): - '''Draw the viewer onto its surface.''' - Viewer.draw(self) - if not self.resizing: - self.draw_menu() - self.draw_body() - - def draw_menu(self): - # menu buttons - pygame.draw.rect(self.surface, FOREGROUND, self.close_rect, 1) - pygame.draw.rect(self.surface, FOREGROUND, self.grow_rect, 1) - - def draw_body(self): - self.surface.fill(self.bg, self.body_rect) - - def mouse_down(self, display, x, y, button): - Viewer.mouse_down(self, display, x, y, button) - if y <= self.MINIMUM_HEIGHT: - self.menu_click(display, x, y, button) - else: - bx, by = self.body_rect.topleft - self.body_click(display, x - bx, y - by, button) - - def body_click(self, display, x, y, button): - if button == 1: - self.draw_an_a(x, y) - - def menu_click(self, display, x, y, button): - if button == 1: - self.resizing = 1 - elif button == 3: - if self.close_rect.collidepoint(x, y): - display.close_viewer(self) - return True - elif self.grow_rect.collidepoint(x, y): - display.grow_viewer(self) - return True - - def mouse_up(self, display, x, y, button): - - if button == 1 and self.resizing: - if self.resizing == 2: - self.resizing = 0 - self.draw() - display.done_resizing() - self.resizing = 0 - return True - - def mouse_motion(self, display, x, y, rel_x, rel_y, button0, button1, button2): - if self.resizing and button0: - self.resizing = 2 - display.change_viewer(self, rel_y, relative=True) - return True - else: - self.resizing = 0 - #self.draw_an_a(x, y) - - def key_up(self, display, key, mod): - if Viewer.key_up(self, display, key, mod): - return True - - def draw_an_a(self, x, y): - # Draw a crude letter A. - lw, lh = 10, 14 - try: surface = self.surface.subsurface((x - lw, y - lh, lw, lh)) - except ValueError: return - draw_a(surface, blend=1) - - -class SomeViewer(MenuViewer): - - def __init__(self, surface): - MenuViewer.__init__(self, surface) - - def resurface(self, surface): - MenuViewer.resurface(self, surface) - - def draw_menu(self): - MenuViewer.draw_menu(self) - - def draw_body(self): - pass - - def body_click(self, display, x, y, button): - pass - - def menu_click(self, display, x, y, button): - if MenuViewer.menu_click(self, display, x, y, button): - return True - - def mouse_up(self, display, x, y, button): - if MenuViewer.mouse_up(self, display, x, y, button): - return True - - def mouse_motion(self, display, x, y, rel_x, rel_y, button0, button1, button2): - if MenuViewer.mouse_motion(self, display, x, y, rel_x, rel_y, - button0, button1, button2): - return True - - def key_down(self, display, uch, key, mod): - try: - print(chr(key), end=' ') - except ValueError: - pass - - -# Note that Oberon book says that if you split at the exact top of a viewer -# it should close, and I think this implies the new viewer gets the old -# viewer's whole height. I haven't implemented that yet, so the edge-case -# in the code is broken by "intent" for now.. - - -def draw_a(surface, color=FOREGROUND, blend=False): - w, h = surface.get_width() - 2, surface.get_height() - 2 - pygame.draw.aalines(surface, color, False, ( - (1, h), (old_div(w, 2), 1), (w, h), (1, old_div(h, 2)) - ), blend) diff --git a/setup.py b/setup.py index 565fbd4..64a0248 100755 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ from textwrap import dedent setup( name='Thun', - version='0.4.0', + version='0.5.0', description='Python Implementation of Joy', long_description=dedent('''\ Joy is a programming language created by Manfred von Thun that is easy to @@ -33,22 +33,17 @@ setup( stay very close to the spirit of Joy but does not precisely match the behaviour of the original version written in C.'''), author='Simon Forman', - author_email='forman.simon@gmail.com', + author_email='sforman@hushmail.com', url='https://joypy.osdn.io', license='GPLv3+', - packages=['joy', 'joy.utils', 'joy.gui', 'joy.vui'], + packages=['joy', 'joy.utils'], classifiers=[ 'Development Status :: 4 - Beta', 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Other', 'Topic :: Software Development :: Interpreters', ], - install_requires=[ - 'dulwich', - 'future', - ], extras_require={ 'build-docs': [ 'sphinx', diff --git a/start-with-i3.sh b/start-with-i3.sh deleted file mode 100755 index 19c8329..0000000 --- a/start-with-i3.sh +++ /dev/null @@ -1 +0,0 @@ -i3-msg "workspace 1; append_layout /home/sforman/Desktop/ArchLayer/System/source/Thun/i3.json" && python -m joy.gui & diff --git a/start.bat b/start.bat deleted file mode 100644 index 20cc249..0000000 --- a/start.bat +++ /dev/null @@ -1 +0,0 @@ -python -m joy.gui \ No newline at end of file diff --git a/startVUI.bat b/startVUI.bat deleted file mode 100644 index 672e7f6..0000000 --- a/startVUI.bat +++ /dev/null @@ -1 +0,0 @@ -python -m joy.vui \ No newline at end of file diff --git a/test/test_type_inference.py b/test/test_type_inference.py deleted file mode 100644 index 3175f25..0000000 --- a/test/test_type_inference.py +++ /dev/null @@ -1,207 +0,0 @@ -#!/usr/bin/env python -import logging, sys, unittest - -from joy.utils.types import * -from joy.utils.stack import list_to_stack as __ -from joy.library import ( - a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, As, - b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, - n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, Ns, - s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, - f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, - i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, - t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, - ) - -globals().update(FUNCTIONS) - -logging.basicConfig( - format='%(message)s', - stream=sys.stdout, - level=logging.INFO, - ) - - -class TestMixin(object): - - def assertEqualTypeStructure(self, a, b): - # Check shape and types match. - self.assert_(a >= b) - self.assert_(b >= a) - # Check type variables match expected pattern. - self._compare_structures(b, a) - - def _compare_structures(self, a, b, seen=None): - # Sometimes we change ONLY the "number" attr of our type vars. - # We need to make sure the patterns still match our expected, uh, - # patterns. - if seen is None: - seen = {} - self.assertEqual(type(a), type(b)) - if isinstance(a, (tuple, list)): - self.assertEqual(len(a), len(b)) - for aa, bb in zip(a, b): - self._compare_structures(aa, bb, seen) - else: - if a in seen: - self.assertEqual(b, seen[a]) - else: - seen[a] = b - - -class TestCombinators(TestMixin, unittest.TestCase): - -# def setUp(self): -# def tearDown(self): - - def test_branch(self): - ''' - a1 [dup] [cons] branch - ''' - expression = a1, (dup, s1), (cons, s2), branch - f = [ - ((a0, s0), (a0, (a0, s0))), # (a0 -- a0 a0) - ((s0, (a0, s1)), ((a0, s0), s1)), # (a0 [...0] -- [a0 ...0]) - ] - self.assertEqualTypeStructure(infer(*expression), f) - - def test_concat(self): - expression = (swons, s3), (a4, s1), concat - f = (s1, ((swons, (a1, s2)), s1)) # (-- [swons a1 ...2]) - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_dip(self): - expression = dip, - f = ((s1, (a1, s2)), (a2, s2)) # (a1 [...1] -- a2) - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_cons_dip(self): - expression = (cons, s3), dip # [cons] dip - # (a2 [...1] a1 -- [a2 ...1] a1) - f = (a1, (s1, (a2, s2))), (a1, ((a2, s1), s2)) - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_cons_dipd(self): - expression = (cons, s0), dipd - f = ((a2, (a1, (s1, (a3, s2)))), (a2, (a1, ((a3, s1), s2)))) - # (a3 [...1] a1 a2 -- [a3 ...1] a1 a2) - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_i(self): - # [cons] i == cons - expression = (cons, s0), i - self.assertEqualTypeStructure(infer(*expression), infer(cons)) - - def test_i_dip(self): - expression = (i, s3), dip # [i] dip - f = ((a1, (s1, s2)), (a1, s2)) # ([...1] a1 -- a1) - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_infra(self): - expression = [ - __((n1, n2, n3), s1), # Three numbers in a stack. - (mul, s2), - infra - ] - f = [ - (s1, ((n1, (n2, s2)), s1)), # (-- [n1 n2 ...2]) - ] - self.assertEqualTypeStructure(infer(*expression), f) - - def test_nullary(self): - expression = n1, n2, (mul, s2), (stack, s3), dip, infra, first - f = [ - (s1, (n1, (n2, (n3, s1)))), # (-- n3 n2 n1) - ] - self.assertEqualTypeStructure(infer(*expression), f) - - expression = n1, n2, (mul, s2), nullary - self.assertEqualTypeStructure(infer(*expression), f) - - def test_nullary_too(self): - expression = (stack, s3), dip, infra, first - f = ((s1, (a1, s2)), (a1, (a1, s2))) # (a1 [...1] -- a1 a1) - self.assertEqualTypeStructure(infer(*expression), [f]) - expression = nullary, - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_x(self): - expression = (a1, (swap, ((dup, s2), (dip, s1)))), x - f = (s0, ((a0, (swap, ((dup, s1), (dip, s2)))), (a1, (a1, s0)))) - # (-- a1 a1 [a0 swap [dup ...1] dip ...2]) - self.assertEqualTypeStructure(infer(*expression), [f]) - - -class TestKleeneStar(TestMixin, unittest.TestCase): - - def test_Astar(self): - expression = a1, As[2], a2, cons - f = [ # Vanish in one, spawn a new variable in the other... - (s1, ((a1, s2), s1)), # (-- [a1 ...2]) - (s1, ((a1, s2), (As[1], (a2, s1)))), # (-- a2 a1* [a1 ...2]) - ] - self.assertEqualTypeStructure(infer(*expression), f) - - def test_sum(self): - expression = [ - __((n1, n2, n3), s1), # Three numbers in a stack. - sum, # builtin shadowed by SymbolJoyType - ] - # A function that puts a single number on the stack. - f = s0, (n0, s0) - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_no_infinite_loop(self): - expression = [ - (Ns[2], s1), # A stack of numbers. - sum, # builtin shadowed by SymbolJoyType. - ] - # A function that puts a single number on the stack. - f = s0, (n0, s0) - self.assertEqualTypeStructure(infer(*expression), [f]) - - -class TestYin(TestMixin, unittest.TestCase): - - def test_MiscYin(self): - expression = pop, swap, rolldown, rest, rest, cons, cons - # ([a3 a4 ...0] a2 a1 a0 -- [a1 a2 ...0]) - f = (a0, (a1, (a2, ((a3, (a4, s0)), s1)))), ((a1, (a2, s0)), s1) - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_swaack(self): - expression = a0, (a1, s0), swaack - f = (s0, ((a0, s0), (a1, s1))) # (-- a1 [a0 ...0]) - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_z_down(self): - expression = s2, swap, uncons, swap - f = (((a1, s1), s2), (a1, (s1, (s3, s2)))) - # ([a1 ...1] -- [...3] [...1] a1) - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_z_right(self): - expression = a1, a2, (swons, s3), cons, dip, uncons, swap - f = ((s1, s2), (a1, (s3, ((a2, s1), s2)))) - # ([...1] -- [a2 ...1] [...3] a1) - self.assertEqualTypeStructure(infer(*expression), [f]) - - def test_stack_dup_ccons(self): - expression = stack, dup, ccons - f = ((a1, s1), ((a1, ((a1, s1), (a1, s1))), s1)) - # (... a1 -- ... [a1 [a1 ...] a1 ...]) - self.assertEqualTypeStructure(infer(*expression), [f]) - -## def test_(self): -## expression = pop, swap, rolldown, rest, rest, cons, cons -## f = -## for sec in infer(*expression): -## print sec, doc_from_stack_effect(*sec) -## self.assertEqualTypeStructure(infer(*expression), [f]) - -## for g in MC(dup, mul): -## print doc_from_stack_effect(*g) - - -if __name__ == '__main__': - unittest.main() #defaultTest='TestCombinators.test_branch') diff --git a/thun/TLA.pl b/thun/TLA.pl deleted file mode 100644 index 710da92..0000000 --- a/thun/TLA.pl +++ /dev/null @@ -1,194 +0,0 @@ - -:- use_module(library(clpfd)). - - -% relly(PC, I, PCnext, Inext). - -initial_state :- relly(start, 0, _, _). - -relly(start, _I, middle, Inext) :- Inext in 0..1000. -relly(middle, I, done, Inext) :- Inext #= I + 1. - - -% next(PC, I) :- -next(done, _). -next(PC, I) :- PC \= done, relly(PC, I, PCnext, Inext), next(PCnext, Inext). - - -% ?- relly(start, 17, middle, 534). -% true. - -% ?- relly(middle, 534, 77, done). -% false. - -% ?- initial_state. -% true. - -% ?- relly(start, 0, PC, I). -% PC = middle, -% I in 0..1000. - -% ?- relly(start, 0, PC, I), relly(PC, I, PCnext, Inext). -% PC = middle, -% PCnext = done, -% I in 0..1000, -% I+1#=Inext, -% Inext in 1..1001. - - - - - - - - - - - - - - - - - - - - - - - - - -type_ok(Small, Big) :- Small in 0..3, Big in 0..5. - -next_dh(Moves) :- next_dh(0, 0, Moves). - -next_dh(Small, Big, [[Move, Si, Bi]|Moves]) :- - type_ok(Small, Big), - die_hard(Move, Small, Big, Si, Bi), - (Bi = 4 -> Moves = [] ; next_dh(Si, Bi, Moves)). - -die_hard( fill_small, Small, Big, 3, Big) :- Small #< 3. -die_hard( fill_big, Small, Big, Small, 5) :- Big #< 5. -die_hard(empty_small, Small, Big, 0, Big) :- Small #> 0. -die_hard( empty_big, Small, Big, Small, 0) :- Big #> 0. - -die_hard(small_to_big, Small, Big, S, B) :- - Big #< 5, Small #> 0, - small_to_big(Small, Big, S, B). - -die_hard(big_to_small, Small, Big, S, B) :- - Small #< 3, Big #> 0, - big_to_small(Small, Big, S, B). - -big_to_small(Small, Big, S, 0) :- - Small + Big #=< 3, - S #= Small + Big. - -big_to_small(Small, Big, 3, B) :- - Small + Big #> 3, - B #= Big - (3 - Small). - -small_to_big(Small, Big, 0, B) :- - Small + Big #=< 5, - B #= Small + Big. - -small_to_big(Small, Big, S, 5) :- - Small + Big #> 5, - S #= Small - (5 - Big). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/* - -With some manual reflow of the list for presentation... - -?- call_with_depth_limit(next_dh(Moves), 11, _). -Moves = [ - [fill_big, 0, 5], - [big_to_small, 3, 2], - [empty_small, 0, 2], - [big_to_small, 2, 0], - [fill_big, 2, 5], - [big_to_small, 3, 4] - ] ; -true. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -call_with_depth_limit(next_dh(0, 0, S, B), 12, REsult). - -find... - -fill big -0 0 -> 0 5 -big to small -0 5 -> 3 2 -empty small -3 2 -> 0 2 -big to small -0 2 -> 2 0 -fill big -2 0 -> 2 5 -big to small -2 5 -> 3 4 - - -*/ \ No newline at end of file diff --git a/thun/asm-dump.txt b/thun/asm-dump.txt deleted file mode 100644 index 7ada828..0000000 --- a/thun/asm-dump.txt +++ /dev/null @@ -1,279 +0,0 @@ -[word(0), -do_offset(A), -allocate(_, 20), -label(A), -mov_imm(0, 0), -store_word(0, 0, 0), -mov_imm(0, 4096), -mov_imm(1, Z1), -mov_imm(2, 0), -mov_imm(3, 0), -store_word(2, 0, 0), -label(H), -sub_imm(1, 1, 0), -eq_offset(I), -load_word(4, 1, 0), -lsl_imm(5, 4, 2), -asr_imm(5, 5, 17), -eq_offset(B), -add(5, 5, 1), -label(B), -lsl_imm(6, 4, 17), -asr_imm(6, 6, 17), -eq_offset(C), -add(6, 6, 1), -label(C), -load_word(3, 5, 0), -mov(1, 6), -asr_imm(6, 3, 30), -and_imm(6, 6, 2), -sub_imm(6, 6, 2), -ne_offset(D), -mov_imm_with_shift(6, 16383), -ior_imm(6, 6, 65535), -and(6, 6, 3), -do(6), -label(D), -sub_imm(0, 0, 4), -sub_imm(5, 5, 0), -eq_offset(F), -sub(2, 5, 0), -hi_offset(E), -and_imm(2, 2, 32767), -label(E), -lsl_imm(2, 2, 15), -ior_imm(2, 2, 4), -do_offset(G), -label(F), -mov_imm(2, 4), -label(G), -store_word(2, 0, 0), -do_offset(H), -label(I), -do_offset(I), -label(J), -symbol(J), -lsl_imm(6, 2, 2), -asr_imm(6, 6, 17), -eq_offset(K), -add(6, 6, 0), -label(K), -lsl_imm(2, 2, 17), -asr_imm(2, 2, 17), -eq_offset(L), -add(2, 2, 0), -label(L), -load_word(7, 2, 0), -lsl_imm(8, 7, 2), -asr_imm(8, 8, 17), -eq_offset(M), -add(8, 8, 2), -label(M), -lsl_imm(9, 7, 17), -asr_imm(9, 9, 17), -eq_offset(N), -add(9, 9, 2), -label(N), -sub_imm(0, 0, 4), -sub_imm(8, 8, 0), -eq_offset(O), -sub(8, 8, 0), -and_imm(8, 8, 32767), -label(O), -sub_imm(6, 6, 0), -eq_offset(P), -sub(6, 6, 0), -and_imm(6, 6, 32767), -label(P), -lsl_imm(8, 8, 15), -ior(8, 8, 6), -store_word(8, 0, 0), -sub_imm(0, 0, 4), -sub_imm(9, 9, 0), -eq_offset(Q), -sub(9, 9, 0), -and_imm(9, 9, 32767), -label(Q), -mov_imm_with_shift(2, 2), -ior(2, 2, 9), -do_offset(G), -label(R), -symbol(R), -lsl_imm(5, 2, 2), -asr_imm(5, 5, 17), -do_offset(D), -label(S), -symbol(S), -lsl_imm(6, 2, 2), -asr_imm(6, 6, 17), -eq_offset(T), -add(6, 6, 0), -label(T), -lsl_imm(2, 2, 17), -asr_imm(2, 2, 17), -eq_offset(U), -add(2, 2, 0), -label(U), -sub_imm(6, 6, 0), -eq_offset(D1), -sub_imm(10, 0, 4), -mov_imm(9, 4), -label(B1), -load_word(3, 6, 0), -lsl_imm(7, 3, 2), -asr_imm(7, 7, 17), -eq_offset(V), -add(7, 7, 6), -label(V), -lsl_imm(8, 3, 17), -asr_imm(8, 8, 17), -eq_offset(W), -add(8, 8, 6), -label(W), -mov(6, 8), -sub_imm(0, 0, 4), -sub_imm(8, 8, 0), -eq_offset(X), -lsl_imm(7, 7, 15), -ior(7, 7, 9), -store_word(7, 0, 0), -do_offset(A1), -label(X), -sub_imm(7, 7, 0), -eq_offset(Y), -sub(7, 7, 0), -and_imm(7, 7, 32767), -label(Y), -sub_imm(1, 1, 0), -eq_offset(Z), -sub(1, 1, 0), -and_imm(1, 1, 32767), -label(Z), -lsl_imm(7, 7, 15), -ior(7, 7, 1), -store_word(7, 0, 0), -label(A1), -sub_imm(6, 6, 0), -eq_offset(C1), -do_offset(B1), -label(C1), -mov(1, 10), -label(D1), -load_word(7, 2, 0), -lsl_imm(6, 7, 2), -asr_imm(6, 6, 17), -eq_offset(E1), -add(6, 6, 2), -label(E1), -lsl_imm(7, 7, 17), -asr_imm(7, 7, 17), -eq_offset(F1), -add(7, 7, 2), -label(F1), -sub_imm(0, 0, 4), -sub_imm(6, 6, 0), -eq_offset(G1), -sub(6, 6, 0), -and_imm(6, 6, 32767), -label(G1), -sub_imm(7, 7, 0), -eq_offset(H1), -sub(7, 7, 0), -and_imm(7, 7, 32767), -label(H1), -lsl_imm(6, 6, 15), -ior(6, 6, 7), -store_word(6, 0, 0), -do_offset(H), -label(I1), -symbol(I1), -mov_imm(5, 0), -do_offset(D), -label(J1), -symbol(J1), -lsl_imm(6, 2, 2), -asr_imm(6, 6, 17), -eq_offset(K1), -add(6, 6, 0), -label(K1), -lsl_imm(7, 2, 17), -asr_imm(7, 7, 17), -eq_offset(L1), -add(7, 7, 0), -label(L1), -load_word(8, 7, 0), -lsl_imm(9, 2, 2), -asr_imm(9, 9, 17), -eq_offset(M1), -add(9, 9, 0), -label(M1), -lsl_imm(10, 2, 17), -asr_imm(10, 10, 17), -eq_offset(N1), -add(10, 10, 0), -label(N1), -sub_imm(0, 0, 4), -sub_imm(6, 6, 0), -eq_offset(O1), -sub(6, 6, 0), -and_imm(6, 6, 32767), -label(O1), -sub_imm(10, 10, 0), -eq_offset(P1), -sub(10, 10, 0), -and_imm(10, 10, 32767), -label(P1), -lsl_imm(6, 6, 15), -ior(6, 6, 10), -store_word(6, 0, 0), -mov_imm(6, 4), -sub_imm(0, 0, 4), -sub_imm(9, 9, 0), -eq_offset(Q1), -sub(9, 9, 0), -and_imm(9, 9, 32767), -label(Q1), -lsl_imm(9, 9, 15), -ior(9, 9, 6), -store_word(9, 0, 0), -do_offset(H), -label(R1), -symbol(R1), -mov_imm(2, S1), -do_offset(U1), -label(S1), -expr_cell(I1, 4), -expr_cell(J, 0), -label(T1), -symbol(T1), -mov_imm(2, V1), -do_offset(U1), -label(V1), -expr_cell(R, 4), -expr_cell(S, 0), -label(W1), -symbol(W1), -mov_imm(2, X1), -do_offset(U1), -label(X1), -expr_cell(J1, 4), -expr_cell(J, 0), -label(U1), -mov_imm(7, 4), -sub_imm(0, 0, 4), -sub_imm(2, 2, 0), -eq_offset(Y1), -sub(2, 2, 0), -and_imm(2, 2, 32767), -label(Y1), -lsl_imm(2, 2, 15), -ior(2, 2, 7), -store_word(2, 0, 0), -mov_imm(7, S), -add_imm(7, 7, 4), -do(7), -label(Z1), -expr_cell(I1, 4), -expr_cell(R, 4), -expr_cell(W1, 4), -expr_cell(S, 0)]. \ No newline at end of file diff --git a/thun/compiler.markII.pl b/thun/compiler.markII.pl deleted file mode 100644 index a0a737d..0000000 --- a/thun/compiler.markII.pl +++ /dev/null @@ -1,649 +0,0 @@ -/* - -Copyright © 2018-2019 Simon Forman - -This file is part of Thun - -Thun is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Thun is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Thun. If not see . - -Mark II - - -*/ -:- use_module(library(assoc)). -:- use_module(library(clpfd)). - -% Just do it in assembler. - -⟐(program) --> - { [SP, EXPR_addr, TOS, TERM, EXPR, TermAddr, TEMP0, TEMP1, TEMP2, TEMP3, TEMP4] - = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] - }, -[ - word(0), % Zero root cell. - do_offset(Reset), % Oberon bootloader writes MemLim to RAM[12] and - allocate(_, 20), % stackOrg to RAM[24], we don't need these - label(reset, Reset), % but they must not be allowed to corrupt our code. - - mov_imm(0, 0), % zero out the root cell. (After reset.) - store_word(0, 0, 0), - - mov_imm(SP, 0x1000), - mov_imm(EXPR_addr, Expression), - mov_imm(TOS, 0), - mov_imm(TERM, 0), - store_word(TOS, SP, 0) % RAM[SP] := 0 -],⟐([ - label(main, Main), % Mainloop. - if_zero(EXPR_addr, HALT), - load(EXPR, EXPR_addr), - % At this point EXPR holds the record word of the expression. - unpack_pair(EXPR, TermAddr, TEMP0, EXPR_addr), - load(TERM, TermAddr), - % TermAddr has the address of the term record. - % Now TERM has the term's record data and TermAddr has the address of the term. - asm(mov(EXPR_addr, TEMP0)), - % EXPR_addr now holds the address of the next cell of the expression list. - if_literal(TERM, PUSH, TEMP0), - % if it is a symbol the rest of it is the pointer to the machine code. - lookup(TERM, TEMP0), % Jump to command. - % going into push we have the term - label(push, PUSH), - % push2(TOS, TEMP1, SP), % stack = TERM, stack - incr(SP), - if_zero(TermAddr, JustPushEmptyList) -]),[ - % SP points to the future home of the new stack cell. - sub(TOS, TermAddr, SP), % TOS := &temp - sp - % Er, what if it's negative? - hi_offset(Bar0), - and_imm(TOS, TOS, 0x7fff), % Mask off high bits so - label(Bar0), % they won't interfere with making a record cell. - % TOS has the offset from new stack cell to term cell. - % Combine with the offset to the previous stack cell. - lsl_imm(TOS, TOS, 15), % TOS := TOS << 15 - ior_imm(TOS, TOS, 4), % TOS := TOS | 4 - do_offset(Done), - label(jpel, JustPushEmptyList), - mov_imm(TOS, 4), % TOS is a pair record with 0 as the head addr - % and the previous word in RAM as tail addr. - - label(done, Done), - store_word(TOS, SP, 0), % RAM[SP] := TOS - do_offset(Main) - -],⟐([ - - halt(HALT), - - definition(cons, Cons), % ====================================== - - unpack_pair(TOS, TEMP0, TOS, SP), - % TEMP0 = Address of the list to which to append. - % TOS = Address of the second stack cell. - load(TEMP1, TOS), - % TEMP1 contains the record of the second stack cell. - unpack_pair(TEMP1, TEMP2, TEMP3, TOS), - % TEMP2 contains the address of the second item on the stack - % TEMP3 = TOS + TEMP1[15:0] the address of the third stack cell - - % Build and write the new list cell. - incr(SP), - sub_base_merge_and_store(TEMP2, TEMP0, SP), - incr(SP), - sub_base_from_offset(TEMP3, SP), - chain_link(TOS, TEMP3), - jump(Done), % Rely on mainloop::Done to write TOS to RAM. - - definition(dup, Dup), % ====================================== - head_addr(TOS, TermAddr), - jump(PUSH), - - definition(i, I), % ====================================== - unpack_pair(TOS, TEMP0, TOS, SP), - % TEMP0 = Address of the quoted program. - % TOS = Address of the stack tail. - br(if_zero(TEMP0), [], % If the program is empty do nothing. - [ % The program has elements. Since we are going to be reading the q.p. - % from the head to the tail we will have to write the cells in that order. - incr(TEMP4, SP), % TEMP4 = address of head of eventual new expression. - asm(mov_imm(TEMP3, 4)), % Factored out of the loop. Used for linking. - repeat_until(if_zero(TEMP0), [ % TEMP0 = Address of the quoted program. - load(TERM, TEMP0), - label(iball, _), - unpack_pair(TERM, TEMP1, TEMP2, TEMP0), - % TEMP1 is the address of head item, TEMP2 is the tail - asm(mov(TEMP0, TEMP2)), % update temp0 to point to rest of quoted program. - incr(SP), % We are about to write a cell. - br(if_zero(TEMP2), - [sub_base_merge_and_store(TEMP1, EXPR_addr, SP)], - % TERM is the last item in the quoted program. - % The expr should point to a cell that has TEMP1 head and tail - % of the rest of the expression. - [sub_base_from_offset(TEMP1, SP), merge_and_store(TEMP1, TEMP3, SP)] - % TERM has at least one more item after it. - % We know that we will be writing that item in a - % cell immediately after this one, so it has TEMP1 - % head and 4 for the tail. - ) - ]), - asm(mov(EXPR_addr, TEMP4)) - ]), - - % SP can never go down, so to point to an earlier cell we have to write - % a new cell. (Maybe use a separate heap register/pointer?) - load(TEMP1, TOS), % TEMP1 contains the record of the second stack cell. - % write a new cell, the head is head of TEMP1, the tail is tail of TEMP1 - % but adjusted to offset from SP+4 where we are about to write this record. - unpack_pair(TEMP1, TEMP0, TEMP1, TOS), % TEMP0 = HeadAddr, TEMP1 = TailAddr - incr(SP), - sub_base_merge_and_store(TEMP0, TEMP1, SP), - jump(Main), % We already wrote the stack cell so 'Main' not 'Done'. - - definition(new, New), % ====================================== - asm(mov_imm(TermAddr, 0)), % Rely on push machinery. - jump(PUSH), - - definition(swap, Swap), % ====================================== - unpack_pair(TOS, TEMP0, TEMP1, SP), - % TEMP0 = Address of the first item on the stack. - % TEMP1 = Address of the stack tail. - load(TEMP2, TEMP1), % TEMP1 contains the record of the second stack cell. - unpack_pair(TOS, TEMP3, TEMP4, SP), - % TEMP3 = Address of the second item on the stack. - % TEMP4 = Address of the stack tail. - incr(SP), - sub_base_merge_and_store(TEMP0, TEMP4, SP), % Push first item onto stack. - asm(mov_imm(TEMP0, 4)), % Used for linking to previous cell. - incr(SP), - sub_base_from_offset(TEMP3, SP), - merge_and_store(TEMP3, TEMP0, SP), % Push second item onto stack. - jump(Main), - - % ====================================== - definition(unit, Unit, [New, Cons], DoDef, TOS), - definition(x, X, [Dup, I], DoDef, TOS), - definition(swons, Swons, [Swap, Cons], DoDef, TOS), - % ====================================== - - label(dodef, DoDef), % ====================================== - % TOS points to body expr, set by definition. - asm(mov_imm(TEMP1, 4)), % Used for linking to previous cell. - incr(SP), - sub_base_from_offset(TOS, SP), - merge_and_store(TOS, TEMP1, SP), % Push body expr onto stack. - asm(mov_imm(TEMP1, I)), % Get address of I's machine code. - asm(add_imm(TEMP1, TEMP1, 4)), - asm(do(TEMP1)), - - % ====================================== - label(expression, Expression), - dexpr([New, Dup, Swons, I]) -]). - - -/* - -This stage ⟐//1 converts the intermediate representation to assembly -language. - -*/ - -⟐([]) --> []. -⟐([Term|Terms]) --> ⟐(Term), ⟐(Terms). - -⟐(if_zero(Reg, Label)) --> [sub_imm(Reg, Reg, 0), eq_offset(Label)]. - -⟐(sub_base_from_offset(Reg, Base)) --> - ⟐(if_zero(Reg, Label)), % if the offset is zero don't subtract - [sub(Reg, Reg, Base), % the Base address, it's the empty list. - and_imm(Reg, Reg, 0x7fff), % Mask off high bits. - label(Label)]. - -⟐(unpack_pair(From, HeadAddr, TailAddr, Base)) --> - [label('unpack[', _), lsl_imm(HeadAddr, From, 2)], % Trim off the type tag 00 bits. - ⟐(roll_down_add_base_if_not_zero(HeadAddr, Base)), - [lsl_imm(TailAddr, From, 17)], % Trim off tag and head address. - ⟐(roll_down_add_base_if_not_zero(TailAddr, Base)), - [label(']unpack', _)]. - -⟐(roll_down_add_base_if_not_zero(Addr, Base)) --> - [asr_imm(Addr, Addr, 17), % Preserving sign. - eq_offset(Label), % If the offset is zero don't add the address. it's empty list. - add(Addr, Addr, Base), - label(Label)]. - -⟐(load(From, To)) --> [load_word(From, To, 0)]. - -⟐(label(L)) --> [label(L)]. % Pass through. -⟐(label(Name, L)) --> [label(Name, L)]. % Pass through. -⟐(dexpr(L)) --> dexpr(L). % Pass through. - -⟐(jump(To)) --> [do_offset(To)]. % Pass through. - -⟐(halt(Halt)) --> [label(Halt), do_offset(Halt)]. -% This is a HALT loop, the emulator detects and traps on this "10 goto 10" instruction. - -⟐(asm(ASM)) --> [ASM]. - -⟐(incr(SP)) --> [sub_imm(SP, SP, 4)]. % SP -= 1 (word, not byte). -⟐(incr(To, SP)) --> [sub_imm(To, SP, 4)]. -⟐(incr(To, SP, N)) --> {M is 4 * N}, [sub_imm(To, SP, M)]. - -⟐(if_literal(TERM, Push, TEMP)) --> - [asr_imm(TEMP, TERM, 30), % get just the two tag bits. - and_imm(TEMP, TEMP, 2), % mask the two tag bits. - sub_imm(TEMP, TEMP, 2), % if this is a symbol result is zero. - ne_offset(Push)]. - -⟐(lookup(TERM, TEMP)) --> - % if it is a symbol the rest of it is the pointer to the machine code. - [mov_imm_with_shift(TEMP, 0x3fff), % TEMP = 0x3fffffff - ior_imm(TEMP, TEMP, 0xffff), - and(TEMP, TEMP, TERM), - do(TEMP)]. % Jump to command. - -⟐(merge_and_store(HeadAddr, TailAddr, SP)) --> - [lsl_imm(HeadAddr, HeadAddr, 15), % HeadAddr := HeadAddr << 15 - ior(HeadAddr, HeadAddr, TailAddr), - store_word(HeadAddr, SP, 0)]. - -⟐(chain_link(In, Term)) --> - [mov_imm_with_shift(In, 2), % In := 4 << 15 - ior(In, In, Term)]. - -⟐(definition(Name, Label)) --> [label(Name, Label), symbol(Label)]. - -⟐(definition(Name, Label, Body, DoDef, TEMP)) --> ⟐(definition(Name, Label)), - [mov_imm(TEMP, BodyList), - do_offset(DoDef), - label(BodyList)], - dexpr(Body). - -⟐(head_addr(Pair, HeadAddr)) --> [lsl_imm(HeadAddr, Pair, 2), asr_imm(HeadAddr, HeadAddr, 17)]. - -⟐(repeat_until(Condition, Body)) --> - {add_label(Condition, End, ConditionL)}, - ⟐([ - label(Loop), - Body, - ConditionL, - jump(Loop), - label(End) - ]). - -⟐(br(Condition, [], Else)) --> !, - {add_label(Condition, END, ConditionL)}, - ⟐([ConditionL, Else, label(END)]). - -⟐(br(Condition, Then, Else)) --> - {add_label(Condition, THEN, ConditionL)}, - ⟐([ - ConditionL, Else, jump(END), - label(THEN), Then, label(END) - ]). - -⟐(sub_base_merge_and_store(HeadAddr, TailAddr, Base)) --> - ⟐([sub_base_from_offset(HeadAddr, Base), - sub_base_from_offset(TailAddr, Base), - merge_and_store(HeadAddr, TailAddr, Base)]). - - -/* -The add_label/3 relation is a meta-logical construct that accepts a comparision -predicate (e.g. if_zero/2) and "patches" it by adding the Label logic variable -to the end. -*/ - -add_label(CmpIn, Label, CmpOut) :- - CmpIn =.. F, - append(F, [Label], G), - CmpOut =.. G. - - -/* -The dexpr//1 DCG establishes a sequence of labeled expr_cell/2 pseudo-assembly -memory locations as a linked list that encodes a Prolog list of Joy function -labels comprising e.g. the body of some Joy definition. -*/ -% This is simpler now that link offsets are just 4. - -dexpr([]) --> !, []. -dexpr([Func]) --> !, [expr_cell(Func, 0)]. -dexpr([Func|Rest]) --> !, [expr_cell(Func, 4)], dexpr(Rest). - - -do :- - compile_program(Binary), - write_binary('joy_asmii.bin', Binary). - - -compile_program(Binary) :- - phrase(⟐(program), ASM), - portray_clause(ASM), - phrase(linker(ASM), EnumeratedASM), - phrase(asm(EnumeratedASM), Binary). - - -/* - -Linker - -*/ - -linker(ASM) --> enumerate_asm(ASM, 0, _). - -enumerate_asm( [], N, N) --> !, []. -enumerate_asm( [Term|Terms], N, M) --> !, enumerate_asm(Term, N, O), enumerate_asm(Terms, O, M). -enumerate_asm( label(N) , N, N) --> !, []. -enumerate_asm( label(Name, N) , N, N) --> !, [], {writeln(Name-N)}. % Emit "symbol table" by side-effect. -enumerate_asm(allocate(N, Bytes), N, M) --> !, {Bits is 8 * Bytes}, [skip(Bits)], {align(N, Bytes, M)}. -enumerate_asm( Instr, N, M) --> [(Z, Instr)], {align(N, 0, Z), align(Z, 4, M)}. - -align(_, Bytes, _) :- (Bytes < 0 -> write('Align negative number? No!')), !, fail. -align(N, 1, M) :- !, M is N + 1. -align(N, Bytes, M) :- N mod 4 =:= 0, !, M is N + Bytes. -align(N, Bytes, M) :- Padding is 4 - (N mod 4), M is N + Bytes + Padding. - - -/* - -Assembler - -*/ - -asm([]) --> !, []. -asm([ skip(Bits)|Rest]) --> !, skip(Bits), asm(Rest). -asm([(N, Instruction)|Rest]) --> !, asm(N, Instruction), asm(Rest). - -asm(Here, expr_cell(Func, NextCell)) --> !, - {Data is (((Func - Here) /\ 0x7fff) << 15) \/ NextCell}, - asm(Here, word(Data)). - -asm(_, symbol(Sym)) --> !, {Data is (Sym + 4) \/ 0x80000000}, asm(_, word(Data)). -% The symbol is at the beginning of the function machine code, so the pointer it -% holds to that code has to be one word beyond the pointer/label Sym that points -% to the symbol itself (one word before the machine code.) The symbol's address -% is used in expressions. - -asm(_, word(Word)) --> !, encode_int(32, Word). - -asm(_, load_word(A, B, Offset)) --> !, instruction_format_F2(0, 0, A, B, Offset). -asm(_, load_byte(A, B, Offset)) --> !, instruction_format_F2(0, 1, A, B, Offset). -asm(_, store_word(A, B, Offset)) --> !, instruction_format_F2(1, 0, A, B, Offset). -asm(_, store_byte(A, B, Offset)) --> !, instruction_format_F2(1, 1, A, B, Offset). - -asm(_, mov(A, C)) --> instruction_format_F0(0, A, 0, mov, C). -asm(_, mov_with_shift(A, C)) --> instruction_format_F0(1, A, 0, mov, C). - -asm(_, mov_imm_with_shift(A, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(1, 0, A, 0, mov, Imm). -asm(_, mov_imm_with_shift(A, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(1, 0, A, 0, mov, Imm). -asm(_, mov_imm_with_shift(_, _)) --> {write('Immediate value out of bounds'), fail}. - -asm(_, mov_imm(A, Imm) ) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, 0, mov, Imm). -asm(_, mov_imm(A, Imm) ) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, 0, mov, Imm). -asm(_, mov_imm(_, _) ) --> {write('Immediate value out of bounds'), fail}. - -asm(_, add(A, B, C)) --> instruction_format_F0(0, A, B, add, C). -asm(_, add_carry(A, B, C)) --> instruction_format_F0(1, A, B, add, C). -asm(_, sub(A, B, C)) --> instruction_format_F0(0, A, B, sub, C). -asm(_, sub_carry(A, B, C)) --> instruction_format_F0(1, A, B, sub, C). - -asm(_, add_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, add, Imm). -asm(_, add_imm(A, B, Imm)) --> {pos_int15(Imm)}, !, instruction_format_F1(0, 0, A, B, add, Imm). -asm(_, add_imm_carry(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(1, 1, A, B, add, Imm). -asm(_, add_imm_carry(A, B, Imm)) --> {pos_int15(Imm)}, !, instruction_format_F1(1, 0, A, B, add, Imm). -asm(_, sub_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, sub, Imm). -asm(_, sub_imm(A, B, Imm)) --> {pos_int15(Imm)}, !, instruction_format_F1(0, 0, A, B, sub, Imm). -asm(_, sub_imm_carry(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(1, 1, A, B, sub, Imm). -asm(_, sub_imm_carry(A, B, Imm)) --> {pos_int15(Imm)}, !, instruction_format_F1(1, 0, A, B, sub, Imm). - -asm(_, mul(A, B, C)) --> instruction_format_F0(0, A, B, mul, C). -asm(_, mul_unsigned(A, B, C)) --> instruction_format_F0(1, A, B, mul, C). -asm(_, mul_imm(A, B, Imm, U)) --> {neg_int15(Imm)}, !, instruction_format_F1(U, 1, A, B, mul, Imm). -asm(_, mul_imm(A, B, Imm, U)) --> {pos_int15(Imm)}, !, instruction_format_F1(U, 0, A, B, mul, Imm). - -asm(_, and(A, B, C)) --> instruction_format_F0(0, A, B, and, C). -asm(_, ann(A, B, C)) --> instruction_format_F0(0, A, B, ann, C). -asm(_, asr(A, B, C)) --> instruction_format_F0(0, A, B, asr, C). -asm(_, div(A, B, C)) --> instruction_format_F0(0, A, B, div, C). -asm(_, ior(A, B, C)) --> instruction_format_F0(0, A, B, ior, C). -asm(_, lsl(A, B, C)) --> instruction_format_F0(0, A, B, lsl, C). -asm(_, ror(A, B, C)) --> instruction_format_F0(0, A, B, ror, C). -asm(_, xor(A, B, C)) --> instruction_format_F0(0, A, B, xor, C). - -asm(_, and_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, and, Imm). -asm(_, and_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, and, Imm). -asm(_, ann_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, ann, Imm). -asm(_, ann_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, ann, Imm). -asm(_, asr_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, asr, Imm). -asm(_, asr_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, asr, Imm). -asm(_, div_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, div, Imm). -asm(_, div_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, div, Imm). -asm(_, ior_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, ior, Imm). -asm(_, ior_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, ior, Imm). -asm(_, lsl_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, lsl, Imm). -asm(_, lsl_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, lsl, Imm). -asm(_, ror_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, ror, Imm). -asm(_, ror_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, ror, Imm). -asm(_, xor_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, xor, Imm). -asm(_, xor_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, xor, Imm). - -asm(_, cc(C)) --> instruction_format_F3a(0, cc, C). -asm(N, cc_offset(Label)) --> instruction_format_F3b(0, cc, Label, N). -asm(_, cc_link(C)) --> instruction_format_F3a(1, cc, C). -asm(N, cc_link_offset(Label)) --> instruction_format_F3b(1, cc, Label, N). -asm(_, cs(C)) --> instruction_format_F3a(0, cs, C). -asm(N, cs_offset(Label)) --> instruction_format_F3b(0, cs, Label, N). -asm(_, cs_link(C)) --> instruction_format_F3a(1, cs, C). -asm(N, cs_link_offset(Label)) --> instruction_format_F3b(1, cs, Label, N). -asm(_, do(C)) --> instruction_format_F3a(0, do, C). -asm(N, do_offset(Label)) --> instruction_format_F3b(0, do, Label, N). -asm(_, do_link(C)) --> instruction_format_F3a(1, do, C). -asm(N, do_link_offset(Label)) --> instruction_format_F3b(1, do, Label, N). -asm(_, eq(C)) --> instruction_format_F3a(0, eq, C). -asm(N, eq_offset(Label)) --> instruction_format_F3b(0, eq, Label, N). -asm(_, eq_link(C)) --> instruction_format_F3a(1, eq, C). -asm(N, eq_link_offset(Label)) --> instruction_format_F3b(1, eq, Label, N). -asm(_, ge(C)) --> instruction_format_F3a(0, ge, C). -asm(N, ge_offset(Label)) --> instruction_format_F3b(0, ge, Label, N). -asm(_, ge_link(C)) --> instruction_format_F3a(1, ge, C). -asm(N, ge_link_offset(Label)) --> instruction_format_F3b(1, ge, Label, N). -asm(_, gt(C)) --> instruction_format_F3a(0, gt, C). -asm(N, gt_offset(Label)) --> instruction_format_F3b(0, gt, Label, N). -asm(_, gt_link(C)) --> instruction_format_F3a(1, gt, C). -asm(N, gt_link_offset(Label)) --> instruction_format_F3b(1, gt, Label, N). -asm(_, hi(C)) --> instruction_format_F3a(0, hi, C). -asm(N, hi_offset(Label)) --> instruction_format_F3b(0, hi, Label, N). -asm(_, hi_link(C)) --> instruction_format_F3a(1, hi, C). -asm(N, hi_link_offset(Label)) --> instruction_format_F3b(1, hi, Label, N). -asm(_, le(C)) --> instruction_format_F3a(0, le, C). -asm(N, le_offset(Label)) --> instruction_format_F3b(0, le, Label, N). -asm(_, le_link(C)) --> instruction_format_F3a(1, le, C). -asm(N, le_link_offset(Label)) --> instruction_format_F3b(1, le, Label, N). -asm(_, ls(C)) --> instruction_format_F3a(0, ls, C). -asm(N, ls_offset(Label)) --> instruction_format_F3b(0, ls, Label, N). -asm(_, ls_link(C)) --> instruction_format_F3a(1, ls, C). -asm(N, ls_link_offset(Label)) --> instruction_format_F3b(1, ls, Label, N). -asm(_, lt(C)) --> instruction_format_F3a(0, lt, C). -asm(N, lt_offset(Label)) --> instruction_format_F3b(0, lt, Label, N). -asm(_, lt_link(C)) --> instruction_format_F3a(1, lt, C). -asm(N, lt_link_offset(Label)) --> instruction_format_F3b(1, lt, Label, N). -asm(_, mi(C)) --> instruction_format_F3a(0, mi, C). -asm(N, mi_offset(Label)) --> instruction_format_F3b(0, mi, Label, N). -asm(_, mi_link(C)) --> instruction_format_F3a(1, mi, C). -asm(N, mi_link_offset(Label)) --> instruction_format_F3b(1, mi, Label, N). -asm(_, ne(C)) --> instruction_format_F3a(0, ne, C). -asm(N, ne_offset(Label)) --> instruction_format_F3b(0, ne, Label, N). -asm(_, ne_link(C)) --> instruction_format_F3a(1, ne, C). -asm(N, ne_link_offset(Label)) --> instruction_format_F3b(1, ne, Label, N). -asm(_, nv(C)) --> instruction_format_F3a(0, nv, C). % NeVer. -asm(N, nv_offset(Label)) --> instruction_format_F3b(0, nv, Label, N). -asm(_, nv_link(C)) --> instruction_format_F3a(1, nv, C). -asm(N, nv_link_offset(Label)) --> instruction_format_F3b(1, nv, Label, N). -asm(_, pl(C)) --> instruction_format_F3a(0, pl, C). -asm(N, pl_offset(Label)) --> instruction_format_F3b(0, pl, Label, N). -asm(_, pl_link(C)) --> instruction_format_F3a(1, pl, C). -asm(N, pl_link_offset(Label)) --> instruction_format_F3b(1, pl, Label, N). -asm(_, vc(C)) --> instruction_format_F3a(0, vc, C). -asm(N, vc_offset(Label)) --> instruction_format_F3b(0, vc, Label, N). -asm(_, vc_link(C)) --> instruction_format_F3a(1, vc, C). -asm(N, vc_link_offset(Label)) --> instruction_format_F3b(1, vc, Label, N). -asm(_, vs(C)) --> instruction_format_F3a(0, vs, C). -asm(N, vs_offset(Label)) --> instruction_format_F3b(0, vs, Label, N). -asm(_, vs_link(C)) --> instruction_format_F3a(1, vs, C). -asm(N, vs_link_offset(Label)) --> instruction_format_F3b(1, vs, Label, N). - -% This is the core of the assembler where the instruction formats are specified. - -instruction_format_F0(U, A, B, Op, C ) --> [0, 0, U, 0], reg(A), reg(B), operation(Op), skip(12), reg(C). -instruction_format_F1(U, V, A, B, Op, Im) --> [0, 1, U, V], reg(A), reg(B), operation(Op), immediate(Im). -instruction_format_F2(U, V, A, B, Offset) --> [1, 0, U, V], reg(A), reg(B), offset(Offset). -instruction_format_F3a(V, Cond, C ) --> [1, 1, 0, V], cond(Cond), skip(20), reg(C). -instruction_format_F3b(V, Cond, To, Here) --> [1, 1, 1, V], cond(Cond), encode_jump_offset(To, Here). - -immediate(Imm) --> encode_int(16, Imm), !. -offset(Offset) --> encode_int(20, Offset), !. - -skip(N) --> collect(N, Zeros), {Zeros ins 0..0}. - -encode_jump_offset(To, Here) --> {Offset is ((To - Here) >> 2) - 1}, encode_int(24, Offset). - -encode_int(Width, I) --> {I >= 0}, !, collect(Width, Bits), { binary_number(Bits, I) }, !. -encode_int(Width, I) --> {I < 0}, !, collect(Width, Bits), {twos_compliment(Bits, I, Width)}, !. - -collect(N, []) --> {N =< 0}. -collect(N, [X|Rest]) --> {N > 0, N0 is N - 1}, [X], collect(N0, Rest). - -reg( 0) --> [0, 0, 0, 0]. -reg( 1) --> [0, 0, 0, 1]. -reg( 2) --> [0, 0, 1, 0]. -reg( 3) --> [0, 0, 1, 1]. -reg( 4) --> [0, 1, 0, 0]. -reg( 5) --> [0, 1, 0, 1]. -reg( 6) --> [0, 1, 1, 0]. -reg( 7) --> [0, 1, 1, 1]. -reg( 8) --> [1, 0, 0, 0]. -reg( 9) --> [1, 0, 0, 1]. -reg(10) --> [1, 0, 1, 0]. -reg(11) --> [1, 0, 1, 1]. -reg(12) --> [1, 1, 0, 0]. -reg(13) --> [1, 1, 0, 1]. -reg(14) --> [1, 1, 1, 0]. -reg(15) --> [1, 1, 1, 1]. - -operation(mov) --> [0, 0, 0, 0]. -operation(lsl) --> [0, 0, 0, 1]. -operation(asr) --> [0, 0, 1, 0]. -operation(ror) --> [0, 0, 1, 1]. -operation(and) --> [0, 1, 0, 0]. -operation(ann) --> [0, 1, 0, 1]. -operation(ior) --> [0, 1, 1, 0]. -operation(xor) --> [0, 1, 1, 1]. -operation(add) --> [1, 0, 0, 0]. -operation(sub) --> [1, 0, 0, 1]. -operation(mul) --> [1, 0, 1, 0]. -operation(div) --> [1, 0, 1, 1]. -operation(fad) --> [1, 1, 0, 0]. -operation(fsb) --> [1, 1, 0, 1]. -operation(fml) --> [1, 1, 1, 0]. -operation(fdv) --> [1, 1, 1, 1]. - -cond(mi) --> [0, 0, 0, 0]. -cond(eq) --> [0, 0, 0, 1]. -cond(cs) --> [0, 0, 1, 0]. -cond(vs) --> [0, 0, 1, 1]. -cond(ls) --> [0, 1, 0, 0]. -cond(lt) --> [0, 1, 0, 1]. -cond(le) --> [0, 1, 1, 0]. -cond(do) --> [0, 1, 1, 1]. -cond(pl) --> [1, 0, 0, 0]. -cond(ne) --> [1, 0, 0, 1]. -cond(cc) --> [1, 0, 1, 0]. -cond(vc) --> [1, 0, 1, 1]. -cond(hi) --> [1, 1, 0, 0]. -cond(ge) --> [1, 1, 0, 1]. -cond(gt) --> [1, 1, 1, 0]. -cond(nv) --> [1, 1, 1, 1]. - -pos_int16(I) :- I >= 0, I < 2^16. -pos_int15(I) :- I >= 0, I < 2^15. -neg_int15(I) :- I < 0, I >= -(2^15). -int15(I) :- pos_int15(I) ; neg_int15(I). - - -invert([], []). -invert([1|Tail], [0|Lait]) :- invert(Tail, Lait). -invert([0|Tail], [1|Lait]) :- invert(Tail, Lait). - -twos_compliment(Bits, Number, Width) :- - X is abs(Number), - binary_number(B, X), - length(B, Width), - invert(B, Antibits), - binary_number(Antibits, Y), - Z is Y+1, - length(Bits, Width), - binary_number(Bits, Z). - -% https://stackoverflow.com/a/28015816 - -canonical_binary_number([0], 0). -canonical_binary_number([1], 1). -canonical_binary_number([1|Bits], Number):- - when(ground(Number), - (Number > 1, - Pow is floor(log(Number) / log(2)), - Number1 is Number - 2 ^ Pow, - ( Number1 > 1 - -> Pow1 is floor(log(Number1) / log(2)) + 1 - ; Pow1 = 1 - ))), - length(Bits, Pow), - between(1, Pow, Pow1), - length(Bits1, Pow1), - append(Zeros, Bits1, Bits), - maplist(=(0), Zeros), - canonical_binary_number(Bits1, Number1), - Number is Number1 + 2 ^ Pow. - -binary_number( Bits , Number) :- canonical_binary_number(Bits, Number). -binary_number([0|Bits], Number) :- binary_number(Bits, Number). - - -% Helper code to write the list of bits as a binary file. - -for_serial(Binary, Ser) :- - length(Binary, LengthInBits), - LengthInBytes is LengthInBits >> 3, - skip(32, Caboose, []), % zero word to signal EOF to bootloader. - append(Binary, Caboose, B), - skip(32, G, B), % Address is zero. - binary_number(Bits, LengthInBytes), - collect(32, Bits, Ser, G). - -write_binary(Name, Binary) :- - open(Name, write, Stream, [type(binary)]), - for_serial(Binary, Ser), - phrase(write_binary_(Stream), Ser), - close(Stream). - -write_binary_(Stream) --> - % Handle "Endian-ness". - collect(8, Bits3), collect(8, Bits2), collect(8, Bits1), collect(8, Bits0), !, - {wb(Bits0, Stream), wb(Bits1, Stream), wb(Bits2, Stream), wb(Bits3, Stream)}, - write_binary_(Stream). -write_binary_(_) --> []. - -wb(Bits, Stream) :- binary_number(Bits, Byte), put_byte(Stream, Byte). diff --git a/thun/compiler.pl b/thun/compiler.pl deleted file mode 100644 index e62411b..0000000 --- a/thun/compiler.pl +++ /dev/null @@ -1,633 +0,0 @@ -/* - -Copyright © 2018 Simon Forman - -This file is part of Thun - -Thun is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Thun is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Thun. If not see . - -*/ -:- use_module(library(assoc)). -:- use_module(library(clpfd)). - - -do :- Program = [ - ヲ,∅,⟴,ヵ,メ,ョ, - [グ,ケ,ゲ,ド,ゴ,サ],ヮ(cons), - [ザ,シ],ヮ(dup), - [グ,ス,[],[ジ,ス,[ズ,セ,ス,[ゼ,ソ],[タ,ゾ],ヰ,ヂ],ヱ],ヰ,チ],ヮ(i), - [ヶ,ペ],ワ(new), - [ナ,ズ,セ,ネ,ヒ,ド,ャ,ペ],ワ(swap), - [new,cons],≡(unit), - [dup,i],≡(x), - [swap,cons],≡(swons) - ], -compile_program(Program, Binary), -write_binary('joy_asm.bin', Binary). - -% phrase(pass0(Program, AST), [], _), -% write_canonical(AST), -% phrase(⟐(AST), IR), -% write_canonical(IR), -% phrase(linker(IR), ASM), -% write_canonical(ASM). - -pass0(Code, Program) --> init, ⦾(Code, Program). - -init, [Context] --> - {empty_assoc(C), empty_assoc(Dictionary), - put_assoc(dictionary, C, Dictionary, Context)}. - -⦾([], []) --> []. - -⦾([Body, ≡(NameAtom)|Terms], [defi(Name, B, Prev, I, SP, TOS)|Ts]) --> - get(dict, Prev), set(dict, Name), get(sp, SP), get(tos, TOS), - inscribe(NameAtom, Name), ⦾(Terms, Ts), lookup(i, I), lookup(Body, B). - -⦾([Body, ヮ(NameAtom)|Terms], [definition(Name, DONE, B, Prev)|Ts]) --> - get(dict, Prev), set(dict, Name), inscribe(NameAtom, Name), - get(done, DONE), ⦾([Body, Terms], [B, Ts]). - -⦾([Body, ワ(NameAtom)|Terms], [definition(Name, MAIN, B, Prev)|Ts]) --> - get(dict, Prev), set(dict, Name), inscribe(NameAtom, Name), - get(main, MAIN), ⦾([Body, Terms], [B, Ts]). - -⦾([P, T, E, ヰ|Terms], [br(Predicate, Then, Else)|Ts]) --> - ⦾([P, T, E, Terms], [Predicate, Then, Else, Ts]). - -⦾([P, B, ヱ|Terms], [repeat_until(Predicate, Body)|Ts]) --> - ⦾([P, B, Terms], [Predicate, Body, Ts]). - -⦾([ヲ|Terms], Ts) --> % Preamble. - set(dict, 0), set(done, _DONE), - set(temp0, 6), set(temp1, 7), - set(temp2, 8), set(temp3, 9), - set(tos, 3), set(sp, 2), set(expr, 4), set(term, 5), - set(dict_top, 12), set(dict_ptr, 11), - set(halt, _HALT), set(main, _MAIN), set(reset, _Reset), - ⦾(Terms, Ts). - -⦾([ヵ|Terms], [ % Initialization. - jump(Over), % Oberon bootloader writes MemLim to RAM[12] and - asm(allocate(_, 16)), % stackOrg to RAM[24], we don't need these - label(Over), % but they must not be allowed to corrupt our code. - set_reg_const(0, 0), % zero out the root cell. - write_ram(0, 0), - set_reg_const(SP, 0x1000), - set_reg_const(EXPR, 0x500), - set_reg_label(DICT_TOP, LastWord), - set_reg_const(TOS, 0), - set_reg_const(TERM, 0), - asm(store_word(TOS, SP, 0)) % RAM[SP] := 0 - |Ts]) --> - get(dict_top, DICT_TOP), get(expr, EXPR), - get(sp, SP), get(term, TERM), get(tos, TOS), - ⦾(Terms, Ts), get(dict, LastWord). - -⦾([メ|Terms], [ % Mainloop. - label(MAIN), - if_zero(EXPR, HALT), - deref(EXPR), - split_word(TERM, EXPR), - if_literal(TERM, PUSH), - lookup(DICT_PTR, DICT_TOP, TERM, HALT), % Jump to command or if not found halt. - label(PUSH), push(TOS, TERM, SP), % stack = TERM, stack - label(DONE), write_ram(SP, TOS), % RAM[SP] := TOS - jump(MAIN) - |Ts]) --> - get(done, DONE), get(main, MAIN), get(halt, HALT), - get(dict_ptr, DICT_PTR), get(dict_top, DICT_TOP), get(expr, EXPR), - get(sp, SP), get(term, TERM), get(tos, TOS), - ⦾(Terms, Ts). - -⦾([Term|Terms], [T|Ts]) --> ⦾(Term, T), ⦾(Terms, Ts). - -⦾(∅, dw(0)) --> []. -⦾(⟴, label(Reset)) --> get(reset, Reset). -⦾(ョ, halt(HALT)) --> get(halt, HALT). -⦾(グ, pop(TEMP0, TOS)) --> get(temp0, TEMP0), get(tos, TOS). -⦾(シ, push(TOS, TOS, SP)) --> get(tos, TOS), get(sp, SP). -⦾(ケ, high_half(TEMP1, TOS)) --> get(temp1, TEMP1), get(tos, TOS). -⦾(サ, merge(SP, TOS)) --> get(tos, TOS), get(sp, SP). -⦾(ザ, swap_halves(TOS)) --> get(tos, TOS). -⦾(ズ, deref(TEMP0)) --> get(temp0, TEMP0). -⦾(ス, if_zero(TEMP0)) --> get(temp0, TEMP0). -⦾(ソ, asm(mov(EXPR, TEMP3))) --> get(expr, EXPR), get(temp3, TEMP3). -⦾(ャ, asm(ior(TOS, TEMP1, SP))) --> get(tos, TOS), get(temp1, TEMP1), get(sp, SP). -⦾(タ, add_const(TEMP2, SP, 8)) --> get(temp2, TEMP2), get(sp, SP). -⦾(ジ, add_const(TEMP3, SP, 4)) --> get(temp3, TEMP3), get(sp, SP). -⦾(チ, add_const(SP, SP, 4)) --> get(sp, SP). -⦾(セ, chop_word(TEMP1, TEMP0)) --> get(temp0, TEMP0), get(temp1, TEMP1). -⦾(ト, chop_word(TEMP0, TOS)) --> get(temp0, TEMP0), get(tos, TOS). -⦾(ネ, chop_word(TEMP2, TOS)) --> get(temp2, TEMP2), get(tos, TOS). -⦾(ゼ, or_inplace(TEMP1, EXPR)) --> get(expr, EXPR), get(temp1, TEMP1). -⦾(ゲ, or_inplace(TEMP0, TEMP1)) --> get(temp0, TEMP0), get(temp1, TEMP1). -⦾(ヒ, or_inplace(TEMP0, TEMP2)) --> get(temp0, TEMP0), get(temp2, TEMP2). -⦾(ゾ, or_inplace(TEMP1, TEMP2)) --> get(temp1, TEMP1), get(temp2, TEMP2). -⦾(ド, write_cell(TEMP0, SP)) --> get(temp0, TEMP0), get(sp, SP). -⦾(ヂ, write_cell(TEMP1, SP)) --> get(temp1, TEMP1), get(sp, SP). -⦾(ペ, write_cell(TOS, SP)) --> get(tos, TOS), get(sp, SP). -⦾(ゴ, low_half(TOS)) --> get(tos, TOS). -⦾(ナ, low_half(TEMP0, TOS)) --> get(temp0, TEMP0), get(tos, TOS). -⦾(ヶ, low_half(TOS, SP)) --> get(sp, SP), get(tos, TOS). - -get(Key, Value) --> state(Context), {get_assoc(Key, Context, Value)}. -set(Key, Value) --> state(ContextIn, ContextOut), - {put_assoc(Key, ContextIn, Value, ContextOut)}. - -inscribe(NameAtom, Label) --> state(ContextIn, ContextOut), - {get_assoc(dictionary, ContextIn, Din), - put_assoc(NameAtom, Din, Label, Dout), - put_assoc(dictionary, ContextIn, Dout, ContextOut)}. - -lookup([], []) --> !. -lookup([T|Ts], [V|Vs]) --> !, lookup(T, V), lookup(Ts, Vs). -lookup(NameAtom, Label) --> state(Context), - {get_assoc(dictionary, Context, D), get_assoc(NameAtom, D, Label)}. - -state(S), [S] --> [S]. -state(S0, S), [S] --> [S0]. - -⟐([]) --> []. -⟐([Term|Terms]) --> ⟐(Term), ⟐(Terms). - -⟐(if_literal(Reg, Label)) --> % commands marked by setting high bit. - [and_imm(0, Reg, 0x8000), % 1 << 15 - eq_offset(Label)]. - -% if reg = 0 jump to label. -⟐(if_zero(Reg, Label)) --> [sub_imm(Reg, Reg, 0), eq_offset(Label)]. - -⟐(set_reg_const(Reg, Immediate)) --> {Immediate >= -(2^15), Immediate < 2^16}, !, - [mov_imm(Reg, Immediate)]. - -⟐(set_reg_const(Reg, Immediate)) --> {Immediate >= 0, Immediate < 2^33}, !, % FIXME: handle negative numbers. - {high_half_word(Immediate, HighHalf), low_half_word(Immediate, LowHalf)}, - [ mov_imm_with_shift(Reg, HighHalf), ior_imm(Reg, Reg, LowHalf)]. - -⟐(set_reg_label(Reg, Label)) --> [mov_imm(Reg, Label)]. - -⟐( noop) --> [mov(0, 0)]. -⟐( halt(Halt)) --> [label(Halt), do_offset(Halt)]. -⟐( asm(ASM)) --> [ASM]. -⟐(label(Label)) --> [label(Label)]. -⟐( jump(Label)) --> [do_offset(Label)]. -⟐( dw(Int)) --> [word(Int)]. - -⟐( low_half(Reg)) --> [and_imm(Reg, Reg, 0xffff)]. -⟐( low_half(To, From)) --> [and_imm(To, From, 0xffff)]. -⟐( high_half(Reg)) --> [mov_imm_with_shift(0, 0xffff), and(Reg, Reg, 0)]. -⟐(high_half(To, From)) --> [mov_imm_with_shift(0, 0xffff), and(To, From, 0)]. - -⟐(swap_halves(Register)) --> [ror_imm(Register, Register, 16)]. -⟐(swap_halves(To, From)) --> [ror_imm( To, From, 16)]. - -⟐(high_half_to(To, From)) --> ⟐([swap_halves(To, From), low_half(To)]). - -⟐(split_word(To, From)) --> ⟐([high_half_to(To, From), low_half(From)]). - -⟐(chop_word(To, From)) --> ⟐([high_half(To, From), low_half(From)]). - -⟐(merge(SP, TOS)) --> - [lsl_imm(0, SP, 16), - ior(TOS, TOS, 0), - add_imm(SP, SP, 4)]. - -⟐(push(TOS, TERM, SP)) --> - [lsl_imm(TOS, TERM, 16), % TOS := TERM << 16 - ior(TOS, TOS, SP), % TOS := TOS | SP - add_imm(SP, SP, 4)]. % SP += 1 (word, not byte) - -⟐( write_ram(To, From)) --> [store_word(From, To, 0)]. -⟐(write_cell(From, SP)) --> [add_imm(SP, SP, 4), store_word(From, SP, 0)]. - -⟐(deref(Reg)) --> [load_word(Reg, Reg, 0)]. - -⟐(or_inplace(To, From)) --> [ior(To, To, From)]. - -⟐(definition(Label, Exit, Body, Prev)) --> - ⟐([ - dw(Prev), - label(Label), - Body, - jump(Exit) - ]). - -⟐(defi(Label, Body, Prev, I, SP, TOS)) --> - ⟐([dw(Prev), - label(Label), - defi_def(BodyLabel, SP, TOS), - jump(I)]), - dexpr(Body, BodyLabel). - -⟐(defi_def(Label, SP, TOS)) --> - [mov_imm_with_shift(TOS, Label), - ior(TOS, TOS, SP)], - ⟐(write_cell(TOS, SP)). - -⟐(lookup(PTR, TOP, TERM, Exit)) --> - [mov(PTR, TOP), % point to the top of the dictionary. - label(Lookup), - sub(0, TERM, PTR), eq(PTR), % if the term is found jump to it, - sub_imm(PTR, PTR, 4), % else load the next pointer. - load_word(PTR, PTR, 0), - sub_imm(PTR, PTR, 0), eq_offset(Exit), % exit if it's zero. - do_offset(Lookup)]. % loop to the top. - -⟐(repeat_until(Condition, Body)) --> - {add_label(Condition, End, ConditionL)}, - ⟐([ - label(Loop), - Body, - ConditionL, - jump(Loop), - label(End) - ]). - -⟐(br(Condition, [], Else)) --> !, - {add_label(Condition, END, ConditionL)}, - ⟐([ConditionL, Else, label(END)]). - -⟐(br(Condition, Then, Else)) --> - {add_label(Condition, THEN, ConditionL)}, - ⟐([ - ConditionL, Else, jump(END), - label(THEN), Then, label(END) - ]). - -⟐(add_const(To, From, Immediate)) --> [add_imm(To, From, Immediate)]. - -⟐(pop(Reg, TOS)) --> ⟐([split_word(Reg, TOS), deref(TOS)]). - -dexpr([], 0) --> []. -dexpr([Func|Rest], ThisCell) --> - [label(ThisCell), expr_cell(Func, NextCell)], - dexpr(Rest, NextCell). - -add_label(CmpIn, Label, CmpOut) :- - CmpIn =.. F, - append(F, [Label], G), - CmpOut =.. G. - -high_half_word(I, HighHalf) :- HighHalf is I >> 16 /\ 0xFFFF. -low_half_word( I, LowHalf) :- LowHalf is I /\ 0xFFFF. - -compile_program(Program, Binary) :- - phrase(pass0(Program, AST), [], _), - phrase(⟐(AST), IR), - phrase(linker(IR), ASM), - phrase(asm(ASM), Binary). - -/* - -| o._ | _ ._ -|_|| ||<(/_| - -Linker - -Logical variables for addresses are unified with the actual locations and -each instruction is paired with its address. - -linker//1 unparses a list of the "IR" that ⟐//1 emits and in turn emits a -list of (Address, Instruction) pairs for assembly instructions. - - */ - -linker(IntermediateRepresentation) --> enumerate_asm(IntermediateRepresentation, 0, _). - -enumerate_asm( [], N, N) --> !, []. -enumerate_asm( [Term|Terms], N, M) --> !, enumerate_asm(Term, N, O), enumerate_asm(Terms, O, M). -enumerate_asm( label(N) , N, N) --> !, []. -enumerate_asm(allocate(N, Bytes), N, M) --> !, [skip(Bits)], {align(N, Bytes, M), Bits is 8 * Bytes}. -enumerate_asm( Instr, N, M) --> [(Z, Instr)], {align(N, 0, Z), align(Z, 4, M)}. - -align(_, Bytes, _) :- (Bytes < 0 -> write('Align negative number? No!')), !, fail. -align(N, 1, M) :- !, M is N + 1. -align(N, Bytes, M) :- N mod 4 =:= 0, !, M is N + Bytes. -align(N, Bytes, M) :- Padding is 4 - (N mod 4), M is N + Bytes + Padding. - -/* - - /\ _ _ _ ._ _ |_ | _ ._ -/--\_>_>(/_| | ||_)|(/_| - -Assembler - -The asm//1 DCG unparses a list of (Address, Instruction) pairs into a list -of 0 or 1 ints representing the binary bits of the machine code. The actual -work is done by asm//2 which uses instruction_format_Fn//n DCGs to generate -the bits. - - */ - -asm([]) --> !, []. -asm([ skip(Bits)|Rest]) --> !, skip(Bits), asm(Rest). -asm([(N, Instruction)|Rest]) --> !, asm(N, Instruction), asm(Rest). - -asm(_, expr_cell(Func, NextCell)) --> !, - {Data is (Func << 16) \/ NextCell}, asm(_, word(Data)). - -asm(_, word(Word)) --> !, {binary_number(Bits, Word)}, collect(32, Bits). - -asm(_, load_word(A, B, Offset)) --> !, instruction_format_F2(0, 0, A, B, Offset). -asm(_, load_byte(A, B, Offset)) --> !, instruction_format_F2(0, 1, A, B, Offset). -asm(_, store_word(A, B, Offset)) --> !, instruction_format_F2(1, 0, A, B, Offset). -asm(_, store_byte(A, B, Offset)) --> !, instruction_format_F2(1, 1, A, B, Offset). - -asm(_, mov(A, C)) --> instruction_format_F0(0, A, 0, mov, C). -asm(_, mov_with_shift(A, C)) --> instruction_format_F0(1, A, 0, mov, C). - -asm(_, mov_imm_with_shift(A, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(1, 0, A, 0, mov, Imm). -asm(_, mov_imm_with_shift(A, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(1, 0, A, 0, mov, Imm). -asm(_, mov_imm_with_shift(_, _)) --> {write('Immediate value out of bounds'), fail}. - -asm(_, mov_imm(A, Imm) ) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, 0, mov, Imm). -asm(_, mov_imm(A, Imm) ) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, 0, mov, Imm). -asm(_, mov_imm(_, _) ) --> {write('Immediate value out of bounds'), fail}. - -asm(_, add(A, B, C)) --> instruction_format_F0(0, A, B, add, C). -asm(_, add_carry(A, B, C)) --> instruction_format_F0(1, A, B, add, C). -asm(_, sub(A, B, C)) --> instruction_format_F0(0, A, B, sub, C). -asm(_, sub_carry(A, B, C)) --> instruction_format_F0(1, A, B, sub, C). - -asm(_, add_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, add, Imm). -asm(_, add_imm(A, B, Imm)) --> {pos_int15(Imm)}, !, instruction_format_F1(0, 0, A, B, add, Imm). -asm(_, add_imm_carry(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(1, 1, A, B, add, Imm). -asm(_, add_imm_carry(A, B, Imm)) --> {pos_int15(Imm)}, !, instruction_format_F1(1, 0, A, B, add, Imm). -asm(_, sub_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, sub, Imm). -asm(_, sub_imm(A, B, Imm)) --> {pos_int15(Imm)}, !, instruction_format_F1(0, 0, A, B, sub, Imm). -asm(_, sub_imm_carry(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(1, 1, A, B, sub, Imm). -asm(_, sub_imm_carry(A, B, Imm)) --> {pos_int15(Imm)}, !, instruction_format_F1(1, 0, A, B, sub, Imm). - -asm(_, mul(A, B, C)) --> instruction_format_F0(0, A, B, mul, C). -asm(_, mul_unsigned(A, B, C)) --> instruction_format_F0(1, A, B, mul, C). -asm(_, mul_imm(A, B, Imm, U)) --> {neg_int15(Imm)}, !, instruction_format_F1(U, 1, A, B, mul, Imm). -asm(_, mul_imm(A, B, Imm, U)) --> {pos_int15(Imm)}, !, instruction_format_F1(U, 0, A, B, mul, Imm). - -asm(_, and(A, B, C)) --> instruction_format_F0(0, A, B, and, C). -asm(_, ann(A, B, C)) --> instruction_format_F0(0, A, B, ann, C). -asm(_, asr(A, B, C)) --> instruction_format_F0(0, A, B, asr, C). -asm(_, div(A, B, C)) --> instruction_format_F0(0, A, B, div, C). -asm(_, ior(A, B, C)) --> instruction_format_F0(0, A, B, ior, C). -asm(_, lsl(A, B, C)) --> instruction_format_F0(0, A, B, lsl, C). -asm(_, ror(A, B, C)) --> instruction_format_F0(0, A, B, ror, C). -asm(_, xor(A, B, C)) --> instruction_format_F0(0, A, B, xor, C). - -asm(_, and_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, and, Imm). -asm(_, and_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, and, Imm). -asm(_, ann_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, ann, Imm). -asm(_, ann_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, ann, Imm). -asm(_, asr_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, asr, Imm). -asm(_, asr_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, asr, Imm). -asm(_, div_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, div, Imm). -asm(_, div_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, div, Imm). -asm(_, ior_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, ior, Imm). -asm(_, ior_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, ior, Imm). -asm(_, lsl_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, lsl, Imm). -asm(_, lsl_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, lsl, Imm). -asm(_, ror_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, ror, Imm). -asm(_, ror_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, ror, Imm). -asm(_, xor_imm(A, B, Imm)) --> {neg_int15(Imm)}, !, instruction_format_F1(0, 1, A, B, xor, Imm). -asm(_, xor_imm(A, B, Imm)) --> {pos_int16(Imm)}, !, instruction_format_F1(0, 0, A, B, xor, Imm). - -asm(_, cc(C)) --> instruction_format_F3a(0, cc, C). -asm(N, cc_offset(Label)) --> instruction_format_F3b(0, cc, Label, N). -asm(_, cc_link(C)) --> instruction_format_F3a(1, cc, C). -asm(N, cc_link_offset(Label)) --> instruction_format_F3b(1, cc, Label, N). -asm(_, cs(C)) --> instruction_format_F3a(0, cs, C). -asm(N, cs_offset(Label)) --> instruction_format_F3b(0, cs, Label, N). -asm(_, cs_link(C)) --> instruction_format_F3a(1, cs, C). -asm(N, cs_link_offset(Label)) --> instruction_format_F3b(1, cs, Label, N). -asm(_, do(C)) --> instruction_format_F3a(0, do, C). -asm(N, do_offset(Label)) --> instruction_format_F3b(0, do, Label, N). -asm(_, do_link(C)) --> instruction_format_F3a(1, do, C). -asm(N, do_link_offset(Label)) --> instruction_format_F3b(1, do, Label, N). -asm(_, eq(C)) --> instruction_format_F3a(0, eq, C). -asm(N, eq_offset(Label)) --> instruction_format_F3b(0, eq, Label, N). -asm(_, eq_link(C)) --> instruction_format_F3a(1, eq, C). -asm(N, eq_link_offset(Label)) --> instruction_format_F3b(1, eq, Label, N). -asm(_, ge(C)) --> instruction_format_F3a(0, ge, C). -asm(N, ge_offset(Label)) --> instruction_format_F3b(0, ge, Label, N). -asm(_, ge_link(C)) --> instruction_format_F3a(1, ge, C). -asm(N, ge_link_offset(Label)) --> instruction_format_F3b(1, ge, Label, N). -asm(_, gt(C)) --> instruction_format_F3a(0, gt, C). -asm(N, gt_offset(Label)) --> instruction_format_F3b(0, gt, Label, N). -asm(_, gt_link(C)) --> instruction_format_F3a(1, gt, C). -asm(N, gt_link_offset(Label)) --> instruction_format_F3b(1, gt, Label, N). -asm(_, hi(C)) --> instruction_format_F3a(0, hi, C). -asm(N, hi_offset(Label)) --> instruction_format_F3b(0, hi, Label, N). -asm(_, hi_link(C)) --> instruction_format_F3a(1, hi, C). -asm(N, hi_link_offset(Label)) --> instruction_format_F3b(1, hi, Label, N). -asm(_, le(C)) --> instruction_format_F3a(0, le, C). -asm(N, le_offset(Label)) --> instruction_format_F3b(0, le, Label, N). -asm(_, le_link(C)) --> instruction_format_F3a(1, le, C). -asm(N, le_link_offset(Label)) --> instruction_format_F3b(1, le, Label, N). -asm(_, ls(C)) --> instruction_format_F3a(0, ls, C). -asm(N, ls_offset(Label)) --> instruction_format_F3b(0, ls, Label, N). -asm(_, ls_link(C)) --> instruction_format_F3a(1, ls, C). -asm(N, ls_link_offset(Label)) --> instruction_format_F3b(1, ls, Label, N). -asm(_, lt(C)) --> instruction_format_F3a(0, lt, C). -asm(N, lt_offset(Label)) --> instruction_format_F3b(0, lt, Label, N). -asm(_, lt_link(C)) --> instruction_format_F3a(1, lt, C). -asm(N, lt_link_offset(Label)) --> instruction_format_F3b(1, lt, Label, N). -asm(_, mi(C)) --> instruction_format_F3a(0, mi, C). -asm(N, mi_offset(Label)) --> instruction_format_F3b(0, mi, Label, N). -asm(_, mi_link(C)) --> instruction_format_F3a(1, mi, C). -asm(N, mi_link_offset(Label)) --> instruction_format_F3b(1, mi, Label, N). -asm(_, ne(C)) --> instruction_format_F3a(0, ne, C). -asm(N, ne_offset(Label)) --> instruction_format_F3b(0, ne, Label, N). -asm(_, ne_link(C)) --> instruction_format_F3a(1, ne, C). -asm(N, ne_link_offset(Label)) --> instruction_format_F3b(1, ne, Label, N). -asm(_, nv(C)) --> instruction_format_F3a(0, nv, C). % NeVer. -asm(N, nv_offset(Label)) --> instruction_format_F3b(0, nv, Label, N). -asm(_, nv_link(C)) --> instruction_format_F3a(1, nv, C). -asm(N, nv_link_offset(Label)) --> instruction_format_F3b(1, nv, Label, N). -asm(_, pl(C)) --> instruction_format_F3a(0, pl, C). -asm(N, pl_offset(Label)) --> instruction_format_F3b(0, pl, Label, N). -asm(_, pl_link(C)) --> instruction_format_F3a(1, pl, C). -asm(N, pl_link_offset(Label)) --> instruction_format_F3b(1, pl, Label, N). -asm(_, vc(C)) --> instruction_format_F3a(0, vc, C). -asm(N, vc_offset(Label)) --> instruction_format_F3b(0, vc, Label, N). -asm(_, vc_link(C)) --> instruction_format_F3a(1, vc, C). -asm(N, vc_link_offset(Label)) --> instruction_format_F3b(1, vc, Label, N). -asm(_, vs(C)) --> instruction_format_F3a(0, vs, C). -asm(N, vs_offset(Label)) --> instruction_format_F3b(0, vs, Label, N). -asm(_, vs_link(C)) --> instruction_format_F3a(1, vs, C). -asm(N, vs_link_offset(Label)) --> instruction_format_F3b(1, vs, Label, N). - -/* -___ _ - | ._ __|_._ __|_o _ ._ |__ ._._ _ _._|_ _ -_|_| |_> |_||_|(_ |_|(_)| | |(_)| | | |(_| |__> - -This is the core of the assembler where the instruction formats are -specified. Each one is a 32-bit word. - -The various jump-to-offset instructions use the addresses to compute the -jump offsets. Offsets and immediate values are converted to binary. - - */ - -instruction_format_F0(U, A, B, Op, C ) --> [0, 0, U, 0], reg(A), reg(B), operation(Op), skip(12), reg(C). -instruction_format_F1(U, V, A, B, Op, Im) --> [0, 1, U, V], reg(A), reg(B), operation(Op), immediate(Im). -instruction_format_F2(U, V, A, B, Offset) --> [1, 0, U, V], reg(A), reg(B), offset(Offset). -instruction_format_F3a(V, Cond, C ) --> [1, 1, 0, V], cond(Cond), skip(20), reg(C). -instruction_format_F3b(V, Cond, To, Here) --> [1, 1, 1, V], cond(Cond), encode_jump_offset(To, Here). - -immediate(Imm) --> encode_int(16, Imm), !. -offset(Offset) --> encode_int(20, Offset), !. - -skip(N) --> collect(N, Zeros), {Zeros ins 0..0}. - -encode_jump_offset(To, Here) --> {Offset is ((To - Here) >> 2) - 1}, encode_int(24, Offset). - -encode_int(Width, I) --> {I >= 0}, !, collect(Width, Bits), { binary_number(Bits, I) }, !. -encode_int(Width, I) --> {I < 0}, !, collect(Width, Bits), {twos_compliment(Bits, I, Width)}, !. - -collect(N, []) --> {N =< 0}. -collect(N, [X|Rest]) --> {N > 0, N0 is N - 1}, [X], collect(N0, Rest). - -reg( 0) --> [0, 0, 0, 0]. -reg( 1) --> [0, 0, 0, 1]. -reg( 2) --> [0, 0, 1, 0]. -reg( 3) --> [0, 0, 1, 1]. -reg( 4) --> [0, 1, 0, 0]. -reg( 5) --> [0, 1, 0, 1]. -reg( 6) --> [0, 1, 1, 0]. -reg( 7) --> [0, 1, 1, 1]. -reg( 8) --> [1, 0, 0, 0]. -reg( 9) --> [1, 0, 0, 1]. -reg(10) --> [1, 0, 1, 0]. -reg(11) --> [1, 0, 1, 1]. -reg(12) --> [1, 1, 0, 0]. -reg(13) --> [1, 1, 0, 1]. -reg(14) --> [1, 1, 1, 0]. -reg(15) --> [1, 1, 1, 1]. - -operation(mov) --> [0, 0, 0, 0]. -operation(lsl) --> [0, 0, 0, 1]. -operation(asr) --> [0, 0, 1, 0]. -operation(ror) --> [0, 0, 1, 1]. -operation(and) --> [0, 1, 0, 0]. -operation(ann) --> [0, 1, 0, 1]. -operation(ior) --> [0, 1, 1, 0]. -operation(xor) --> [0, 1, 1, 1]. -operation(add) --> [1, 0, 0, 0]. -operation(sub) --> [1, 0, 0, 1]. -operation(mul) --> [1, 0, 1, 0]. -operation(div) --> [1, 0, 1, 1]. -operation(fad) --> [1, 1, 0, 0]. -operation(fsb) --> [1, 1, 0, 1]. -operation(fml) --> [1, 1, 1, 0]. -operation(fdv) --> [1, 1, 1, 1]. - -cond(mi) --> [0, 0, 0, 0]. -cond(eq) --> [0, 0, 0, 1]. -cond(cs) --> [0, 0, 1, 0]. -cond(vs) --> [0, 0, 1, 1]. -cond(ls) --> [0, 1, 0, 0]. -cond(lt) --> [0, 1, 0, 1]. -cond(le) --> [0, 1, 1, 0]. -cond(do) --> [0, 1, 1, 1]. -cond(pl) --> [1, 0, 0, 0]. -cond(ne) --> [1, 0, 0, 1]. -cond(cc) --> [1, 0, 1, 0]. -cond(vc) --> [1, 0, 1, 1]. -cond(hi) --> [1, 1, 0, 0]. -cond(ge) --> [1, 1, 0, 1]. -cond(gt) --> [1, 1, 1, 0]. -cond(nv) --> [1, 1, 1, 1]. - -pos_int16(I) :- I >= 0, I < 2^16. -pos_int15(I) :- I >= 0, I < 2^15. -neg_int15(I) :- I < 0, I >= -(2^15). -int15(I) :- pos_int15(I) ; neg_int15(I). - - -invert([], []). -invert([1|Tail], [0|Lait]) :- invert(Tail, Lait). -invert([0|Tail], [1|Lait]) :- invert(Tail, Lait). - - -/* - _ -|_)o._ _.._ |\ | ._ _ |_ _ .__ -|_)|| |(_||\/ | \||_|| | ||_)(/_|_> - / - -binary_number(ListOfBits, Integer) - -twos_compliment(ListOfBits, Integer, NumberOfBits) - - */ - -twos_compliment(Bits, Number, Width) :- - X is abs(Number), - binary_number(B, X), - length(B, Width), - invert(B, Antibits), - binary_number(Antibits, Y), - Z is Y+1, - length(Bits, Width), - binary_number(Bits, Z). - -% https://stackoverflow.com/a/28015816 - -canonical_binary_number([0], 0). -canonical_binary_number([1], 1). -canonical_binary_number([1|Bits], Number):- - when(ground(Number), - (Number > 1, - Pow is floor(log(Number) / log(2)), - Number1 is Number - 2 ^ Pow, - ( Number1 > 1 - -> Pow1 is floor(log(Number1) / log(2)) + 1 - ; Pow1 = 1 - ))), - length(Bits, Pow), - between(1, Pow, Pow1), - length(Bits1, Pow1), - append(Zeros, Bits1, Bits), - maplist(=(0), Zeros), - canonical_binary_number(Bits1, Number1), - Number is Number1 + 2 ^ Pow. - -binary_number([0|Bits], Number) :- binary_number(Bits, Number). -binary_number( Bits , Number) :- canonical_binary_number(Bits, Number). - - -% Helper code to write the list of bits as a binary file. - -for_serial(Binary, Ser) :- - length(Binary, LengthInBits), - LengthInBytes is LengthInBits >> 3, - skip(32, Caboose, []), % zero word to signal EOF to bootloader. - append(Binary, Caboose, B), - skip(32, G, B), % Address is zero. - binary_number(Bits, LengthInBytes), - collect(32, Bits, Ser, G). - -write_binary(Name, Binary) :- - open(Name, write, Stream, [type(binary)]), - phrase(write_binary_(Stream), Binary), - close(Stream). - -write_binary_(Stream) --> - % Handle "Endian-ness". - collect(8, Bits3), collect(8, Bits2), collect(8, Bits1), collect(8, Bits0), !, - {wb(Bits0, Stream), wb(Bits1, Stream), wb(Bits2, Stream), wb(Bits3, Stream)}, - write_binary_(Stream). -write_binary_(_) --> []. - -wb(Bits, Stream) :- binary_number(Bits, Byte), put_byte(Stream, Byte). diff --git a/thun/crap-n-stuff.txt b/thun/crap-n-stuff.txt deleted file mode 100644 index 7507386..0000000 --- a/thun/crap-n-stuff.txt +++ /dev/null @@ -1,93 +0,0 @@ - - -combo(branch, [T, F, Expr|S], S, Ei, Eo) :- - \+ Expr = true, \+ Expr = false, - catch( % Try Expr and do one or the other, - (Expr -> append(T, Ei, Eo) ; append(F, Ei, Eo)), - _, % If Expr don't grok, try both branches. - (append(T, Ei, Eo) ; append(F, Ei, Eo)) - ). - -combo(loop, [B, Expr|S], S, Ei, Eo) :- - \+ Expr = true, \+ Expr = false, - catch( % Try Expr and do one or the other, - (Expr -> append(B, [B, loop|Ei], Eo) ; Ei=Eo), - _, % If Expr don't grok, try both branches. - (Ei=Eo ; append(B, [B, loop|Ei], Eo)) - ). - -/* - -To handle comparision operators the possibility of exceptions due to -insufficiently instantiated arguments must be handled. First try to make -the comparison and set the result to a Boolean atom. If an exception -happens just leave the comparison expression as the result and some other -function or combinator will deal with it. Example: - - func(>, [A, B|S], [C|S]) :- catch( - (B > A -> C=true ; C=false), - _, - C=(B>A) % in case of error. - ). - -To save on conceptual overhead I've defined a term_expansion/2 that sets -up the func/3 for each op. -*/ - -term_expansion(comparison_operator(X), (func(X, [A, B|S], [C|S]) :- - F =.. [X, B, A], catch((F -> C=true ; C=false), _, C=F))). - -% I don't use Prolog-compatible op symbols in all cases. -term_expansion(comparison_operator(X, Y), (func(X, [A, B|S], [C|S]) :- - F =.. [Y, B, A], catch((F -> C=true ; C=false), _, C=F))). - -% Likewise for math operators, try to evaluate, otherwise use the -% symbolic form. - -term_expansion(math_operator(X), (func(X, [A, B|S], [C|S]) :- - F =.. [X, B, A], catch(C is F, _, C=F))). - -term_expansion(math_operator(X, Y), (func(X, [A, B|S], [C|S]) :- - F =.. [Y, B, A], catch(C is F, _, C=F))). - - - -% Symbolic math expressions are literals. -literal(_+_). -literal(_-_). -literal(_*_). -literal(_/_). -literal(_ mod _). - -% Symbolic comparisons are literals. -literal(_>_). -literal(_<_). -literal(_>=_). -literal(_=<_). -literal(_=:=_). -literal(_=\=_). - - - -% Symbolic math. Compute the answer, or derivative, or whatever, later. -math_operator(+). -math_operator(-). -math_operator(*). -math_operator(/). -math_operator(mod). - -% Attempt to calculate the value of a symbolic math expression. -func(calc, [A|S], [B|S]) :- B is A. - -func(sqrt, [A|S], [sqrt(A)|S]). - - -comparison_operator(>). -comparison_operator(<). -comparison_operator(>=). -comparison_operator(<=, =<). -comparison_operator(=, =:=). -comparison_operator(<>, =\=). - - - diff --git a/thun/defs.pl b/thun/defs.pl deleted file mode 100644 index 5a2853c..0000000 --- a/thun/defs.pl +++ /dev/null @@ -1,76 +0,0 @@ -% Apparently there's no good way to have multi-line string literals in -% Prolog code. I could do something like this: - -def(`-- 1 -`). -def(`? dup bool`). -def(`++ 1 +`). -def(`anamorphism [pop []] swap [dip swons] genrec`). -def(`app1 grba infrst`). -def(`app2 [grba swap grba swap] dip [infrst] cons ii`). -def(`app3 3 appN`). -def(`appN [grabN] cons dip map disenstacken`). -def(`at drop first`). -def(`average [sum 1.0 *] [size] cleave /`). -def(`b [i] dip i`). -def(`binary unary popd`). -def(`ccons cons cons`). -def(`cleave fork popdd`). -def(`clop cleave popdd`). -def(`codireco cons dip rest cons`). -def(`dinfrirst dip infrst`). -def(`disenstacken ? [uncons ?] loop pop`). -def(`down_to_zero [0 >] [dup --] while`). -def(`drop [rest] times`). -def(`dupd [dup] dip`). -def(`dupdd [dup] dipd`). -def(`dupdipd dup dipd`). -def(`enstacken stack [clear] dip`). -def(`flatten [] swap [concat] step`). -def(`fork [i] app2`). -def(`fourth rest third`). -def(`gcd true [tuck mod dup 0 >] loop pop`). -def(`grabN [] swap [cons] times`). -def(`grba [stack popd] dip`). -def(`hypot [sqr] ii + sqrt`). -def(`ifte [nullary] dipd swap branch`). -def(`ii [dip] dupdip i`). -def(`infra swons swaack [i] dip swaack`). -def(`infrst infra first`). -def(`make_generator [codireco] ccons`). -def(`neg 0 swap -`). -def(`not [true] [false] branch`). -def(`nullary [stack] dinfrirst`). -def(`of swap at`). -def(`pam [i] map`). -def(`pm [+] [-] clop`). -def(`popd [pop] dip`). -def(`popdd [pop] dipd`). -def(`popop pop pop`). -def(`popopd [popop] dip`). -def(`popopdd [popop] dipd`). -def(`primrec [i] genrec`). -def(`product 1 swap [*] step`). -def(`quoted [unit] dip`). -def(`range [0 <=] [1 - dup] anamorphism`). -def(`range_to_zero unit [down_to_zero] infra`). -def(`reverse [] swap shunt`). -def(`rrest rest rest`). -def(`run [] swap infra`). -def(`second rest first`). -def(`shift uncons [swons] dip`). -def(`shunt [swons] step`). -def(`size 0 swap [pop ++] step`). -def(`split_at [drop] [take] clop`). -def(`sqr dup *`). -def(`step_zero 0 roll> step`). -def(`sum 0 swap [+] step`). -def(`swons swap cons`). -def(`take [] rolldown [shift] times pop`). -def(`ternary binary popd`). -def(`third rest second`). -def(`unary nullary popd`). -def(`unit [] cons`). -def(`unquoted [i] dip`). -def(`unswons uncons swap`). -def(`while swap [nullary] cons dup dipd concat loop`). -def(`x dup i`). \ No newline at end of file diff --git a/thun/defs.txt b/thun/defs.txt deleted file mode 100644 index 043b96a..0000000 --- a/thun/defs.txt +++ /dev/null @@ -1,78 +0,0 @@ --- 1 - -? dup bool -&& [nullary] cons [nullary [false]] dip branch -++ 1 + -|| [nullary] cons [nullary] dip [true] branch -!- 0 >= -abs dup 0 < [] [neg] branch -anamorphism [pop []] swap [dip swons] genrec -app1 grba infrst -app2 [grba swap grba swap] dip [infrst] cons ii -app3 3 appN -appN [grabN] cons dip map disenstacken -at drop first -average [sum 1.0 *] [size] cleave / -b [i] dip i -binary unary popd -ccons cons cons -cleave fork popdd -clop cleave popdd -codireco cons dip rest cons -dinfrirst dip infrst -disenstacken ? [uncons ?] loop pop -down_to_zero [0 >] [dup --] while -drop [rest] times -dupd [dup] dip -dupdd [dup] dipd -dupdipd dup dipd -enstacken stack [clear] dip -flatten [] swap [concat] step -fork [i] app2 -fourth rest third -gcd true [tuck mod dup 0 >] loop pop -grabN [] swap [cons] times -grba [stack popd] dip -hypot [sqr] ii + sqrt -ifte [nullary] dipd swap branch -ii [dip] dupdip i -infra swons swaack [i] dip swaack -infrst infra first -make_generator [codireco] ccons -neg 0 swap - -not [true] [false] branch -nullary [stack] dinfrirst -of swap at -pam [i] map -pm [+] [-] clop -popd [pop] dip -popdd [pop] dipd -popop pop pop -popopd [popop] dip -popopdd [popop] dipd -primrec [i] genrec -product 1 swap [*] step -quoted [unit] dip -range [0 <=] [1 - dup] anamorphism -range_to_zero unit [down_to_zero] infra -reverse [] swap shunt -rrest rest rest -run [] swap infra -second rest first -shift uncons [swons] dip -shunt [swons] step -size 0 swap [pop ++] step -spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte -split_at [drop] [take] clop -sqr dup * -step_zero 0 roll> step -sum 0 swap [+] step -swons swap cons -take [] rolldown [shift] times pop -ternary binary popd -third rest second -unary nullary popd -unit [] cons -unquoted [i] dip -unswons uncons swap -while swap [nullary] cons dup dipd concat loop -x dup i \ No newline at end of file diff --git a/thun/dump-asm.py b/thun/dump-asm.py deleted file mode 100644 index c0114cd..0000000 --- a/thun/dump-asm.py +++ /dev/null @@ -1,2 +0,0 @@ -with open('./thun/asm-dump.txt', 'wb') as f: f.write(' '.join('''\ -'''.splitlines()).replace('), ', '),\n')) \ No newline at end of file diff --git a/thun/gnu-prolog/DCG_basics.pl b/thun/gnu-prolog/DCG_basics.pl deleted file mode 100644 index 406f739..0000000 --- a/thun/gnu-prolog/DCG_basics.pl +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright 2019 Simon Forman - - This file is part of Thun - - Thun is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Thun is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Thun. If not see . - - -DCG basics. For some of this I cribbed the source from SWI library code -and adapted it for GNU Prolog Compiler. - -N.B. is_glyph//1 excludes '[' and ']' characters. D'oh! FIXME - -*/ - - -:- set_prolog_flag(double_quotes, codes). - - -% TODO: scientific notation. - -signed_float_or_integer(Codes) --> signed_digits(J), ".", !, digits(I), - { append(J, [0'.|I], Codes) }. -signed_float_or_integer(Codes) --> signed_digits(Codes). - -signed_digits([0'-|Codes]) --> "-", !, digits(Codes). -signed_digits( Codes ) --> digits(Codes). - -% Groups of characters. - -chars(Chars) --> one_or_more(char, Chars). -blanks --> blank, !, blanks | []. -digits(Digits) --> one_or_more(digit, Digits). - -% Character types. - -char(Ch) --> [Ch], { nonvar(Ch), is_glyph(Ch) }. -blank --> [Ch], { nonvar(Ch), is_space(Ch) }. -digit(Ch) --> [Ch], { nonvar(Ch), between(0'0, 0'9, Ch) }. - -is_glyph(Ch) :- Ch =\= 0'[, Ch =\= 0'], between(0'!, 0'~, Ch). -is_space(Ch) :- Ch =:= 32 ; between(9, 13, Ch). - -one_or_more(P, [Ch|Rest]) --> call(P, Ch), one_or_more(P, Rest). -one_or_more(P, [Ch] ) --> call(P, Ch). - diff --git a/thun/gnu-prolog/Makefile b/thun/gnu-prolog/Makefile deleted file mode 100644 index f8c1c6e..0000000 --- a/thun/gnu-prolog/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -#GPLC_OPTIONS=--min-size -GPLC_OPTIONS=--no-top-level -#GPLC_OPTIONS= - -THUN_DEPS=parser.pl defs.pl main.pl math.pl DCG_basics.pl fork.pl - -thun: thun.pl $(THUN_DEPS) Makefile - gplc $(GPLC_OPTIONS) -o thun thun.pl $(THUN_DEPS) - -defs.pl: meta-defs.pl parser.pl defs.txt thun.pl DCG_basics.pl - gprolog \ - --consult-file meta-defs.pl \ - --consult-file parser.pl \ - --consult-file fork.pl \ - --consult-file thun.pl \ - --consult-file DCG_basics.pl \ - --query-goal do - -math.pl: meta-math.pl - gprolog \ - --consult-file meta-math.pl \ - --query-goal do - diff --git a/thun/gnu-prolog/defs.pl b/thun/gnu-prolog/defs.pl deleted file mode 100644 index af6466d..0000000 --- a/thun/gnu-prolog/defs.pl +++ /dev/null @@ -1,69 +0,0 @@ -def(--,[1,-]). -def(?,[dup,bool]). -def(++,[1,+]). -def(anamorphism,[[pop,[]],swap,[dip,swons],genrec]). -def(app1,[grba,infrst]). -def(app2,[[grba,swap,grba,swap],dip,[infrst],cons,ii]). -def(app3,[3,appN]). -def(appN,[[grabN],cons,dip,map,disenstacken]). -def(at,[drop,first]). -def(b,[[i],dip,i]). -def(binary,[unary,popd]). -def(ccons,[cons,cons]). -def(cleave,[fork,popdd]). -def(clop,[cleave,popdd]). -def(codireco,[cons,dip,rest,cons]). -def(dinfrirst,[dip,infrst]). -def(disenstacken,[?,[uncons,?],loop,pop]). -def(down_to_zero,[[0,>],[dup,--],while]). -def(drop,[[rest],times]). -def(dupdd,[[dup],dipd]). -def(dupdipd,[dup,dipd]). -def(enstacken,[stack,[clear],dip]). -def(fourth,[rest,third]). -def(gcd,[true,[tuck,mod,dup,0,>],loop,pop]). -def(grabN,[[],swap,[cons],times]). -def(grba,[[stack,popd],dip]). -def(hypot,[[sqr],ii,+,sqrt]). -def(ifte,[[nullary],dipd,swap,branch]). -def(ii,[[dip],dupdip,i]). -def(infer,[thunk,dup,rollup,infra]). -def(infra,[swons,swaack,[i],dip,swaack]). -def(infrst,[infra,first]). -def(least_fraction,[dup,[gcd],infra,[div],concat,map]). -def(make_generator,[[codireco],ccons]). -def(neg,[0,swap,-]). -def(nullary,[[stack],dinfrirst]). -def(of,[swap,at]). -def(pam,[[i],map]). -def(pm,[[+],[-],clop]). -def(popd,[[pop],dip]). -def(popdd,[[pop],dipd]). -def(popop,[pop,pop]). -def(popopd,[[popop],dip]). -def(popopdd,[[popop],dipd]). -def(primrec,[[i],genrec]). -def(product,[1,swap,[*],step]). -def(quoted,[[unit],dip]). -def(range,[[0,<=],[1,-,dup],anamorphism]). -def(range_to_zero,[unit,[down_to_zero],infra]). -def(reverse,[[],swap,shunt]). -def(rrest,[rest,rest]). -def(run,[[],swap,infra]). -def(second,[rest,first]). -def(shunt,[[swons],step]). -def(size,[0,swap,[pop,++],step]). -def(split_at,[[drop],[take],clop]). -def(sqr,[dup,*]). -def(step_zero,[0,rollup,step]). -def(sum,[0,swap,[+],step]). -def(swoncat,[swap,concat]). -def(swons,[swap,cons]). -def(take,[[],rolldown,[shift],times,pop]). -def(ternary,[binary,popd]). -def(third,[rest,second]). -def(unary,[nullary,popd]). -def(unquoted,[[i],dip]). -def(unswons,[uncons,swap]). -def(while,[swap,[nullary],cons,dup,dipd,concat,loop]). -def(x,[dup,i]). diff --git a/thun/gnu-prolog/defs.txt b/thun/gnu-prolog/defs.txt deleted file mode 100644 index 039ecd2..0000000 --- a/thun/gnu-prolog/defs.txt +++ /dev/null @@ -1,74 +0,0 @@ --- == 1 - -? == dup bool -++ == 1 + -anamorphism == [pop []] swap [dip swons] genrec -app1 == grba infrst -app2 == [grba swap grba swap] dip [infrst] cons ii -app3 == 3 appN -appN == [grabN] cons dip map disenstacken -at == drop first -b == [i] dip i -binary == unary popd -ccons == cons cons -cleave == fork popdd -clop == cleave popdd -codireco == cons dip rest cons -dinfrirst == dip infrst -disenstacken == ? [uncons ?] loop pop -down_to_zero == [0 >] [dup --] while -drop == [rest] times -dupd == [dup] dip -dupdd == [dup] dipd -dupdipd == dup dipd -enstacken == stack [clear] dip -flatten == [] swap [concat] step -fork == [i] app2 -fourth == rest third -gcd == true [tuck mod dup 0 >] loop pop -grabN == [] swap [cons] times -grba == [stack popd] dip -hypot == [sqr] ii + sqrt -ifte == [nullary] dipd swap branch -ii == [dip] dupdip i -infer == thunk dup rollup infra -infra == swons swaack [i] dip swaack -infrst == infra first -least_fraction == dup [gcd] infra [div] concat map -make_generator == [codireco] ccons -neg == 0 swap - -nullary == [stack] dinfrirst -of == swap at -pam == [i] map -pm == [+] [-] clop -popd == [pop] dip -popdd == [pop] dipd -popop == pop pop -popopd == [popop] dip -popopdd == [popop] dipd -primrec == [i] genrec -product == 1 swap [*] step -quoted == [unit] dip -range == [0 <=] [1 - dup] anamorphism -range_to_zero == unit [down_to_zero] infra -reverse == [] swap shunt -rrest == rest rest -run == [] swap infra -second == rest first -shift == uncons [swons] dip -shunt == [swons] step -size == 0 swap [pop ++] step -split_at == [drop] [take] clop -sqr == dup * -step_zero == 0 rollup step -sum == 0 swap [+] step -swoncat == swap concat -swons == swap cons -take == [] rolldown [shift] times pop -ternary == binary popd -third == rest second -unary == nullary popd -unit == [] cons -unquoted == [i] dip -unswons == uncons swap -while == swap [nullary] cons dup dipd concat loop -x == dup i diff --git a/thun/gnu-prolog/fork.pl b/thun/gnu-prolog/fork.pl deleted file mode 100644 index e2aa8be..0000000 --- a/thun/gnu-prolog/fork.pl +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright 2019 Simon Forman - - This file is part of Thun - - Thun is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Thun is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Thun. If not see . - -A fork function that actually forks. Experimental. - -*/ -:- multifile(func/3). - -func(fork, [F, G|S], [X, Y|S]) :- - fork(F, S, R, ChildPID), % Send F off to the child, - thun(G, S, [Y|_]), % Run G locally, - read_pipe(R, X), % Collect the result from F, - % FIXME deal with X=timeout... - wait(ChildPID, Status). % FIXME check status!!! - -fork(Expr, Stack, In, ChildPID) :- - mkpipe(In, Out), - fork_prolog(ChildPID), - korf(ChildPID, In, Out, Expr, Stack). - -korf(0, In, Out, Expr, Stack) :- close(In), % In the child. - thun(Expr, Stack, [Result|_]), - w(Out, Result), close(Out), - halt. - -korf(PID, _, Out, _, _) :- % In the parent. - integer(PID), PID =\= 0, - close(Out). - -read_pipe(In, Result) :- % select/5, read the pipe or timeout. - select([In], R, [], _, 1500), - read_pipe_(R, In, Result), - close(In). - -read_pipe_([In], In, Result) :- read(In, Result). -read_pipe_( [], _, timeout). - -mkpipe(In, Out) :- - create_pipe(In, Out), - set_stream_buffering(Out, none), - set_stream_buffering(In, none). - -w(Out, Term) :- % To get a term written out and recognized, - write(Out, Term), % you write it to the stream - put_code(Out, 0'.), % add a period at the end - nl(Out), % and a newline even if you set buffering - flush_output(Out). % to none, then flush for good measure. - diff --git a/thun/gnu-prolog/junk/gthun.pl b/thun/gnu-prolog/junk/gthun.pl deleted file mode 100644 index 46ec3bb..0000000 --- a/thun/gnu-prolog/junk/gthun.pl +++ /dev/null @@ -1,120 +0,0 @@ - -:- op(990, xfy, =-). -:- dynamic((=-)/2). - -:- initialization(loop). - - -/* -Parser -*/ - -joy_parse([T|S]) --> blanks, joy_term(T), blanks, joy_parse(S). -joy_parse([]) --> []. - -joy_term(N) --> num(N), !. -joy_term(S) --> [0'[], !, joy_parse(S), [0']]. -joy_term(A) --> chars(Chars), !, {atom_codes(A, Chars)}. - - -/* -Interpreter. -*/ - -thun([], S, S). - -thun( [Lit|E], Si, So) :- literal(Lit), !, thun(E, [Lit|Si], So). -thun( [Func|E], Si, So) :- func(Func, Si, S), !, thun(E, S, So). -thun([Combo|E], Si, So) :- combo(Combo, Si, S, E, Eo), !, thun(Eo, S, So). - -thun(Err, S, [Err|S]) :- write('Unknown term!'), nl. - - -/* -Literals -*/ - -literal(V) :- var(V). -literal(I) :- number(I). -literal([]). -literal([_|_]). -literal(true). -literal(false). - - -/* -Functions -*/ - -func(cons, [A, B|S], [[B|A]|S]). -func(swap, [A, B|S], [B, A|S]). -func(dup, [A|S], [A, A|S]). -func(pop, [_|S], S ). - -func(uncons, Si, So) :- func(cons, So, Si). - -func(+, [A, B|S], [B+A|S]). -func(=, [A|S], [B|S]) :- B is A. - -func(clear, _, []). -func(stack, S, [S|S]). - - -/* -Definitions -*/ - -% This is NOT the Continuation-Passing Style -% -% func(Name, Si, So) :- Name =- Body, thun(Body, Si, So). - -func(inscribe, [Definition|S], S) :- - Definition = [Name|Body], - atom(Name), - assertz(Name =- Body). - -swons =- [swap, cons]. -x =- [dup, i]. -unit =- [[], cons]. -enstacken =- [stack, [clear], dip]. - -% This IS the Continuation-Passing Style -% -combo(Name, S, S, Ei, Eo) :- Name =- Body, append(Body, Ei, Eo). - -/* -Combinators -*/ - -combo(i, [P|S], S, Ei, Eo) :- append(P, Ei, Eo). -combo(dip, [P, X|S], S, Ei, Eo) :- append(P, [X|Ei], Eo). -combo(dipd, [P, X, Y|S], S, Ei, Eo) :- append(P, [Y, X|Ei], Eo). - -combo(branch, [T, _, true|S], S, Ei, Eo) :- append(T, Ei, Eo). -combo(branch, [_, F, false|S], S, Ei, Eo) :- append(F, Ei, Eo). - -combo(loop, [_, false|S], S, E, E ). -combo(loop, [B, true|S], S, Ei, Eo) :- append(B, [B, loop|Ei], Eo). - -combo(step, [_, []|S], S, E, E ). -combo(step, [P, [X]|S], [X|S], Ei, Eo) :- !, append(P, Ei, Eo). -combo(step, [P, [X|Z]|S], [X|S], Ei, Eo) :- append(P, [Z, P, step|Ei], Eo). - - -/* -Main Loop -*/ - -loop :- line(Line), loop(Line, [], _Out). - -loop([eof], S, S) :- !. -loop( Line, In, Out) :- - do_line(Line, In, S), - write(S), nl, - line(NextLine), !, - loop(NextLine, S, Out). - - -do_line(Line, In, Out) :- phrase(joy_parse(E), Line), thun(E, In, Out). -do_line(_Line, S, S) :- write('Err'), nl. - diff --git a/thun/gnu-prolog/junk/meta.pl b/thun/gnu-prolog/junk/meta.pl deleted file mode 100644 index 524937f..0000000 --- a/thun/gnu-prolog/junk/meta.pl +++ /dev/null @@ -1,10 +0,0 @@ - - -do(DCG) :- - fd_domain(X, 0, 9), - fd_labeling(X), - number_codes(X, [C]), - DCG = `-->`(digit(C), [C]). - - - diff --git a/thun/gnu-prolog/junk/partev.pl b/thun/gnu-prolog/junk/partev.pl deleted file mode 100644 index 995bda2..0000000 --- a/thun/gnu-prolog/junk/partev.pl +++ /dev/null @@ -1,167 +0,0 @@ -:- use_module(library(clpfd)). - -%-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -% -% Program 18.3 from "Art of Prolog" -% - -process(Program, ReducedProgram) :- - findall(PC1, (member(C1, Program), preduce(C1, PC1), portray_clause(PC1)), ReducedProgram). - -preduce( (A :- B), (Pa :- Pb) ) :- !, preduce(B, Pb), preduce(A, Pa). -preduce( true, true ) :- !. -preduce( (A, B), Residue ) :- !, preduce(A, Pa), preduce(B, Pb), combine(Pa, Pb, Residue). -preduce( A, B ) :- should_fold(A, B), !. -preduce( A, Residue ) :- should_unfold(A), !, clause(A, B), preduce(B, Residue). -preduce( A, A ). - -combine(true, B, B) :- !. -combine(A, true, A) :- !. -combine(A, B, (A, B)). - -test(Name, Program) :- program(Name, Clauses), process(Clauses, Program). - -%-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -program(tundra, [ - ( thun([], S, S) ), - ( thun( [Lit|E], Si, So) :- literal(Lit), thun(E, [Lit|Si], So) ), - ( thun( [Def|E], Si, So) :- def(Def, Body), append(Body, E, Eo), thun(Eo, Si, So) ), - ( thun( [Func|E], Si, So) :- func(Func, Si, S), thun(E, S, So) ), - ( thun([Combo|E], Si, So) :- combo(Combo, Si, S, E, Eo), thun(Eo, S, So) ) - ]). - -should_unfold(literal(Lit)). -should_unfold(def(Def, Body)). -should_unfold(func(Func, Si, So)). -should_unfold(combo(A, B, C, D, E)). -should_fold(sam, bill). - -%-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -literal(V) :- var(V). -literal(I) :- number(I). -literal([]). -literal([_|_]). -literal(true). -literal(false). - -func(cons, [A, B|S], [[B|A]|S]). -func(swap, [A, B|S], [B, A|S]). -func(dup, [A|S], [A, A|S]). -func(pop, [_|S], S ). -func(+, [A, B|S], [C|S]) :- C #= A + B. -func(-, [A, B|S], [C|S]) :- C #= B - A. -func(*, [A, B|S], [C|S]) :- C #= A * B. -func(/, [A, B|S], [C|S]) :- C #= B div A. - -func(nullary, [P|S], [X|S]) :- thun(P, S, [X|_]). % Combinator. -func(infra, [P, R|S], [Q|S]) :- thun(P, R, Q). % Combinator. - -func(concat, [A, B|S], [C|S]) :- append(B, A, C). -func(flatten, [A|S], [B|S]) :- flatten(A, B). -func(swaack, [R|S], [S|R]). -func(stack, S , [S|S]). -func(clear, _ , []). -func(first, [[X|_]|S], [X|S]). -func(rest, [[_|X]|S], [X|S]). -func(unit, [X|S], [[X]|S]). - -combo(i, [P|S], S, Ei, Eo) :- append(P, Ei, Eo). -combo(dip, [P, X|S], S, Ei, Eo) :- append(P, [X|Ei], Eo). -combo(dipd, [P, X, Y|S], S, Ei, Eo) :- append(P, [Y, X|Ei], Eo). - -def(at,[drop,first]). -def(b,[[i],dip,i]). -def(binary,[unary,popd]). - -% thun([binary|A], C, D) :- thun([unary, popd|A], C, D). - -%-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - -% ?- test(tundra, _). -% thun([], A, A). -% thun([A|B], C, D) :- var(A), thun(B, [A|C], D). -% thun([A|B], C, D) :- number(A), thun(B, [A|C], D). -% thun([[]|A], B, C) :- thun(A, [[]|B], C). -% thun([[B|C]|A], D, E) :- thun(A, [[B|C]|D], E). -% thun([true|A], B, C) :- thun(A, [true|B], C). -% thun([false|A], B, C) :- thun(A, [false|B], C). -% thun([cons|A], [C, B|D], E) :- thun(A, [[B|C]|D], E). -% thun([swap|A], [C, B|D], E) :- thun(A, [B, C|D], E). -% thun([dup|A], [B|C], D) :- thun(A, [B, B|C], D). -% thun([pop|A], [_|B], C) :- thun(A, B, C). -% thun([+|E], [A, B|F], G) :- -% ( integer(C) -% -> ( integer(A), -% integer(B) -% -> C=:=A+B -% ; D=C, -% clpfd:clpfd_equal(D, A+B) -% ) -% ; integer(A), -% integer(B) -% -> ( var(C) -% -> C is A+B -% ; D is A+B, -% clpfd:clpfd_equal(C, D) -% ) -% ; clpfd:clpfd_equal(C, A+B) -% ), -% thun(E, [C|F], G). -% thun([-|E], [B, A|F], G) :- -% ( integer(C) -% -> ( integer(A), -% integer(B) -% -> C=:=A-B -% ; D=C, -% clpfd:clpfd_equal(D, A-B) -% ) -% ; integer(A), -% integer(B) -% -> ( var(C) -% -> C is A-B -% ; D is A-B, -% clpfd:clpfd_equal(C, D) -% ) -% ; clpfd:clpfd_equal(C, A-B) -% ), -% thun(E, [C|F], G). -% thun([*|E], [A, B|F], G) :- -% ( integer(C) -% -> ( integer(A), -% integer(B) -% -> C=:=A*B -% ; D=C, -% clpfd:clpfd_equal(D, A*B) -% ) -% ; integer(A), -% integer(B) -% -> ( var(C) -% -> C is A*B -% ; D is A*B, -% clpfd:clpfd_equal(C, D) -% ) -% ; clpfd:clpfd_equal(C, A*B) -% ), -% thun(E, [C|F], G). -% thun([/|C], [B, A|E], F) :- D#=A div B, thun(C, [D|E], F). -% thun([nullary|C], [A|B], E) :- thun(A, B, [D|_]), thun(C, [D|B], E). -% thun([infra|C], [A, B|E], F) :- thun(A, B, D), thun(C, [D|E], F). -% thun([concat|C], [B, A|E], F) :- append(A, B, D), thun(C, [D|E], F). -% thun([flatten|B], [A|D], E) :- flatten(A, C), thun(B, [C|D], E). -% thun([swaack|A], [C|B], D) :- thun(A, [B|C], D). -% thun([stack|A], B, C) :- thun(A, [B|B], C). -% thun([clear|A], _, B) :- thun(A, [], B). -% thun([first|A], [[B|_]|C], D) :- thun(A, [B|C], D). -% thun([rest|A], [[_|B]|C], D) :- thun(A, [B|C], D). -% thun([unit|A], [B|C], D) :- thun(A, [[B]|C], D). -% thun([i|B], [A|D], E) :- append(A, B, C), thun(C, D, E). -% thun([dip|C], [A, B|E], F) :- append(A, [B|C], D), thun(D, E, F). -% thun([dipd|D], [A, C, B|F], G) :- append(A, [B, C|D], E), thun(E, F, G). -% true. - - - - - diff --git a/thun/gnu-prolog/junk/swi-thun.pl b/thun/gnu-prolog/junk/swi-thun.pl deleted file mode 100644 index e2dd117..0000000 --- a/thun/gnu-prolog/junk/swi-thun.pl +++ /dev/null @@ -1,350 +0,0 @@ -:- dynamic(func/3). -:- discontiguous(func/3). - -/* - Copyright © 2018, 2019 Simon Forman - - This file is part of Thun - - Thun is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Thun is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Thun. If not see . - -*/ -:- dynamic(def/2). - - -/* - -To handle comparision operators the possibility of exceptions due to -insufficiently instantiated arguments must be handled. First try to make -the comparison and set the result to a Boolean atom. If an exception -happens just leave the comparison expression as the result and some other -function or combinator will deal with it. Example: - - func(>, [A, B|S], [C|S]) :- catch( - (B > A -> C=true ; C=false), - _, - C=(B>A) % in case of error. - ). - -To save on conceptual overhead I've defined a term_expansion/2 that sets -up the func/3 for each op. -*/ - -term_expansion(comparison_operator(X), (func(X, [A, B|S], [C|S]) :- - F =.. [X, B, A], catch((F -> C=true ; C=false), _, C=F))). - -% I don't use Prolog-compatible op symbols in all cases. -term_expansion(comparison_operator(X, Y), (func(X, [A, B|S], [C|S]) :- - F =.. [Y, B, A], catch((F -> C=true ; C=false), _, C=F))). - -% Likewise for math operators, try to evaluate, otherwise use the -% symbolic form. - -term_expansion(math_operator(X), (func(X, [A, B|S], [C|S]) :- - F =.. [X, B, A], catch(C is F, _, C=F))). - -term_expansion(math_operator(X, Y), (func(X, [A, B|S], [C|S]) :- - F =.. [Y, B, A], catch(C is F, _, C=F))). - - -/* -An entry point. -*/ - -joy(InputString, StackIn, StackOut) :- - phrase(joy_parse(Expression), InputString), !, - thun(Expression, StackIn, StackOut). - -/* -Parser - - joy :== number | '[' joy* ']' | atom - -*/ - -joy_parse([T|J]) --> blanks, joy_term(T), blanks, joy_parse(J). -joy_parse([]) --> []. - -joy_term(N) --> number(N), !. -joy_term(J) --> "[", !, joy_parse(J), "]". -joy_term(C) --> symbol(C). - -symbol(C) --> chars(Chars), !, {Chars \= [61, 61], atom_string(C, Chars)}. - -chars([Ch|Rest]) --> char(Ch), chars(Rest). -chars([Ch]) --> char(Ch). - -char(Ch) --> [Ch], {Ch \== 91, Ch \== 93, code_type(Ch, graph)}. - - -/* -Interpreter -thun(Expression, InputStack, OutputStack) -*/ - -thun([], S, S). -thun( [Lit|E], Si, So) :- literal(Lit), !, thun(E, [Lit|Si], So). -thun( [Def|E], Si, So) :- def(Def, Body), !, append(Body, E, Eo), thun(Eo, Si, So). -thun( [Func|E], Si, So) :- func(Func, Si, S), thun(E, S, So). -thun([Combo|E], Si, So) :- combo(Combo, Si, S, E, Eo), thun(Eo, S, So). - -% Some error handling. - -thun([Unknown|E], Si, So) :- - damned_thing(Unknown), - write("wtf? "), - writeln(Unknown), - So = [[Unknown|E]|Si]. - -damned_thing(It) :- - \+ literal(It), - \+ def(It, _), - \+ func(It, _, _), - \+ combo(It, _, _, _, _). - - -/* -Literals -*/ - -literal(V) :- var(V). -literal(I) :- number(I). -literal([]). -literal([_|_]). -literal(true). -literal(false). - -% Symbolic math expressions are literals. -literal(_+_). -literal(_-_). -literal(_*_). -literal(_/_). -literal(_ mod _). - -% Symbolic comparisons are literals. -literal(_>_). -literal(_<_). -literal(_>=_). -literal(_=<_). -literal(_=:=_). -literal(_=\=_). - - -/* -Functions -*/ - -func(cons, [A, B|S], [[B|A]|S]). -func(swap, [A, B|S], [B, A|S]). -func(dup, [A|S], [A, A|S]). -func(pop, [_|S], S ). - -% Symbolic math. Compute the answer, or derivative, or whatever, later. -math_operator(+). -math_operator(-). -math_operator(*). -math_operator(/). -math_operator(mod). - -% Attempt to calculate the value of a symbolic math expression. -func(calc, [A|S], [B|S]) :- B is A. - -func(sqrt, [A|S], [sqrt(A)|S]). - -func(concat, [A, B|S], [C|S]) :- append(B, A, C). -func(flatten, [A|S], [B|S]) :- flatten(A, B). -func(swaack, [R|S], [S|R]). -func(stack, S , [S|S]). -func(clear, _ , []). -func(first, [[X|_]|S], [X|S]). -func(rest, [[_|X]|S], [X|S]). -func(unit, [X|S], [[X]|S]). - -func(rolldown, [A, B, C|S], [B, C, A|S]). -func(dupd, [A, B|S], [A, B, B|S]). -func(over, [A, B|S], [B, A, B|S]). -func(tuck, [A, B|S], [A, B, A|S]). - -func(shift, [[B|A], C|D], [A, [B|C]|D]). - -func(rollup, Si, So) :- func(rolldown, So, Si). -func(uncons, Si, So) :- func(cons, So, Si). - -func(bool, [ 0|S], [false|S]) :- !. -func(bool, [ 0.0|S], [false|S]) :- !. -func(bool, [ []|S], [false|S]) :- !. -func(bool, [ ""|S], [false|S]) :- !. -func(bool, [false|S], [false|S]) :- !. - -func(bool, [_|S], [true|S]). - -comparison_operator(>). -comparison_operator(<). -comparison_operator(>=). -comparison_operator(<=, =<). -comparison_operator(=, =:=). -comparison_operator(<>, =\=). - - -/* -Definitions -*/ - -joy_def(def(Def, Body)) --> symbol(Def), blanks, "==", joy_parse(Body). - -joy_defs --> blanks, joy_def(Def), {assert_def(Def)}, blanks, joy_defs. -joy_defs --> []. - -assert_defs(DefsFile) :- - read_file_to_codes(DefsFile, Codes, []), - phrase(joy_defs, Codes). - -assert_def(def(Def, Body)) :- - retractall(def(Def, _)), - assertz(def(Def, Body)). - -:- assert_defs("defs.txt"). - - -/* -Combinators -*/ - -combo(i, [P|S], S, Ei, Eo) :- append(P, Ei, Eo). -combo(dip, [P, X|S], S, Ei, Eo) :- append(P, [X|Ei], Eo). -combo(dipd, [P, X, Y|S], S, Ei, Eo) :- append(P, [Y, X|Ei], Eo). - -combo(dupdip, [P, X|S], [X|S], Ei, Eo) :- append(P, [X|Ei], Eo). - -combo(branch, [T, _, true|S], S, Ei, Eo) :- append(T, Ei, Eo). -combo(branch, [_, F, false|S], S, Ei, Eo) :- append(F, Ei, Eo). -combo(branch, [T, F, Expr|S], S, Ei, Eo) :- - \+ Expr = true, \+ Expr = false, - catch( % Try Expr and do one or the other, - (Expr -> append(T, Ei, Eo) ; append(F, Ei, Eo)), - _, % If Expr don't grok, try both branches. - (append(T, Ei, Eo) ; append(F, Ei, Eo)) - ). - -combo(loop, [_, false|S], S, E, E ). -combo(loop, [B, true|S], S, Ei, Eo) :- append(B, [B, loop|Ei], Eo). -combo(loop, [B, Expr|S], S, Ei, Eo) :- - \+ Expr = true, \+ Expr = false, - catch( % Try Expr and do one or the other, - (Expr -> append(B, [B, loop|Ei], Eo) ; Ei=Eo), - _, % If Expr don't grok, try both branches. - (Ei=Eo ; append(B, [B, loop|Ei], Eo)) - ). - -combo(step, [_, []|S], S, E, E ). -combo(step, [P, [X]|S], [X|S], Ei, Eo) :- !, append(P, Ei, Eo). -combo(step, [P, [X|Z]|S], [X|S], Ei, Eo) :- append(P, [Z, P, step|Ei], Eo). - -combo(times, [_, 0|S], S, E, E ). -combo(times, [P, 1|S], S, Ei, Eo) :- append(P, Ei, Eo). -combo(times, [P, N|S], S, Ei, Eo) :- N #>= 2, M #= N - 1, append(P, [M, P, times|Ei], Eo). -combo(times, [_, N|S], S, _, _ ) :- N #< 0, fail. - -combo(genrec, [R1, R0, Then, If|S], - [ Else, Then, If|S], E, [ifte|E]) :- - Quoted = [If, Then, R0, R1, genrec], - append(R0, [Quoted|R1], Else). - -/* -This is a crude but servicable implementation of the map combinator. - -Obviously it would be nice to take advantage of the implied parallelism. -Instead the quoted program, stack, and terms in the input list are -transformed to simple Joy expressions that run the quoted program on -prepared copies of the stack that each have one of the input terms on -top. These expressions are collected in a list and the whole thing is -evaluated (with infra) on an empty list, which becomes the output list. - -The chief advantage of doing it this way (as opposed to using Prolog's -map) is that the whole state remains in the pending expression, so -there's nothing stashed in Prolog's call stack. This preserves the nice -property that you can interrupt the Joy evaluation and save or transmit -the stack+expression knowing that you have all the state. -*/ - -combo(map, [_, []|S], [[]|S], E, E ) :- !. -combo(map, [P, List|S], [Mapped, []|S], E, [infra|E]) :- - prepare_mapping(P, S, List, Mapped). - -% Set up a program for each term in ListIn -% -% [term S] [P] infrst -% -% prepare_mapping(P, S, ListIn, ListOut). - -prepare_mapping(P, S, In, Out) :- prepare_mapping(P, S, In, [], Out). - -prepare_mapping( _, _, [], Out, Out) :- !. -prepare_mapping( P, S, [T|In], Acc, Out) :- - prepare_mapping(P, S, In, [[T|S], P, infrst|Acc], Out). - - -/* -Compiler -*/ - -joy_compile(Name, Expression) :- jcmpl(Name, Expression, Rule), asserta(Rule). - -show_joy_compile(Name, Expression) :- jcmpl(Name, Expression, Rule), portray_clause(Rule). - -jcmpl(Name, Expression, Rule) :- - call_residue_vars(thun(Expression, Si, So), Term), - copy_term(Term, Term, Gs), - Head =.. [func, Name, Si, So], - rule(Head, Gs, Rule). - -rule(Head, [], Head ). -rule(Head, [A|B], Head :- maplist(call, [A|B])). - -sjc(Name, InputString) :- phrase(joy_parse(E), InputString), show_joy_compile(Name, E). - - -% Simple DCGs to expand/contract definitions. - -expando, Body --> [Def], {def(Def, Body)}. -contracto, [Def] --> {def(Def, Body)}, Body. - -% Apply expando/contracto more than once, and descend into sub-lists. -% The K term is one of expando or contracto, and the J term is used -% on sub-lists, i.e. expando/grow and contracto/shrink. -% BTW, "rebo" is a meaningless name, don't break your brain -% trying to figure it out. - -rebo(K, J) --> K , rebo(K, J). -rebo(K, J), [E] --> [[H|T]], !, {call(J, [H|T], E)}, rebo(K, J). -rebo(K, J), [A] --> [ A ], !, rebo(K, J). -rebo(_, _) --> []. - -to_fixed_point(DCG, Ei, Eo) :- - phrase(DCG, Ei, E), % Apply DCG... - (Ei=E -> Eo=E ; to_fixed_point(DCG, E, Eo)). % ...until a fixed-point is reached. - -grow --> to_fixed_point(rebo(expando, grow )). -shrink --> to_fixed_point(rebo(contracto, shrink)). - - -% format_n(N) --> {number(N), !, number_codes(N, Codes)}, Codes. -% format_n(N) --> signed_digits(Codes), !, {number_codes(N, Codes)}. - -% signed_digits([45|Codes]) --> [45], !, digits(Codes). -% signed_digits( Codes ) --> digits(Codes). - -% digits([Ch|Chars]) --> [Ch], {code_type(Ch, digit)}, digits(Chars). -% digits([]), [Ch] --> [Ch], {code_type(Ch, space) ; Ch=0'] }. -% digits([], [], _). % Match if followed by space, ], or nothing. diff --git a/thun/gnu-prolog/main.pl b/thun/gnu-prolog/main.pl deleted file mode 100644 index ee7fc89..0000000 --- a/thun/gnu-prolog/main.pl +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright 2019 Simon Forman - - This file is part of Thun - - Thun is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Thun is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Thun. If not see . - -Main Loop - -*/ - -% :- debug. -% :- spy(thun). - -:- initialization(loop). - -loop :- prompt(Line), loop(Line, [], _Out). - -loop([eof], S, S) :- !. -loop( Line, In, Out) :- - do_line(Line, In, S), - show_stack(S), - prompt(NextLine), !, - loop(NextLine, S, Out). - -do_line(Line, In, Out) :- phrase(joy_parse(E), Line), thun(E, In, Out). -do_line(_Line, S, S) :- write('Err'), nl. - -prompt(Line) :- write(`joy? `), get_line(Line). -show_stack(S) :- nl, print_stack(S), write(` <-top`), nl, nl. - - -% Line is the next newget_line-delimited line from standard input stream as -% a list of character codes. - -get_line(Line) :- get_code(X), line(X, Line). - -line(10, []) :- !. % break on new-lines. -line(-1, [eof]) :- !. % break on EOF -line(X, [X|Line]) :- get_code(Y), !, line(Y, Line). - diff --git a/thun/gnu-prolog/math.pl b/thun/gnu-prolog/math.pl deleted file mode 100644 index 8e4727f..0000000 --- a/thun/gnu-prolog/math.pl +++ /dev/null @@ -1,46 +0,0 @@ -:- multifile(func/3). - -func(+, [A, B|C], [D|C]) :- - E =.. [+, B, A], - catch(D is E, _, D = E). - -func(-, [A, B|C], [D|C]) :- - E =.. [-, B, A], - catch(D is E, _, D = E). - -func(*, [A, B|C], [D|C]) :- - E =.. [*, B, A], - catch(D is E, _, D = E). - -func(/, [A, B|C], [D|C]) :- - E =.. [/, B, A], - catch(D is E, _, D = E). - -func(mod, [A, B|C], [D|C]) :- - E =.. [mod, B, A], - catch(D is E, _, D = E). - -func(>, [A, B|C], [D|C]) :- - E =.. [>, B, A], - catch((E -> D = true ; D = false), _, D = E). - -func(<, [A, B|C], [D|C]) :- - E =.. [<, B, A], - catch((E -> D = true ; D = false), _, D = E). - -func(>=, [A, B|C], [D|C]) :- - E =.. [>=, B, A], - catch((E -> D = true ; D = false), _, D = E). - -func(<=, [A, B|C], [D|C]) :- - E =.. [=<, B, A], - catch((E -> D = true ; D = false), _, D = E). - -func(=, [A, B|C], [D|C]) :- - E =.. [=:=, B, A], - catch((E -> D = true ; D = false), _, D = E). - -func(<>, [A, B|C], [D|C]) :- - E =.. [=\=, B, A], - catch((E -> D = true ; D = false), _, D = E). - diff --git a/thun/gnu-prolog/meta-defs.pl b/thun/gnu-prolog/meta-defs.pl deleted file mode 100644 index 35326ec..0000000 --- a/thun/gnu-prolog/meta-defs.pl +++ /dev/null @@ -1,68 +0,0 @@ -/* - Copyright 2019 Simon Forman - - This file is part of Thun - - Thun is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Thun is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Thun. If not see . - -Definitions -*/ - -do :- assert_defs(`defs.txt`), print_defs, halt. - -joy_def(def(Def, Body)) --> symbol(Def), blanks, "==", joy_parse(Body). - -joy_def --> joy_def(Def), {ignore(assert_def(Def))}. - -joy_defs --> blanks, joy_def, blanks, joy_defs. -joy_defs --> []. - - -assert_defs(DefsFile) :- - read_file_to_codes(DefsFile, Codes, []), - phrase(joy_defs, Codes). - -assert_def(def(Def, Body)) :- - \+ func(Def, _, _), - \+ combo(Def, _, _, _, _), - retractall(def(Def, _)), - assertz(def(Def, Body)). - - -read_file_to_codes(File, Codes, _) :- - open(File, read, Stream), - stream_to_codes(Stream, Codes), - close(Stream). - - -stream_to_codes(Stream, Codes) :- - get_code(Stream, Code), - stream_to_codes(Code, Stream, Codes). - -stream_to_codes(-1, _, []) :- !. -stream_to_codes(Ch, Stream, [Ch|Codes]) :- stream_to_codes(Stream, Codes). - - -print_defs :- - findall(def(Name, Body), def(Name, Body), List), - open(`defs.pl`, write, Stream), - maplist(print_def(Stream), List), - close(Stream). - -print_def(Stream, Def) :- write(Stream, Def), write(Stream, `.`), nl(Stream). - - -ignore(Goal) :- Goal, !. -ignore(_). - diff --git a/thun/gnu-prolog/meta-math.pl b/thun/gnu-prolog/meta-math.pl deleted file mode 100644 index f48b7c4..0000000 --- a/thun/gnu-prolog/meta-math.pl +++ /dev/null @@ -1,89 +0,0 @@ -/* - Copyright 2019 Simon Forman - - This file is part of Thun - - Thun is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Thun is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Thun. If not see . - - -To handle comparision operators the possibility of exceptions due to -insufficiently instantiated arguments must be handled. First try to make -the comparison and set the result to a Boolean atom. If an exception -happens just leave the comparison expression as the result and some other -function or combinator will deal with it. Example: - - func(>, [A, B|S], [C|S]) :- catch( - (B > A -> C=true ; C=false), - _, - C=(B>A) % in case of error. - ). - -To save on conceptual overhead I've defined a term_expansion/2 that sets -up the func/3 for each op. -*/ - -term_expansion(comparison_operator(X), (func(X, [A, B|S], [C|S]) :- - F =.. [X, B, A], catch((F -> C=true ; C=false), _, C=F))). - -% I don't use Prolog-compatible op symbols in all cases. -term_expansion(comparison_operator(X, Y), (func(X, [A, B|S], [C|S]) :- - F =.. [Y, B, A], catch((F -> C=true ; C=false), _, C=F))). - -% Likewise for math operators, try to evaluate, otherwise use the -% symbolic form. - -term_expansion(math_operator(X), (func(X, [A, B|S], [C|S]) :- - F =.. [X, B, A], catch(C is F, _, C=F))). - -term_expansion(math_operator(X, Y), (func(X, [A, B|S], [C|S]) :- - F =.. [Y, B, A], catch(C is F, _, C=F))). - - -% Symbolic math. Compute the answer, or derivative, or whatever, later. -math_operator(+). -math_operator(-). -math_operator(*). -math_operator(/). -math_operator(mod). - - -comparison_operator(>). -comparison_operator(<). -comparison_operator(>=). -comparison_operator(<=, =<). -comparison_operator(=, =:=). -comparison_operator(<>, =\=). - - -expand_op(Op, Term) :- Op, expand_term(Op, Term). - -print_o(Stream, Op) :- - findall(Term, expand_op(Op, Term), List), - maplist(writeln(Stream), List). - -writeln(Stream, Thing) :- - portray_clause(Stream, Thing), - nl(Stream). - -do :- - open(`math.pl`, write, Stream), - write(Stream, `:- multifile(func/3).`), - nl(Stream), nl(Stream), - print_o(Stream, math_operator(Op)), - print_o(Stream, comparison_operator(Op)), - print_o(Stream, comparison_operator(Op, Po)), - close(Stream), - halt. - - diff --git a/thun/gnu-prolog/parser.pl b/thun/gnu-prolog/parser.pl deleted file mode 100644 index f24577b..0000000 --- a/thun/gnu-prolog/parser.pl +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright 2019 Simon Forman - - This file is part of Thun - - Thun is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Thun is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Thun. If not see . - - -Parser - -*/ - - -:- set_prolog_flag(double_quotes, codes). - - -joy_parse([T|J]) --> blanks, joy_term(T), blanks, joy_parse(J). -joy_parse([]) --> []. - -joy_term(N) --> num(N), !. -joy_term(J) --> "[", !, joy_parse(J), "]". -joy_term(C) --> symbol(C). - - -symbol(C) --> chars(Chars), !, { Chars \= "==", atom_codes(C, Chars) }. -num(N) --> number_digits(Codes), { number_codes(N, Codes) }. - -number_digits(Codes) --> signed_float_or_integer(Codes), !, end_num. - -% At the end of a number look ahead one character for a space -% or '[' character, or the end of the code list. -end_num, [Ch] --> [Ch], { [Ch] = "[" ; is_space(Ch) }. -end_num([], []). - - -/* - -Print state. - -*/ - -format_state(Stack, Expression, Codes) :- - reverse(Stack, RStack), - phrase(format_joy(RStack), RStackCodes), - phrase(format_joy(Expression), ExpressionCodes), - append(RStackCodes, [32, 46, 32|ExpressionCodes], Codes). - -frump(Stack, Expression) :- - format_state(Stack, Expression, Codes), - maplist(put_code, Codes), nl. - -print_stack(Stack) :- - reverse(Stack, RStack), - phrase(format_joy(RStack), Codes), - maplist(put_code, Codes). - -% Print Joy expressions as text. - -format_joy(Tail) --> {var(Tail)}, !, [46, 46, 46]. -format_joy([T]) --> format_term(T), !. -format_joy([T|S]) --> format_term(T), " ", format_joy(S). -format_joy([]) --> []. - -format_term(N) --> {number(N), number_codes(N, Codes)}, Codes. -format_term(A) --> { atom(A), atom_codes(A, Codes)}, Codes. -format_term(V) --> { var(V), write_to_codes(Codes, V)}, Codes. -format_term([A|As]) --> "[", format_joy([A|As]), "]". -format_term(F) --> { write_to_codes(Codes, F)}, Codes. - diff --git a/thun/gnu-prolog/thun.pl b/thun/gnu-prolog/thun.pl deleted file mode 100644 index 850e1db..0000000 --- a/thun/gnu-prolog/thun.pl +++ /dev/null @@ -1,198 +0,0 @@ -/* - Copyright 2018, 2019 Simon Forman - - This file is part of Thun - - Thun is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Thun is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Thun. If not see . - -*/ -% :- dynamic(func/3). -% :- discontiguous(func/3). -:- multifile(func/3). - -/* -Interpreter -thun(Expression, InputStack, OutputStack) -*/ - -thun([], S, S). -thun( [Lit|E], Si, So) :- literal(Lit), !, thun(E, [Lit|Si], So). -thun( [Def|E], Si, So) :- def(Def, Body), !, append(Body, E, Eo), thun(Eo, Si, So). -thun( [Func|E], Si, So) :- func(Func, Si, S), thun(E, S, So). -thun([Combo|E], Si, So) :- combo(Combo, Si, S, E, Eo), thun(Eo, S, So). - -% Some error handling. - -thun([Unknown|E], Si, So) :- - damned_thing(Unknown), - write(`huh? `), - write(Unknown), nl, - So = [[Unknown|E]|Si]. - -damned_thing(It) :- - \+ literal(It), - \+ def(It, _), - \+ func(It, _, _), - \+ combo(It, _, _, _, _). - - -/* -Literals -*/ - -literal(V) :- var(V). -literal(I) :- number(I). -literal([]). -literal([_|_]). -literal(true). -literal(false). - -% Symbolic math expressions are literals. -literal(_+_). -literal(_-_). -literal(_*_). -literal(_/_). -literal(_ mod _). - -% Symbolic comparisons are literals. -literal(_>_). -literal(_<_). -literal(_>=_). -literal(_=<_). -literal(_=:=_). -literal(_=\=_). - - -/* -Functions -*/ - -func(cons, [A, B|S], [[B|A]|S]). -func(swap, [A, B|S], [B, A|S]). -func(dup, [A|S], [A, A|S]). -func(pop, [_|S], S ). -func(concat, [A, B|S], [C|S]) :- append(B, A, C). -func(flatten, [A|S], [B|S]) :- flatten(A, B). -func(swaack, [R|S], [S|R]). -func(stack, S , [S|S]). -func(unstack, [S|_], S ). -func(clear, _ , []). -func(first, [[X|_]|S], [X|S]). -func(rest, [[_|X]|S], [X|S]). -func(unit, [X|S], [[X]|S]). -func(thunk, S , [X|S]). - -func(rolldown, [A, B, C|S], [B, C, A|S]). -func(swapd, [A, B, C|S], [A, C, B|S]). -func(dupd, [A, B|S], [A, B, B|S]). -func(over, [A, B|S], [B, A, B|S]). -func(tuck, [A, B|S], [A, B, A|S]). - -func(shift, [[B|A], C|D], [A, [B|C]|D]). - -func(rollup, Si, So) :- func(rolldown, So, Si). -func(uncons, Si, So) :- func(cons, So, Si). - -func(bool, [ 0|S], [false|S]) :- !. -func(bool, [ 0.0|S], [false|S]) :- !. -func(bool, [ []|S], [false|S]) :- !. -func(bool, [ ""|S], [false|S]) :- !. -func(bool, [false|S], [false|S]) :- !. - -func(bool, [_|S], [true|S]). - -func(sqrt, [A|S], [B|S]) :- B is sqrt(A). - -func(small, [[_]|S], [ true|S]). -func(small, [ []|S], [ true|S]). -func(small, [ X|S], [false|S]) :- X \= [_], X \= []. - - -/* -Combinators -*/ - -combo(i, [P|S], S, Ei, Eo) :- append(P, Ei, Eo). -combo(dip, [P, X|S], S, Ei, Eo) :- append(P, [X|Ei], Eo). -combo(dipd, [P, X, Y|S], S, Ei, Eo) :- append(P, [Y, X|Ei], Eo). - -combo(dupdip, [P, X|S], [X|S], Ei, Eo) :- append(P, [X|Ei], Eo). - -combo(branch, [T, _, true|S], S, Ei, Eo) :- append(T, Ei, Eo). -combo(branch, [_, F, false|S], S, Ei, Eo) :- append(F, Ei, Eo). -combo(branch, [T, F, Expr|S], S, Ei, Eo) :- - \+ Expr = true, \+ Expr = false, - catch( % Try Expr and do one or the other, - (Expr -> append(T, Ei, Eo) ; append(F, Ei, Eo)), - _, % If Expr don't grok, try both branches. - (append(T, Ei, Eo) ; append(F, Ei, Eo)) - ). - -combo(loop, [_, false|S], S, E, E ). -combo(loop, [B, true|S], S, Ei, Eo) :- append(B, [B, loop|Ei], Eo). -combo(loop, [B, Expr|S], S, Ei, Eo) :- - \+ Expr = true, \+ Expr = false, - catch( % Try Expr and do one or the other, - (Expr -> append(B, [B, loop|Ei], Eo) ; Ei=Eo), - _, % If Expr don't grok, try both branches. - (Ei=Eo ; append(B, [B, loop|Ei], Eo)) - ). - -combo(step, [_, []|S], S, E, E ). -combo(step, [P, [X]|S], [X|S], Ei, Eo) :- !, append(P, Ei, Eo). -combo(step, [P, [X|Z]|S], [X|S], Ei, Eo) :- append(P, [Z, P, step|Ei], Eo). - -combo(times, [_, 0|S], S, E, E ). -combo(times, [P, 1|S], S, Ei, Eo) :- append(P, Ei, Eo). -combo(times, [P, N|S], S, Ei, Eo) :- N #>= 2, M #= N - 1, append(P, [M, P, times|Ei], Eo). -combo(times, [_, N|S], S, _, _ ) :- N #< 0, fail. - -combo(genrec, [R1, R0, Then, If|S], - [ Else, Then, If|S], E, [ifte|E]) :- - Quoted = [If, Then, R0, R1, genrec], - append(R0, [Quoted|R1], Else). - -/* -This is a crude but servicable implementation of the map combinator. - -Obviously it would be nice to take advantage of the implied parallelism. -Instead the quoted program, stack, and terms in the input list are -transformed to simple Joy expressions that run the quoted program on -prepared copies of the stack that each have one of the input terms on -top. These expressions are collected in a list and the whole thing is -evaluated (with infra) on an empty list, which becomes the output list. - -The chief advantage of doing it this way (as opposed to using Prolog's -map) is that the whole state remains in the pending expression, so -there's nothing stashed in Prolog's call stack. This preserves the nice -property that you can interrupt the Joy evaluation and save or transmit -the stack+expression knowing that you have all the state. -*/ - -combo(map, [_, []|S], [[]|S], E, E ) :- !. -combo(map, [P, List|S], [Mapped, []|S], E, [infra|E]) :- - prepare_mapping(P, S, List, Mapped). - -% Set up a program for each term in ListIn -% -% [term S] [P] infrst -% -% prepare_mapping(P, S, ListIn, ListOut). - -prepare_mapping(P, S, In, Out) :- prepare_mapping(P, S, In, [], Out). - -prepare_mapping( _, _, [], Out, Out) :- !. -prepare_mapping( P, S, [T|In], Acc, Out) :- - prepare_mapping(P, S, In, [[T|S], P, infrst|Acc], Out). - diff --git a/thun/joy_asm.bin b/thun/joy_asm.bin deleted file mode 100644 index e8bce11..0000000 Binary files a/thun/joy_asm.bin and /dev/null differ diff --git a/thun/joy_asmii.bin b/thun/joy_asmii.bin deleted file mode 100644 index 195459b..0000000 Binary files a/thun/joy_asmii.bin and /dev/null differ diff --git a/thun/markII.rst b/thun/markII.rst deleted file mode 100644 index 487cd0d..0000000 --- a/thun/markII.rst +++ /dev/null @@ -1,972 +0,0 @@ - - -Mark II -========================= - - - -This (and the previous incarnation) is really more of a "macro assembler" -than a compiler, and nothing like what I want it to be. It should be -tracking the "types" of registers in some enviroment that gets carried -along and picking primitives and making optimizations based on that -information. - - -TO replace the crude first draft I want to expand the representation of -data types. - -At first I thought I might use the COLA object model but when I reviewed -it I realized that it was way too flexible for what I needed, so I"m -going to use a simple tagged record kind of a thing. There are three -"types": symbols, lists (cons lists, pairs), and integers. In order to -deal with large numbers and do double duty as strings, I'm going to let -them be made up of more than one word of memory. - -Preliminary design: A record is one or more 32-bit words, the two most -signifigant bits are a type tag: - - 00 - Pair of pointers to other records, 30 bits left so 15 each? - 10 - Symbol, the remaining 30 bits are the address of the func. - 01 - Integer, the next, hmm, 6? bits are the length in words. - 11 - escape hatch to COLA maybe? - -Deets: For pairs, the empty list is still 0 and by leaving 0 in RAM[0] -it's "safe" to deref it. Each half of the rest of the word (15 bits) is -an offset (not a direct pointer) from the pair to the member record. - -For symbols, the rest of the word is the direct pointer to the machine -code of the function denoted by the symbol. I might add some additional -data to the head of the record because the CPU doesn't have 30 address -lines. I'm assuming that the (as yet unwritten) parser will take care of -looking up the symbols at parse time, but it would also be possible to -point to a integer that represents the string name of the function and do -lookup during evaluation, or during some intermediate stage. - -For ints, I'm putting a little length field in the record, 0 length means -the integer's bits all fit in the rest of the record word. If the length -is 1 the integer is in the following word (but what if the rest of the -record word was a pointer to the data word? Could save space for popular -integers, eh?) If the length is greater than 1 the rest of the bytes in -the record word are included in the intger(?) - - 01000000|byte|byte|byte <- three bytes of integer. - - 01000001|0000|0000|0000 <- (Pointer to data maybe?) - byte|byte|byte|byte <- four bytes of integer. - -Or how about... - - 010nnnnn|byte|byte|byte <- 29 bits of immediate integer - 011nnnnn|byte|byte|byte <- length and offset packed in 29 bits? - pointing to a stretch of words in RAM - -If the offset is limited to 16 bits that leaves 13 bits for the length. -8K 32-bit words is 262144 bits, and 2^262144 is a pretty big number. - -It doesn't matter yet because I'm not about to implement math yet. - -So let's see how bad it is to rewrite the compiler to make it implement -this new stuff. - -main loop -------------------------------------- - - -if_zero(EXPR, HALT) - -No change to the iplementation is needed. - -deref(EXPR) loads the record at the address in expr register into that -register, but now we are going to need to remember that address to add -it to the offset in the record to find the records of the head and tail -records. - -Change it to deref(EXPR, TEMP0) and keep the address around in TEMP0. - -split_word(TERM, EXPR) puts the record pointed to by head of the expr -record into term register and leave the address of the tail record in -expr. THe address of the tail record is just the last 15 bits plus the -address in TEMP0. - -The address of the head record is bits [30:15] of the record plus the -address in TEMP0. - -SO, load the head record address bits into ToAddr and then add FromAddr - - ior_imm(ToAddr, From, -15), % roll right 15 bits - % No need to mask off high bits as the type tag for pairs is 00 - add(ToAddr, ToAddr, FromAddr), - - load_word(To, ToAddr, 0), % Bring the record in from RAM. - - and_imm(From, From, 0x7fff), % Mask off lower 15 bits. - add(From, From, FromAddr), % Add the address to the offset. - - -If a record can only be created after its parts and the parts are being -allocated in strictly ascending (or descending) order of addresses then -the offsets will always be negative (or positive). SInce it's easier to -deal with positive offsets and it's just as easy to allocate up as down, -I'm going to do that. - - -Next, we must check if the term is a literal (not a symbol) - -That involves rolling the value to get the top two bits and then checking -whether they are 10 or not. - -lookup(DICT_PTR, DICT_TOP, TERM, HALT) - -It turns out that you don;t need anything but the record since it's -already been looked up. The symbol contains the jump address. - - - -Next, push - -push(TOS, TERM, SP) - -There's a note saying - - set(sp, 2), % Reg 2 points to just under top of stack. - -But I've forgotten if that's exactly true. I want to just point to TOS -pair record in SP. If that's the case, then the PUSH operation is: - -Since the record we are constructing is going to have the rest of the -stack as its tail and it's going to be written to the next word in RAM -after (before) the SP (the address of the stack/tail) the offset is +4. - -The address of the term is in a register, the address of the pair record -that we are contrsucting will be SP - 4, to get the offset we have to -subtract that from the term's address. Since we need it anyway, and -we're going to do it sooner or later, let's subtract 4 from the SP right -off: - - sp = sp - 4 - -Then we can use it to calculate the offset and put it in tos: - - tos = &temp - sp - tos = tos << 15 - -If I was as slick as I like to pretend I would insert a check here that -the two high bits are indeed 00. ... - -With the offset of the term in the tos register already we just have to -OR 4: - - tos = tos | 4 - -And write it to the (already decremented) sp. - - ram[sp] = tos - - -cons ------------------------------- - - [グ,ケ,ゲ,ド,ゴ,サ],ヮ(cons), - - グ pop(TEMP0, TOS) split_word(TEMP0, TOS), high_half_to(To, From), swap_halves(To, From), ror_imm(To, From, 16) - low_half(To) and_imm(Reg, Reg, 0xffff) - low_half(From) and_imm(Reg, Reg, 0xffff) - - Puts the term on tos (the list to cons onto) into temp0 and points tos - deref(TOS) to the value under tos (the item to cons onto the list.) - - ケ high_half(TEMP1, TOS) mov_imm_with_shift(0, 0xffff), Mask off the high half of (new) tos to isolate value. - and(TEMP1, TOS, 0) - ゲ or_inplace(TEMP0, TEMP1) ior(TEMP0, TEMP0, TEMP1) Combines value with the list in a new pair record. - ド write_cell(TEMP0, SP) add_imm(SP, SP, 4), Writes the new pair cell word to ++sp. - store_word(TEMP0, SP, 0) - ゴ low_half(TOS) and_imm(TOS, TOS, 0xffff) Delete the reference to second item down. - サ merge(SP, TOS) lsl_imm(0, SP, 16), Make a new pair record from the SP which points to the new cons'd list - ior(TOS, TOS, 0), and TOS which points to the rest of the stack. This record is then the - add_imm(SP, SP, 4) new TOS pair cell word, and we let the mainloop write it to RAM for us. - -So now that i've recreated it, what is it doing? - -⦾(グ, pop(TEMP0, TOS)) -⦾(ケ, high_half(TEMP1, TOS)) -⦾(ゲ, or_inplace(TEMP0, TEMP1)) -⦾(ド, write_cell(TEMP0, SP)) -⦾(ゴ, low_half(TOS)) -⦾(サ, merge(SP, TOS)) - -⟐(pop(Reg, TOS)) --> ⟐([split_word(Reg, TOS), deref(TOS)]). -⟐(high_half(To, From)) --> [mov_imm_with_shift(0, 0xffff), and(To, From, 0)]. -⟐(or_inplace(To, From)) --> [ior(To, To, From)]. -⟐(write_cell(From, SP)) --> [add_imm(SP, SP, 4), store_word(From, SP, 0)]. -⟐( low_half(Reg)) --> [and_imm(Reg, Reg, 0xffff)]. -⟐(merge(SP, TOS)) --> - [lsl_imm(0, SP, 16), - ior(TOS, TOS, 0), - add_imm(SP, SP, 4)]. - - -This blows, just write it in assembly already. - - -------------------------------- - -TO review, at this point, when we jump to the machine code of a -definition, the following registers hold: - - EXPR - the record word of the expression. - EXPR_addr - the address of the next cell of the expression list. - TERM - the term's record word. - TermAddr - the address of the term. - SP - points to TOS record in RAM - TOS - the record word of TOS - - address of the list to append to is SP + TOS[30:15] - the address of the second stack cell is SP + TOS[15:0] - the address of the second item on the stack is (SP + TOS[15:0]) + ram[SP + TOS[15:0]][30:15] - the address of the third stack cell is (SP + TOS[15:0]) + ram[SP + TOS[15:0]][15: 0] - -we need to create - - [SP - 4] -> 00:(address of the second item on the stack):(address of the list to append to) - [SP - 8] -> 00:(address of the record above) :(address of the third stack cell) - -Each of the addresses above must be converted to offsets from their -respective records. - -ror_imm(TEMP0, TOS, 15), % TEMP0 := TOS >> 15 -add(TEMP0, TEMP0, SP) -% TEMP0 = SP + TOS[30:15] Address of the list to which to append. - -and_imm(TOS, TOS, 0x7fff), % get the offset of the tail of the stack -add(TOS, TOS, SP) -% TOS = SP + TOS[15:0] Address of the second stack cell. - -% the address of the second item on the stack is (TOS) + ram[TOS][30:15] -% the address of the third stack cell is (TOS) + ram[TOS][15: 0] - -load_word(TEMP1, TOS, 0), % TOS := TOS << 15 -% TEMP1 contains the record of the second stack cell. - -% the address of the second item on the stack is (TOS) + TEMP1[30:15] -% the address of the third stack cell is (TOS) + TEMP1[15: 0] - -ror_imm(TEMP2, TEMP1, 15), % TEMP2 := TEMP1 >> 15 -add(TEMP2, TEMP2, TOS) -% TEMP2 contains the address of the second item on the stack - -and_imm(TEMP3, TEMP1, 0x7fff), % get the offset of the third stack cell -add(TEMP3, TEMP1, TOS) -% TEMP3 = TOS + TEMP1[15:0] the address of the third stack cell - - -we need to create - - [SP - 4] -> 00:(address of the second item on the stack):(address of the list to append to) - [SP - 8] -> 00:(address of the record above) :(address of the third stack cell) - 4 << 15 -Each of the addresses above must be converted to offsets from their -respective records. - -sub_imm(SP, SP, 4), -sub(TEMP2, TEMP2, SP), -sub(TEMP0, TEMP0, SP), -lsl_imm(TEMP2, TEMP2, 15), % TEMP2 := TEMP2 << 15 -ior(TEMP2, TEMP2, TEMP0), -store_word(TEMP2, SP, 0), - - -sub_imm(SP, SP, 4), -sub(TEMP3, TEMP3, SP), -mov_imm(TEMP2, 4), -lsl_imm(TEMP2, TEMP2, 15), % TEMP2 := 4 << 15 -ior(TEMP2, TEMP2, TEMP3), -store_word(TEMP2, SP, 0), - -I had some bugs because I forgot that when the offset is zero the base -should not be added/subtracted: zero offset means the value is the empty -list. - -If offsets can only be positive (as I have it now) then record pairs on -the stack can only point to cells above them. That implies that symbols -must be allocated above the stack in RAM. However, I am constructing the -code library from low mem upwards, and if I include the symbol cells in -the function machine code as a kind of header (as I intend to) they'll be -below the stack. I could put the symbol cells together in a clump just -above the stack but then I would need to implement org() and modify the -for_serial/2 relation to emit more than one "patch" for the bootloader. - -I could modify the implementation to allow for negative offsets. That -would be a little tricky but probably easier at the moment than adding -org() and changing for_serial/2. It would also facilitate writing lists -in "reverse" order (the head cell is above the tail in RAM) which is -useful for appending lists to other lists. - -Yeah, I think that's the way to go... - ---------------------------------------------- - -There's soething fishey with the symbols now that they are in the header -of the machine code. Each symbol's pointer field points to the next cell, -which seems really redundant. We need some symbol record to -differentiate from lists and ints. Maybe if more information was in the -header? Like the name of the function? It would make more sense? - -Right now I'm assuming that the eventual parser would be looking up -symbols at parse-time and reusing the header symbols rather than -allocating cells for new ones. If the symbols were kept apart from the -machine code then it makes sense for them to have pointers? - -Maybe I can dispense with symbol records by modifying the -is-this-a-symbol code to just check if the address is below the end of -the library code. - ------------------------------------- - - - [ザ,シ],ヮ(dup), - - ザ swap_halves(TOS) - シ push(TOS, TOS, SP) - - ------------------------------------- - - - [グ,ス,[],[ジ,ス,[ズ,セ,ス,[ゼ,ソ],[タ,ゾ],ヰ,ヂ],ヱ],ヰ,チ],ヮ(i), - - グ, pop(TEMP0, TOS) - ス, if_zero(TEMP0) - ジ, add_const(TEMP3, SP, 4) - ズ, deref(TEMP0) - セ, chop_word(TEMP1, TEMP0) - ゼ, or_inplace(TEMP1, EXPR) - ソ, asm(mov(EXPR, TEMP3)) - タ, add_const(TEMP2, SP, 8) - ゾ, or_inplace(TEMP1, TEMP2) - ヂ, write_cell(TEMP1, SP) - チ, add_const(SP, SP, 4) - - - -⦾([P, T, E, ヰ|Terms], [br(Predicate, Then, Else)|Ts]) --> - ⦾([P, T, E, Terms], [Predicate, Then, Else, Ts]). - -⦾([P, B, ヱ|Terms], [repeat_until(Predicate, Body)|Ts]) --> - ⦾([P, B, Terms], [Predicate, Body, Ts]). - - - - [ - グ, pop(TEMP0, TOS) - ス, if_zero(TEMP0) - [], Then - [ Else - ジ, add_const(TEMP3, SP, 4) - ス, if_zero(TEMP0) - [ Body - ズ, deref(TEMP0) - セ, chop_word(TEMP1, TEMP0) - ス, if_zero(TEMP0) - [ Then - ゼ, or_inplace(TEMP1, EXPR) - ソ asm(mov(EXPR, TEMP3)) - ], - [ Else - タ, add_const(TEMP2, SP, 8) - ゾ or_inplace(TEMP1, TEMP2) - ], - ヰ, br(Predicate, Then, Else) - ヂ write_cell(TEMP1, SP) - ], - ヱ repeat_until(Predicate, Body) - ], - ヰ, br(Predicate, Then, Else) - チ add_const(SP, SP, 4) - ], - ヮ(i), - - ------------------------------------------- - - [ヶ,ペ],ワ(new), - - ヶ, low_half(TOS, SP) - ペ, write_cell(TOS, SP) - - ------------------------------------------- - - - [ナ,ズ,セ,ネ,ヒ,ド,ャ,ペ],ワ(swap), - - ナ, low_half(TEMP0, TOS) - ズ, deref(TEMP0) - セ, chop_word(TEMP1, TEMP0) - ネ, chop_word(TEMP2, TOS) - ヒ, or_inplace(TEMP0, TEMP2) - ド, write_cell(TEMP0, SP) - ャ, asm(ior(TOS, TEMP1, SP)) - ペ, write_cell(TOS, SP) - - --------------------------------------- - -Debugging definitions - - swons 0xd2 load R[0] <- ram[R[0] + 0x34c] -> 0xd3 mov R[2] <- 0x354 - 0xd4 BR T 0x2 immediate - 0xd5 BR F -0x69fffc immediate and R[15] <- PC + 1 - 0xd6 BR GT -0x4c0000 immediate and R[15] <- PC + 1 - dodef 0xd7 mov R[7] <- 0x4 - 0xd8 sub R[0] <- R[0] 0x4 immediate - -Q: Is 0x354 >> 2 == 0xd5 ? - -In [1]: 0x354 >> 2 == 0xd5 -Out[1]: True - -Okay then. - - -> dodef 0xd7 mov R[7] <- 0x4 - 0xd8 sub R[0] <- R[0] 0x4 immediate - 0xd9 sub R[2] <- R[2] 0x0 immediate - 0xda BR EQ 0x2 immediate - 0xdb sub R[2] <- R[2] R[0] - 0xdc and R[2] <- R[2] 0x7fff immediate - - -0xff4 r0 -0x354 r2 - - -> 0xde ior R[2] <- R[2] R[7] - 0xdf store R[2] -> ram[R[0]] - 0xe0 mov R[7] <- 0x168 - 0xe1 add R[7] <- R[7] 0x4 immediate - 0xe2 BR T R[7] - expressi 0xe3 BR F 0x740004 immediate and R[15] <- PC + 1 - -0x39b00004 r2 - - 0xe0 mov R[7] <- 0x168 -> 0xe1 add R[7] <- R[7] 0x4 immediate - 0xe2 BR T R[7] - expressi 0xe3 BR F 0x740004 immediate and R[15] <- PC + 1 - - -0x16c r7 = 364 decimal - -0x5b I machine code in words - -In [8]: 0x16c >> 2 == 0x5b -Out[8]: True - - i 0x5a load R[0] <- ram[R[0] + 0x16c] -> 0x5b lsl R[6] <- R[2] 0x2 immediate - 0x5c asr R[6] <- R[6] 0x11 immediate - 0x5d BR EQ 0x1 immediate - 0x5e add R[6] <- R[6] R[0] - 0x5f lsl R[2] <- R[2] 0x11 immediate - 0x60 asr R[2] <- R[2] 0x11 immediate - -and then... - - i 0x5a load R[0] <- ram[R[0] + 0x16c] - 0x5b lsl R[6] <- R[2] 0x2 immediate - 0x5c asr R[6] <- R[6] 0x11 immediate - 0x5d BR EQ 0x1 immediate -> 0x5e add R[6] <- R[6] R[0] - 0x5f lsl R[2] <- R[2] 0x11 immediate - 0x60 asr R[2] <- R[2] 0x11 immediate - 0x61 BR EQ 0x1 immediate - 0x62 add R[2] <- R[2] R[0] - 0x63 sub R[6] <- R[6] 0x0 immediate - -0x354 r6 check - - 0x5e add R[6] <- R[6] R[0] - 0x5f lsl R[2] <- R[2] 0x11 immediate - 0x60 asr R[2] <- R[2] 0x11 immediate - 0x61 BR EQ 0x1 immediate -> 0x62 add R[2] <- R[2] R[0] - 0x63 sub R[6] <- R[6] 0x0 immediate - 0x64 BR EQ 0x22 immediate - 0x65 sub R[10] <- R[0] 0x4 immediate - -0xff8 r2 - - 0x61 BR EQ 0x1 immediate - 0x62 add R[2] <- R[2] R[0] - 0x63 sub R[6] <- R[6] 0x0 immediate -#117 0x64 BR EQ 0x22 immediate -> 0x65 sub R[10] <- R[0] 0x4 immediate - 0x66 mov R[9] <- 0x4 - 0x67 load R[3] <- ram[R[6]] - iball 0x68 lsl R[7] <- R[3] 0x2 immediate - 0x69 asr R[7] <- R[7] 0x11 immediate - 0x6a BR EQ 0x1 immediate - -line 120 - -#120 0x65 sub R[10] <- R[0] 0x4 immediate - 0x66 mov R[9] <- 0x4 -> 0x67 load R[3] <- ram[R[6]] - iball 0x68 lsl R[7] <- R[3] 0x2 immediate - 0x69 asr R[7] <- R[7] 0x11 immediate - 0x6a BR EQ 0x1 immediate - 0x6b add R[7] <- R[7] R[6] - 0x6c lsl R[8] <- R[3] 0x11 immediate - -line 123 - -0xff960004 r3 - - iball 0x68 lsl R[7] <- R[3] 0x2 immediate - 0x69 asr R[7] <- R[7] 0x11 immediate - 0x6a BR EQ 0x1 immediate -> 0x6b add R[7] <- R[7] R[6] - 0x6c lsl R[8] <- R[3] 0x11 immediate - 0x6d asr R[8] <- R[8] 0x11 immediate - 0x6e BR EQ 0x1 immediate - 0x6f add R[8] <- R[8] R[6] - 0x70 mov R[6] <- R[8] - -0x280 r7 Address of swons def list? of swap symbol? - - In [4]: w.cpu.R[7] - Out[4]: 640L - - In [5]: hex(_) - Out[5]: '0x280L' - - In [6]: w.cpu.ram[w.cpu.R[7]] - Out[6]: 2147484292L - - In [7]: bin(_) - Out[7]: '0b10000000000000000000001010000100' - - In [8]: w.syms.keys() - Out[8]: [160, 35, 7, 104, 44, 45, 14, 205, 48, 200, 210, 227, 86, 215, 90, 157] - - In [9]: 640 >> 2 - Out[9]: 160 - - In [10]: w.syms[160] - Out[10]: 'swap' - -0x280 r7 points to swap symbol record. -=================================================== - - 0x6b add R[7] <- R[7] R[6] - 0x6c lsl R[8] <- R[3] 0x11 immediate - 0x6d asr R[8] <- R[8] 0x11 immediate - 0x6e BR EQ 0x1 immediate -> 0x6f add R[8] <- R[8] R[6] -#127 0x70 mov R[6] <- R[8] - 0x71 sub R[0] <- R[0] 0x4 immediate - 0x72 sub R[8] <- R[8] 0x0 immediate - 0x73 BR EQ 0x4 immediate - -0x358 r8 - -> 0x70 mov R[6] <- R[8] - -line 127 - - 0x70 mov R[6] <- R[8] - 0x71 sub R[0] <- R[0] 0x4 immediate - 0x72 sub R[8] <- R[8] 0x0 immediate -> 0x73 BR EQ 0x4 immediate - 0x74 lsl R[7] <- R[7] 0xf immediate - 0x75 ior R[7] <- R[7] R[9] - 0x76 store R[7] -> ram[R[0]] - 0x77 BR T 0xb immediate - 0x78 sub R[7] <- R[7] 0x0 immediate - -line 129 - - 0x73 BR EQ 0x4 immediate - 0x74 lsl R[7] <- R[7] 0xf immediate - 0x75 ior R[7] <- R[7] R[9] -> 0x76 store R[7] -> ram[R[0]] - 0x77 BR T 0xb immediate - -0x1400004 r7 -> ram[r[0]] w/ r0 = 0xff0 - -saved foobar1 - -I think I found it. Not subtracting SP from r7 address -before merge_and_store(TEMP1, TEMP3, SP) on line #134. -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -jmp @ 0x77 to 0xb -> 0x83 -repeat -> 0x83 sub R[6] <- R[6] 0x0 immediate - 0x84 BR EQ 0x1 immediate - 0x85 BR T -0x1f immediate - 0x86 mov R[1] <- R[10] - 0x87 load R[7] <- ram[R[2]] - 0x88 lsl R[6] <- R[7] 0x2 immediate - - -0x85 + -0x1f - -> 0x67 load R[3] <- ram[R[6]] - iball 0x68 lsl R[7] <- R[3] 0x2 immediate - 0x69 asr R[7] <- R[7] 0x11 immediate - 0x6a BR EQ 0x1 immediate - 0x6b add R[7] <- R[7] R[6] - 0x6c lsl R[8] <- R[3] 0x11 immediate - -back to line 123 - - iball 0x68 lsl R[7] <- R[3] 0x2 immediate - 0x69 asr R[7] <- R[7] 0x11 immediate - 0x6a BR EQ 0x1 immediate - 0x6b add R[7] <- R[7] R[6] - 0x6c lsl R[8] <- R[3] 0x11 immediate - 0x6d asr R[8] <- R[8] 0x11 immediate -> 0x6e BR EQ 0x1 immediate - 0x6f add R[8] <- R[8] R[6] - 0x70 mov R[6] <- R[8] - 0x71 sub R[0] <- R[0] 0x4 immediate - 0x72 sub R[8] <- R[8] 0x0 immediate - 0x73 BR EQ 0x4 immediate - -0xc0 r7 -0x0 r8 - - 0x6e BR EQ 0x1 immediate - 0x6f add R[8] <- R[8] R[6] - 0x70 mov R[6] <- R[8] - 0x71 sub R[0] <- R[0] 0x4 immediate - 0x72 sub R[8] <- R[8] 0x0 immediate -> 0x73 BR EQ 0x4 immediate - 0x74 lsl R[7] <- R[7] 0xf immediate - 0x75 ior R[7] <- R[7] R[9] - 0x76 store R[7] -> ram[R[0]] - 0x77 BR T 0xb immediate - 0x78 sub R[7] <- R[7] 0x0 immediate - -We take the high road this time - - 0x73 BR EQ 0x4 immediate - 0x74 lsl R[7] <- R[7] 0xf immediate - 0x75 ior R[7] <- R[7] R[9] - 0x76 store R[7] -> ram[R[0]] - 0x77 BR T 0xb immediate -> 0x78 sub R[7] <- R[7] 0x0 immediate - 0x79 BR EQ 0x2 immediate - 0x7a sub R[7] <- R[7] R[0] - 0x7b and R[7] <- R[7] 0x7fff immediate - 0x7c sub R[1] <- R[1] 0x0 immediate - 0x7d BR EQ 0x2 immediate - - -r7 = 0xc0 -r0 = 0xfec - -so, @0x7a, r7 <- r7 - r0 -> -3884 or -0xf2c -Hmm... - - 0x78 sub R[7] <- R[7] 0x0 immediate - 0x79 BR EQ 0x2 immediate - 0x7a sub R[7] <- R[7] R[0] -> 0x7b and R[7] <- R[7] 0x7fff immediate - 0x7c sub R[1] <- R[1] 0x0 immediate - 0x7d BR EQ 0x2 immediate - 0x7e sub R[1] <- R[1] R[0] - 0x7f and R[1] <- R[1] 0x7fff immediate - 0x80 lsl R[7] <- R[7] 0xf immediate - - - - 0x7b and R[7] <- R[7] 0x7fff immediate - 0x7c sub R[1] <- R[1] 0x0 immediate - 0x7d BR EQ 0x2 immediate -> 0x7e sub R[1] <- R[1] R[0] - 0x7f and R[1] <- R[1] 0x7fff immediate - 0x80 lsl R[7] <- R[7] 0xf immediate - 0x81 ior R[7] <- R[7] R[1] - 0x82 store R[7] -> ram[R[0]] - -0xfffff3ac r1 ... 0x73ac - - 0x7e sub R[1] <- R[1] R[0] - 0x7f and R[1] <- R[1] 0x7fff immediate - 0x80 lsl R[7] <- R[7] 0xf immediate - 0x81 ior R[7] <- R[7] R[1] -> 0x82 store R[7] -> ram[R[0]] - 0x83 sub R[6] <- R[6] 0x0 immediate - 0x84 BR EQ 0x1 immediate - 0x85 BR T -0x1f immediate - 0x86 mov R[1] <- R[10] - 0x87 load R[7] <- ram[R[2]] - -0x386a73ac r7 !? - - 0x82 store R[7] -> ram[R[0]] - 0x83 sub R[6] <- R[6] 0x0 immediate - 0x84 BR EQ 0x1 immediate - 0x85 BR T -0x1f immediate -> 0x86 mov R[1] <- R[10] - 0x87 load R[7] <- ram[R[2]] - 0x88 lsl R[6] <- R[7] 0x2 immediate - 0x89 asr R[6] <- R[6] 0x11 immediate - 0x8a BR EQ 0x1 immediate - 0x8b add R[6] <- R[6] R[2] - -line 141 - -> 0x87 load R[7] <- ram[R[2]] - -line 146 - -0x4 r7 "the record of the second stack cell" -empty list followed by the record one cell above - - 0x87 load R[7] <- ram[R[2]] -* 0x88 lsl R[6] <- R[7] 0x2 immediate -* 0x89 asr R[6] <- R[6] 0x11 immediate -* 0x8a BR EQ 0x1 immediate -* 0x8b add R[6] <- R[6] R[2] -* 0x8c lsl R[7] <- R[7] 0x11 immediate -* 0x8d asr R[7] <- R[7] 0x11 immediate -* 0x8e BR EQ 0x1 immediate -* 0x8f add R[7] <- R[7] R[2] -> 0x90 sub R[0] <- R[0] 0x4 immediate - 0x91 sub R[6] <- R[6] 0x0 immediate - 0x92 BR EQ 0x2 immediate - 0x93 sub R[6] <- R[6] R[0] - 0x94 and R[6] <- R[6] 0x7fff immediate - 0x95 sub R[7] <- R[7] 0x0 immediate - -at line 150 -0x0 r6 -0xffc r7 - -TEMP0 = HeadAddr, TEMP1 = TailAddr - -mkII.2.2 saved here. - - 0x90 sub R[0] <- R[0] 0x4 immediate - 0x91 sub R[6] <- R[6] 0x0 immediate - 0x92 BR EQ 0x2 immediate - 0x93 sub R[6] <- R[6] R[0] - 0x94 and R[6] <- R[6] 0x7fff immediate - 0x95 sub R[7] <- R[7] 0x0 immediate - 0x96 BR EQ 0x2 immediate - 0x97 sub R[7] <- R[7] R[0] - 0x98 and R[7] <- R[7] 0x7fff immediate - 0x99 lsl R[6] <- R[6] 0xf immediate - 0x9a ior R[6] <- R[6] R[7] -> 0x9b store R[6] -> ram[R[0]] - 0x9c BR T -0x8f immediate - new 0x9d load R[0] <- ram[R[0] + 0x278] - 0x9e mov R[5] <- 0x0 - 0x9f BR T -0x7d immediate - swap 0xa0 load R[0] <- ram[R[0] + 0x284] - - -lie 151-152 end of I machine code - -0x14 r6 20 decimal 5 words/cells above -0xfe8 r0 - -> main 0xe sub R[1] <- R[1] 0x0 immediate - 0xf BR EQ 0x1f immediate - 0x10 load R[4] <- ram[R[1]] - 0x11 lsl R[5] <- R[4] 0x2 immediate - 0x12 asr R[5] <- R[5] 0x11 immediate - 0x13 BR EQ 0x1 immediate - -0xff0 r1 - - - -saved mkII.2.3 - - main 0xe sub R[1] <- R[1] 0x0 immediate - 0xf BR EQ 0x1f immediate -> 0x10 load R[4] <- ram[R[1]] - 0x11 lsl R[5] <- R[4] 0x2 immediate - 0x12 asr R[5] <- R[5] 0x11 immediate - 0x13 BR EQ 0x1 immediate - 0x14 add R[5] <- R[5] R[1] - 0x15 lsl R[6] <- R[4] 0x11 immediate - -line 50 -0x1400004 r4 - - main 0xe sub R[1] <- R[1] 0x0 immediate - 0xf BR EQ 0x1f immediate - 0x10 load R[4] <- ram[R[1]] - 0x11 lsl R[5] <- R[4] 0x2 immediate - 0x12 asr R[5] <- R[5] 0x11 immediate - 0x13 BR EQ 0x1 immediate -> 0x14 add R[5] <- R[5] R[1] - 0x15 lsl R[6] <- R[4] 0x11 immediate - 0x16 asr R[6] <- R[6] 0x11 immediate - 0x17 BR EQ 0x1 immediate - 0x18 add R[6] <- R[6] R[1] - 0x19 load R[3] <- ram[R[5]] - -0x1270 r5 - - 0x14 add R[5] <- R[5] R[1] - 0x15 lsl R[6] <- R[4] 0x11 immediate - 0x16 asr R[6] <- R[6] 0x11 immediate - 0x17 BR EQ 0x1 immediate -> 0x18 add R[6] <- R[6] R[1] - 0x19 load R[3] <- ram[R[5]] - 0x1a mov R[1] <- R[6] - 0x1b asr R[6] <- R[3] 0x1e immediate - 0x1c and R[6] <- R[6] 0x2 immediate - 0x1d sub R[6] <- R[6] 0x2 immediate - -0xff4 r6 - -> 0x19 load R[3] <- ram[R[5]] - -line 53 -0x0 r3 ram[0x1270] - -> 0x1a mov R[1] <- R[6] - -line 56 - -0xff4 r1 - - - 0x1d sub R[6] <- R[6] 0x2 immediate - 0x1e BR NE 0x4 immediate - 0x1f mov R[6] <- 0x3fff0000 - 0x20 ior R[6] <- R[6] 0xffff immediate - 0x21 and R[6] <- R[6] R[3] - 0x22 BR T R[6] -> push 0x23 sub R[0] <- R[0] 0x4 immediate - 0x24 sub R[5] <- R[5] 0x0 immediate - 0x25 BR EQ 0x6 immediate - 0x26 sub R[2] <- R[5] R[0] - 0x27 BR HI 0x1 immediate - 0x28 and R[2] <- R[2] 0x7fff immediate - -Not a literal, 0x0 (but it should be, it should point to swap) - - push 0x23 sub R[0] <- R[0] 0x4 immediate - 0x24 sub R[5] <- R[5] 0x0 immediate - 0x25 BR EQ 0x6 immediate -> 0x26 sub R[2] <- R[5] R[0] - 0x27 BR HI 0x1 immediate - 0x28 and R[2] <- R[2] 0x7fff immediate - 0x29 lsl R[2] <- R[2] 0xf immediate - 0x2a ior R[2] <- R[2] 0x4 immediate - 0x2b BR T 0x1 immediate - -line 68 - -0xfe4 r0 SP -0x28c r2 TOS -0x1270 r5 TermAddr - - push 0x23 sub R[0] <- R[0] 0x4 immediate - 0x24 sub R[5] <- R[5] 0x0 immediate - 0x25 BR EQ 0x6 immediate - 0x26 sub R[2] <- R[5] R[0] - 0x27 BR HI 0x1 immediate - 0x28 and R[2] <- R[2] 0x7fff immediate -> 0x29 lsl R[2] <- R[2] 0xf immediate - 0x2a ior R[2] <- R[2] 0x4 immediate - 0x2b BR T 0x1 immediate - jpel 0x2c mov R[2] <- 0x4 - done 0x2d store R[2] -> ram[R[0]] - 0x2e BR T -0x21 immediate - -line 75 - - - - -================================================== - -iball * 2 - -0xfeac0000 r2 - - -0xc0 r7 - - 0x67 load R[3] <- ram[R[6]] - iball 0x68 lsl R[7] <- R[3] 0x2 immediate - 0x69 asr R[7] <- R[7] 0x11 immediate - 0x6a BR EQ 0x1 immediate -> 0x6b add R[7] <- R[7] R[6] - 0x6c lsl R[8] <- R[3] 0x11 immediate - 0x6d asr R[8] <- R[8] 0x11 immediate - 0x6e BR EQ 0x1 immediate - 0x6f add R[8] <- R[8] R[6] - 0x70 mov R[6] <- R[8] - -0x0 r8 - - 0x70 mov R[6] <- R[8] -> 0x71 sub R[0] <- R[0] 0x4 immediate - 0x72 sub R[8] <- R[8] 0x0 immediate - 0x73 BR EQ 0x8 immediate - 0x74 sub R[7] <- R[7] 0x0 immediate - 0x75 BR EQ 0x2 immediate - 0x76 sub R[7] <- R[7] R[0] - 0x77 and R[7] <- R[7] 0x7fff immediate - 0x78 lsl R[7] <- R[7] 0xf immediate - 0x79 ior R[7] <- R[7] R[9] - 0x7a store R[7] -> ram[R[0]] - 0x7b BR T 0xb immediate -> 0x7c sub R[7] <- R[7] 0x0 immediate - 0x7d BR EQ 0x2 immediate - 0x7e sub R[7] <- R[7] R[0] - 0x7f and R[7] <- R[7] 0x7fff immediate - 0x80 sub R[1] <- R[1] 0x0 immediate - 0x81 BR EQ 0x2 immediate - - - -=================================================== - -Looksgood so far... - -but we just loaded -> 0x67 load R[3] <- ram[R[6]] - -and the value in r3 is malformed: - -In [14]: x = 0xfeac0000 - -In [15]: bin(x) -Out[15]: '0b11111110101011000000000000000000' - -In [16]: len(_)-2 -Out[16]: 32 - -We just loaded that at line 123 -load(TERM, TEMP0), - -Ah! - -I think it's that expr_cell/2 doesn't zero out the top two bits for -records that have negative head offsets. - - - - - - - - - -PC == 0 -PC == 0x25 - -ram[R[0]] -ram[R[1]] \ No newline at end of file diff --git a/thun/metalogical.pl b/thun/metalogical.pl deleted file mode 100644 index caf4b04..0000000 --- a/thun/metalogical.pl +++ /dev/null @@ -1,84 +0,0 @@ -% A Tracing Meta-Interpreter for Thun - -% See https://www.metalevel.at/acomip/ - -tmi(true). -tmi(!). -tmi((A, B)) :- tmi(A), tmi(B). -tmi(number(A)) :- number(A). -tmi(var(A)) :- var(A). - -% Meta-logical print trace. -% (Could also be captured in a list or something instead.) -tmi(thun(E, Si, _)) :- frump(Si, E), fail. - -tmi(Goal) :- - checky(Goal), - clause(Goal, Body), % doesn't work for e.g. + - tmi(Body). - -checky(Goal) :- - Goal \= true, - Goal \= (_,_), - Goal \= var(_), - Goal \= number(_), - Goal \= !. - - -format_state(Stack, Expression, Codes) :- - reverse(Stack, RStack), - phrase(format_stack(RStack), RStackCodes), - phrase(format_stack(Expression), ExpressionCodes), - append(RStackCodes, [32, 46, 32|ExpressionCodes], Codes). - - -frump(Stack, Expression) :- - format_state(Stack, Expression, Codes), - maplist(put_code, Codes), nl. - -% do(In) :- phrase(format_stack(In), Codes), maplist(put_code, Codes). - -% Print Joy expressions as text. - -format_stack(Tail) --> {var(Tail)}, !, [46, 46, 46]. -format_stack([T]) --> format_term(T), !. -format_stack([T|S]) --> format_term(T), " ", format_stack(S). -format_stack([]) --> []. - -format_term(N) --> {number(N), number_codes(N, Codes)}, Codes. -format_term(A) --> { atom(A), atom_codes(A, Codes)}, Codes. -format_term([A|As]) --> "[", format_stack([A|As]), "]". - - - -/* - -[debug] ?- tmi(thun([1, 2, swap], Si, So)). -_-[1, 2, swap]. -[1|_]-[2, swap]. -[2, 1|_]-[swap]. -[1, 2|_]-[]. -So = [1, 2|Si] ; -false. - -[debug] ?- tmi(thun([[1], 2, swons], Si, So)). -_-[[1], 2, swons]. -[[1]|_]-[2, swons]. -[2, [1]|_]-[swons]. -[2, [1]|_]-[swap, cons]. -[[1], 2|_]-[cons]. -[[2, 1]|_]-[]. -So = [[2, 1]|Si] . - -[debug] ?- tmi(thun([[1], 2, [swons], i], Si, So)). -_-[[1], 2, [swons], i]. -[[1]|_]-[2, [swons], i]. -[2, [1]|_]-[[swons], i]. -[[swons], 2, [1]|_]-[i]. -[2, [1]|_]-[swons]. -[2, [1]|_]-[swap, cons]. -[[1], 2|_]-[cons]. -[[2, 1]|_]-[]. -So = [[2, 1]|Si] . - -*/ \ No newline at end of file diff --git a/thun/symbols.txt b/thun/symbols.txt deleted file mode 100644 index 0f2dec8..0000000 --- a/thun/symbols.txt +++ /dev/null @@ -1,32 +0,0 @@ -reset-28 -main-56 -unpack[-68 -]unpack-100 -push-140 -jpel-176 -done-180 -cons-192 -unpack[-196 -]unpack-228 -unpack[-232 -]unpack-264 -dup-344 -i-360 -unpack[-364 -]unpack-396 -iball-416 -unpack[-416 -]unpack-448 -unpack[-560 -]unpack-592 -new-644 -swap-656 -unpack[-660 -]unpack-692 -unpack[-696 -]unpack-728 -unit-816 -x-836 -swons-856 -dodef-876 -expression-924 \ No newline at end of file diff --git a/thun/thun.pl b/thun/thun.pl deleted file mode 100644 index f4699f7..0000000 --- a/thun/thun.pl +++ /dev/null @@ -1,1208 +0,0 @@ -/* - -████████╗██╗ ██╗██╗ ██╗███╗ ██╗ -╚══██╔══╝██║ ██║██║ ██║████╗ ██║ - ██║ ███████║██║ ██║██╔██╗ ██║ - ██║ ██╔══██║██║ ██║██║╚██╗██║ - ██║ ██║ ██║╚██████╔╝██║ ╚████║ - ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ - - Copyright © 2018, 2019, 2020 Simon Forman - - This file is part of Thun - - Thun is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Thun is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Thun. If not see . - -(Big fonts are from Figlet "ANSI Shadow" http://www.patorjk.com/software/taag/#p=display&f=ANSI%20Shadow&t=formatter - and "Small".) - -Table of Contents - Parser & Grammar - Semantics - Functions - Combinators - Definitions - Compiler - to Prolog - to Machine Code - Meta-Programming - Expand/Contract Definitions - Formatter - Partial Reducer - - */ - -:- use_module(library(clpfd)). -:- use_module(library(dcg/basics)). -:- dynamic func/3. -:- dynamic def/2. - - -/* -An entry point. -*/ - -joy(InputString, StackIn, StackOut) :- - phrase(joy_parse(Expression), InputString), !, - thun(Expression, StackIn, StackOut). - -/* - -██████╗ █████╗ ██████╗ ███████╗███████╗██████╗ ██╗ -██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔════╝██╔══██╗ ██║ -██████╔╝███████║██████╔╝███████╗█████╗ ██████╔╝ ████████╗ -██╔═══╝ ██╔══██║██╔══██╗╚════██║██╔══╝ ██╔══██╗ ██╔═██╔═╝ -██║ ██║ ██║██║ ██║███████║███████╗██║ ██║ ██████║ -╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ - - ██████╗ ██████╗ █████╗ ███╗ ███╗███╗ ███╗ █████╗ ██████╗ -██╔════╝ ██╔══██╗██╔══██╗████╗ ████║████╗ ████║██╔══██╗██╔══██╗ -██║ ███╗██████╔╝███████║██╔████╔██║██╔████╔██║███████║██████╔╝ -██║ ██║██╔══██╗██╔══██║██║╚██╔╝██║██║╚██╔╝██║██╔══██║██╔══██╗ -╚██████╔╝██║ ██║██║ ██║██║ ╚═╝ ██║██║ ╚═╝ ██║██║ ██║██║ ██║ - ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ - -The grammar of Joy is very simple. A Joy expression is zero or more Joy -terms separated by blanks, and terms can be either integers, Booleans, -quoted Joy expressions, or symbols (names of functions.) - - joy ::= ( blanks term blanks )* - - term ::= integer | bool | '[' joy ']' | symbol - - integer ::= [ '-' | '+' ] ('0'...'9')+ - bool ::= 'true' | 'false' - symbol ::= char+ - - char ::= - blanks ::= - -For integer//1 and blanks//0 I delegate to SWI's dcg/basics library. The -blank//0 matches and discards space and newline characters and integer//1 -"processes an optional sign followed by a non-empty sequence of digits -into an integer." (https://www.swi-prolog.org/pldoc/man?section=basics) - -Symbols can be made of any non-blank characters except '['and ']' which -are fully reserved for list literals (aka "quotes"). 'true' and 'false' -would be valid symbols but they are reserved for Boolean literals. - -For now strings are neglected in favor of lists of numbers. (But there's -no support for parsing string notation and converting to lists of ints.) - -One wrinkle of the grammar is that numbers do not need to be followed by -blanks before the next match, which is nice when the next match is a -square bracket but a little weird when it's a symbol term. E.g. "2[3]" -parses as [2, [3]] but "23x" parses as [23, x]. It's a minor thing not -worth disfiguring the grammar to change IMO. - -Integers are converted to Prolog integers, symbols and bools to Prolog -atoms, and list literals to Prolog lists. - -*/ - -joy_parse([J|Js]) --> blanks, joy_term(J), blanks, joy_parse(Js). -joy_parse([]) --> []. - -joy_term(int(I)) --> integer(I), !. -joy_term(list(J)) --> "[", !, joy_parse(J), "]". -joy_term(bool(true)) --> "true", !. -joy_term(bool(false)) --> "false", !. -joy_term(symbol(S)) --> symbol(S). - -symbol(C) --> chars(Chars), !, {atom_string(C, Chars)}. - -chars([Ch|Rest]) --> char(Ch), chars(Rest). -chars([Ch]) --> char(Ch). - -char(Ch) --> [Ch], {Ch \== 91, Ch \== 93, code_type(Ch, graph)}. - - -/* Here is an example of Joy code: - - [ [[abs] ii <=] - [ - [<>] [pop !-] || - ] && - ] - [[ !-] [[++]] [[--]] ifte dip] - [[pop !-] [--] [++] ifte ] - ifte - -It probably seems unreadable but with a little familiarity it becomes -just as legible as any other notation. This function accepts two -integers on the stack and increments or decrements one of them such that -the new pair of numbers is the next coordinate pair in a square spiral -(like that used to construct an Ulam Spiral). It is adapted from the -code in the answer here: - -https://stackoverflow.com/questions/398299/looping-in-a-spiral/31864777#31864777 - -It can be used with the x combinator to make a kind of generator for -spiral square coordinates. - - - -███████╗███████╗███╗ ███╗ █████╗ ███╗ ██╗████████╗██╗ ██████╗███████╗ -██╔════╝██╔════╝████╗ ████║██╔══██╗████╗ ██║╚══██╔══╝██║██╔════╝██╔════╝ -███████╗█████╗ ██╔████╔██║███████║██╔██╗ ██║ ██║ ██║██║ ███████╗ -╚════██║██╔══╝ ██║╚██╔╝██║██╔══██║██║╚██╗██║ ██║ ██║██║ ╚════██║ -███████║███████╗██║ ╚═╝ ██║██║ ██║██║ ╚████║ ██║ ██║╚██████╗███████║ -╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝ - -The fundamental Joy relation involves an expression and two stacks. One -stack serves as input and the other as output. - - thun(Expression, InputStack, OutputStack) - -The null expression (denoted by an empty Prolog list) is effectively an -identity function and serves as the end-of-processing marker. As a -matter of efficiency (of Prolog) the thun/3 predicate picks off the first -term of the expression (if any) and passes it to thun/4 which can then -take advantage of Prolog indexing on the first term of a predicate. */ - -thun([], S, S). -thun([Term|E], Si, So) :- thun(Term, E, Si, So). - -/* The thun/4 predicate was originally written in terms of the thun/3 -predicate, which was very elegant, but prevented (I assume but have not -checked) tail-call recursion. In order to alleviate this, partial -reduction is used to generate the actual thun/4 rules, see below. - -Original thun/4 code: - -thun(int(I), E, Si, So) :- thun(E, [ int(I)|Si], So). -thun(bool(B), E, Si, So) :- thun(E, [bool(B)|Si], So). -thun(list(L), E, Si, So) :- thun(E, [list(L)|Si], So). -thun(symbol(Def), E, Si, So) :- def(Def, Body), append(Body, E, Eo), thun(Eo, Si, So). -thun(symbol(Func), E, Si, So) :- func(Func, Si, S), thun(E, S, So). -thun(symbol(Combo), E, Si, So) :- combo(Combo, Si, S, E, Eo), thun(Eo, S, So). - -Integers, Boolean values, and lists are put onto the stack, symbols are -dispatched to one of three kinds of processing: functions, combinators -and definitions (see "defs.txt".) */ - -% Literals turn out okay. - -thun(int(A), [], B, [int(A)|B]). -thun(int(C), [A|B], D, E) :- thun(A, B, [int(C)|D], E). - -thun(bool(A), [], B, [bool(A)|B]). -thun(bool(C), [A|B], D, E) :- thun(A, B, [bool(C)|D], E). - -thun(list(A), [], B, [list(A)|B]). -thun(list(C), [A|B], D, E) :- thun(A, B, [list(C)|D], E). - -% Partial reduction works for func/3 cases. - -thun(symbol(A), [], B, C) :- func(A, B, C). -thun(symbol(A), [C|D], B, F) :- func(A, B, E), thun(C, D, E, F). - -% Combinators look ok too. - -% thun(symbol(A), D, B, C) :- combo(A, B, C, D, []). -% thun(symbol(A), C, B, G) :- combo(A, B, F, C, [D|E]), thun(D, E, F, G). - -% However, in this case, I think the original version will be more -% efficient. - -thun(symbol(Combo), E, Si, So) :- combo(Combo, Si, S, E, Eo), thun(Eo, S, So). - -% In the reduced rules Prolog will redo all the work of the combo/5 -% predicate on backtracking through the second rule. It will try combo/5, -% which usually won't end in Eo=[] so the first rule fails, then it will -% try combo/5 again in the second rule. In this form, after combo/5 has -% completed Prolog has computed Eo and can index on it for thun/3. -% -% Neither functions nor definitions can affect the expression so this -% consideration doesn't apply to those rules. The unification of the head -% clauses will distinguish the cases for them. - -% Definitions don't work though (See "Partial Reducer" section below.) -% I hand-wrote the def/3 cases here. - -thun(symbol(D), [], Si, So) :- def(D, [DH| E]), thun(DH, E, Si, So). -thun(symbol(D), [H|E0], Si, So) :- def(D, [DH|DE]), - append(DE, [H|E0], E), /* ................. */ thun(DH, E, Si, So). - -% Partial reduction has been the subject of a great deal of research and -% I'm sure there's a way to make definitions work, but it's beyond the -% scope of the project at the moment. It works well enough as-is that I'm -% happy to manually write out two rules by hand. - -% Some error handling. - -thun(symbol(Unknown), _, _, _) :- - \+ def(Unknown, _), - \+ func(Unknown, _, _), - \+ combo(Unknown, _, _, _, _), - write("Unknown: "), - writeln(Unknown), - fail. - -/* - -███████╗██╗ ██╗███╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗███████╗ -██╔════╝██║ ██║████╗ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║██╔════╝ -█████╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║███████╗ -██╔══╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║╚════██║ -██║ ╚██████╔╝██║ ╚████║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║███████║ -╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ - -*/ - -func(words, S, [Words|S]) :- words(Words). - -func(swap, [A, B|S], [B, A|S]). -func(dup, [A|S], [A, A|S]). -func(pop, [_|S], S ). - -func(cons, [list(A), B |S], [list([B|A])|S]). -func(concat, [list(A), list(B)|S], [list(C)|S]) :- append(B, A, C). -func(flatten, [list(A)|S], [list(B)|S]) :- flatten(A, B). -func(swaack, [list(R)|S], [list(S)|R]). -func(stack, S , [list(S)|S]). -func(clear, _ , []). -func(first, [list([X|_])|S], [ X |S]). -func(rest, [list([_|X])|S], [list(X)|S]). -func(unit, [X|S], [list([X])|S]). - -func(rolldown, [A, B, C|S], [B, C, A|S]). -func(dupd, [A, B|S], [A, B, B|S]). -func(over, [A, B|S], [B, A, B|S]). -func(tuck, [A, B|S], [A, B, A|S]). - -func(shift, [list([B|A]), list(C)|D], [list(A), list([B|C])|D]). - -func(rollup, Si, So) :- func(rolldown, So, Si). -func(uncons, Si, So) :- func(cons, So, Si). - -func(bool, [ int(0)|S], [bool(false)|S]). -func(bool, [ list([])|S], [bool(false)|S]). -func(bool, [bool(false)|S], [bool(false)|S]). - -func(bool, [ int(N)|S], [bool(true)|S]) :- N #\= 0. -func(bool, [list([_|_])|S], [bool(true)|S]). -func(bool, [ bool(true)|S], [bool(true)|S]). -% func(bool, [A|S], [bool(true)|S]) :- \+ func(bool, [A], [bool(false)]). - -func('empty?', [ list([])|S], [ bool(true)|S]). -func('empty?', [ list([_|_])|S], [bool(false)|S]). - -func('list?', [ list(_)|S], [ bool(true)|S]). -func('list?', [ bool(_)|S], [bool(false)|S]). -func('list?', [ int(_)|S], [bool(false)|S]). -func('list?', [symbol(_)|S], [bool(false)|S]). - -func('one-or-more?', [list([_|_])|S], [ bool(true)|S]). -func('one-or-more?', [ list([])|S], [bool(false)|S]). - -func(and, [bool(true), bool(true)|S], [ bool(true)|S]). -func(and, [bool(true), bool(false)|S], [bool(false)|S]). -func(and, [bool(false), bool(true)|S], [bool(false)|S]). -func(and, [bool(false), bool(false)|S], [bool(false)|S]). - -func(or, [bool(true), bool(true)|S], [ bool(true)|S]). -func(or, [bool(true), bool(false)|S], [ bool(true)|S]). -func(or, [bool(false), bool(true)|S], [ bool(true)|S]). -func(or, [bool(false), bool(false)|S], [bool(false)|S]). - -func( + , [int(A), int(B)|S], [int(C)|S]) :- C #= A + B. -func( - , [int(A), int(B)|S], [int(C)|S]) :- C #= B - A. -func( * , [int(A), int(B)|S], [int(C)|S]) :- C #= A * B. -func( / , [int(A), int(B)|S], [int(C)|S]) :- C #= B div A. -func('%', [int(A), int(B)|S], [int(C)|S]) :- C #= B mod A. - -func('/%', [int(A), int(B)|S], [int(C), int(D)|S]) :- C #= B div A, D #= B mod A. -func( pm , [int(A), int(B)|S], [int(C), int(D)|S]) :- C #= A + B, D #= B - A. - -func(>, [int(A), int(B)|S], [T|S]) :- B #> A #<==> R, r_truth(R, T). -func(<, [int(A), int(B)|S], [T|S]) :- B #< A #<==> R, r_truth(R, T). -func(=, [int(A), int(B)|S], [T|S]) :- B #= A #<==> R, r_truth(R, T). -func(>=, [int(A), int(B)|S], [T|S]) :- B #>= A #<==> R, r_truth(R, T). -func(<=, [int(A), int(B)|S], [T|S]) :- B #=< A #<==> R, r_truth(R, T). -func(<>, [int(A), int(B)|S], [T|S]) :- B #\= A #<==> R, r_truth(R, T). - -r_truth(0, bool(false)). -r_truth(1, bool(true)). - - -/* - - ██████╗ ██████╗ ███╗ ███╗██████╗ ██╗███╗ ██╗ █████╗ ████████╗ ██████╗ ██████╗ ███████╗ -██╔════╝██╔═══██╗████╗ ████║██╔══██╗██║████╗ ██║██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗██╔════╝ -██║ ██║ ██║██╔████╔██║██████╔╝██║██╔██╗ ██║███████║ ██║ ██║ ██║██████╔╝███████╗ -██║ ██║ ██║██║╚██╔╝██║██╔══██╗██║██║╚██╗██║██╔══██║ ██║ ██║ ██║██╔══██╗╚════██║ -╚██████╗╚██████╔╝██║ ╚═╝ ██║██████╔╝██║██║ ╚████║██║ ██║ ██║ ╚██████╔╝██║ ██║███████║ - ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ - -*/ - -combo(i, [list(P)|S], S, Ei, Eo) :- append(P, Ei, Eo). -combo(dip, [list(P), X|S], S, Ei, Eo) :- append(P, [X|Ei], Eo). -combo(dipd, [list(P), X, Y|S], S, Ei, Eo) :- append(P, [Y, X|Ei], Eo). - -combo(dupdip, [list(P), X|S], [X|S], Ei, Eo) :- append(P, [X|Ei], Eo). - -combo(branch, [list(T), list(_), bool(true)|S], S, Ei, Eo) :- append(T, Ei, Eo). -combo(branch, [list(_), list(F), bool(false)|S], S, Ei, Eo) :- append(F, Ei, Eo). - -combo(loop, [list(_), bool(false)|S], S, E, E ). -combo(loop, [list(B), bool(true)|S], S, Ei, Eo) :- append(B, [list(B), symbol(loop)|Ei], Eo). - -combo(step, [list(_), list([])|S], S, E, E ). -combo(step, [list(P), list([X|Z])|S], [X|S], Ei, Eo) :- append(P, [list(Z), list(P), symbol(step)|Ei], Eo). - -combo(times, [list(_), int(0)|S], S, E, E ). -combo(times, [list(P), int(1)|S], S, Ei, Eo) :- append(P, Ei, Eo). -combo(times, [list(P), int(N)|S], S, Ei, Eo) :- N #>= 2, M #= N - 1, append(P, [int(M), list(P), symbol(times)|Ei], Eo). -combo(times, [list(_), int(N)|S], S, _, _ ) :- N #< 0, fail. - -combo(genrec, [R1, R0, Then, If|S], - [ Else, Then, If|S], E, [ifte|E]) :- - append(R0, [[If, Then, R0, R1, symbol(genrec)]|R1], Else). - -combo(primrec, [list(_), list(B), int(N)|S], S, E, Eo) :- - N #=< 0, - append(B, E, Eo). -combo(primrec, [list(R), list(B), int(N) |S], - [list(R), list(B), int(M), int(N)|S], E, Eo) :- - N #> 0, - M #= N - 1, - append([symbol(primrec)|R], E, Eo). - -/* -This is a crude but servicable implementation of the map combinator. - -Obviously it would be nice to take advantage of the implied parallelism. -Instead the quoted program, stack, and terms in the input list are -transformed to simple Joy expressions that run the quoted program on -prepared copies of the stack that each have one of the input terms on -top. These expressions are collected in a list and the whole thing is -evaluated (with infra) on an empty list, which becomes the output list. - -The chief advantage of doing it this way (as opposed to using Prolog's -map) is that the whole state remains in the pending expression, so -there's nothing stashed in Prolog's call stack. This preserves the nice -property that you can interrupt the Joy evaluation and save or transmit -the stack+expression knowing that you have all the state. -*/ - -combo(map, [list(_), list([])|S], [list([])|S], E, E ) :- !. -combo(map, [list(P), list(List)|S], [list(Mapped), list([])|S], E, [symbol(infra)|E]) :- - prepare_mapping(list(P), S, List, Mapped). - -% Set up a program for each term in ListIn -% -% [term S] [P] infrst -% -% prepare_mapping(P, S, ListIn, ListOut). - -prepare_mapping(Pl, S, In, Out) :- prepare_mapping(Pl, S, In, [], Out). - -prepare_mapping( _, _, [], Out, Out) :- !. -prepare_mapping( Pl, S, [T|In], Acc, Out) :- - prepare_mapping(Pl, S, In, [list([T|S]), Pl, symbol(infrst)|Acc], Out). - - -/* - -██████╗ ███████╗███████╗██╗███╗ ██╗██╗████████╗██╗ ██████╗ ███╗ ██╗███████╗ -██╔══██╗██╔════╝██╔════╝██║████╗ ██║██║╚══██╔══╝██║██╔═══██╗████╗ ██║██╔════╝ -██║ ██║█████╗ █████╗ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║███████╗ -██║ ██║██╔══╝ ██╔══╝ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║╚════██║ -██████╔╝███████╗██║ ██║██║ ╚████║██║ ██║ ██║╚██████╔╝██║ ╚████║███████║ -╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ - -*/ - -joy_def --> joy_parse([symbol(Name)|Body]), { assert_def(Name, Body) }. - -assert_defs(DefsFile) :- - read_file_to_codes(DefsFile, Codes, []), - lines(Codes, Lines), - maplist(phrase(joy_def), Lines). - -assert_def(Symbol, Body) :- - ( % Don't let this "shadow" functions or combinators. - \+ func(Symbol, _, _), - \+ combo(Symbol, _, _, _, _) - ) -> ( % Replace any existing defs of this name. - retractall(def(Symbol, _)), - assertz(def(Symbol, Body)) - ) ; true. - -% Split on newline chars a list of codes into a list of lists of codes -% one per line. Helper function. -lines([], []) :- !. -lines(Codes, [Line|Lines]) :- append(Line, [0'\n|Rest], Codes), !, lines(Rest, Lines). -lines(Codes, [Codes]). - -:- assert_defs("defs.txt"). - - -% A meta function that finds the names of all available functions. - -words(Words) :- - findall(Name, clause(func(Name, _, _), _), Funcs), - findall(Name, clause(combo(Name, _, _, _, _), _), Combos, Funcs), - findall(Name, clause(def(Name, _), _), Words0, Combos), - list_to_set(Words0, Words1), - sort(Words1, Words). - - -/* - - ██████╗ ██████╗ ███╗ ███╗██████╗ ██╗██╗ ███████╗██████╗ -██╔════╝██╔═══██╗████╗ ████║██╔══██╗██║██║ ██╔════╝██╔══██╗ -██║ ██║ ██║██╔████╔██║██████╔╝██║██║ █████╗ ██████╔╝ -██║ ██║ ██║██║╚██╔╝██║██╔═══╝ ██║██║ ██╔══╝ ██╔══██╗ -╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ██║███████╗███████╗██║ ██║ - ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ - _ ___ _ - | |_ ___ | _ \_ _ ___| |___ __ _ - | _/ _ \ | _/ '_/ _ \ | _ \/ _` | - \__\___/ |_| |_| \___/_|___/\__, | - |___/ - -This is an experimental compiler from Joy expressions to Prolog code. -As you will see it's also doing type inference and type checking. - -For many Joy expressions the existing code is enough to "compile" them to -Prolog code. E.g. the definition of 'third' is 'rest rest first' and -that's enough for the code to generate the "type" of the expression: - - ?- joy(`third`, Si, So). - Si = [list([_32906, _32942, _32958|_32960])|_32898], - So = [_32958|_32898] . - -Because 'third' is just manipulating lists (the stack is a list too) the -type signature is the whole of the (Prolog) implementation of the -function: - - ?- sjc(third, `third`). - func(third, [list([_, _, A|_])|B], [A|B]). - -So that's nice. - -Functions that involve just math require capturing the constraints -recorded by the CLP(FD) subsystem. SWI Prolog provide a predicate -call_residue_vars/2 to do just that. Together with copy_term/3 it's -possible to collect all the information needed to capture functions -made out of math and stack/list manipulation. (I do not understand the -details of how they work. Markus Triska said they would do the trick and -they did.) - -https://www.swi-prolog.org/pldoc/doc_for?object=call_residue_vars/2 - -https://www.swi-prolog.org/pldoc/doc_for?object=copy_term/3 - -I think this is sort of like "gradual" or "dependent" types. But the -formal theory there is beyond me. In any event, it captures the integer -constraints established by the expressions as well as the "types" of -inputs and outputs. - - ?- sjc(fn, `* + * -`). - func(fn, [int(H), int(I), int(F), int(D), int(C)|A], [int(B)|A]) :- - maplist(call, - - [ clpfd:(B+E#=C), - clpfd:(G*D#=E), - clpfd:(J+F#=G), - clpfd:(H*I#=J) - ]). - -For functions involving 'branch', compilation results in one rule for each -(reachable) path of the branch: - - ?- sjc(fn, `[+] [-] branch`). - - func(fn, [bool(true), int(C), int(D)|A], [int(B)|A]) :- - maplist(call, [clpfd:(B+C#=D)]). - - func(fn, [bool(false), int(B), int(C)|A], [int(D)|A]) :- - maplist(call, [clpfd:(B+C#=D)]). - -(Note that in the subtraction case (bool(true)) the CLP(FD) constraints -are coded as addition but the meaning is the same (subtaction) because of -how the logic variables are named: B + C #= D <==> B #= D - C.) - -?- sjc(fn, `[[+] [-] branch] [pop *] branch`). - - func(fn, [bool(true), _, int(B), int(C)|A], [int(D)|A]) :- - maplist(call, [clpfd:(B*C#=D)]). - - func(fn, [bool(false), bool(true), int(C), int(D)|A], [int(B)|A]) :- - maplist(call, [clpfd:(B+C#=D)]). - - func(fn, [bool(false), bool(false), int(B), int(C)|A], [int(D)|A]) :- - maplist(call, [clpfd:(B+C#=D)]). - -Three paths, three rules. Neat, eh? - -That leaves loop, genrec, and x combinators... - - -*/ - -joy_compile(Name, Expression) :- jcmpl(Name, Expression, Rule), asserta(Rule). - -show_joy_compile(Name, Expression) :- jcmpl(Name, Expression, Rule), portray_clause(Rule). - -jcmpl(Name, Expression, Rule) :- - call_residue_vars(thun(Expression, Si, So), Term), - copy_term(Term, Term, Gs), - Head =.. [func, Name, Si, So], - rule(Head, Gs, Rule). - -rule(Head, [], Head). -rule(Head, [A|B], Head :- maplist(call, [A|B])). - -sjc(Name, InputString) :- phrase(joy_parse(E), InputString), show_joy_compile(Name, E). - - -/* - -Experiments with compilation. - -?- sjc(fn, `[+ dup bool] loop`). - -func(fn, [bool(false)|A], A). - -func(fn, [bool(true), int(B), int(C)|A], [int(0)|A]) :- - maplist(call, [clpfd:(B+C#=0)]). - -func(fn, [bool(true), int(D), int(E), int(B)|A], [int(0)|A]) :- - maplist(call, - [ clpfd:(B in inf.. -1\/1..sup), - clpfd:(C+B#=0), - clpfd:(C in inf.. -1\/1..sup), - clpfd:(D+E#=C) - ]). - -func(fn, [bool(true), int(F), int(G), int(D), int(B)|A], [int(0)|A]) :- - maplist(call, - [ clpfd:(B in inf.. -1\/1..sup), - clpfd:(C+B#=0), - clpfd:(C in inf.. -1\/1..sup), - clpfd:(E+D#=C), - clpfd:(E in inf.. -1\/1..sup), - clpfd:(F+G#=E) - ]). - - - -?- sjc(fn, `[] loop`). - -func(fn, [bool(false)|A], A). - -func(fn, [bool(true), bool(false)|A], A). - -func(fn, [bool(true), bool(true), bool(false)|A], A). - -func(fn, [bool(true), bool(true), bool(true), bool(false)|A], A). - -So... - - `[] loop` ::= true* false - -sorta... - - -The quine '[[dup cons] dup cons]' works fine: - -?- sjc(fn, `dup cons`). -func(fn, [list(A)|B], [list([list(A)|A])|B]). - -?- sjc(fn, `[dup cons] dup cons`). -func(fn, A, [list([list([symbol(dup), symbol(cons)]), symbol(dup), symbol(cons)])|A]). - -?- sjc(fn, `[dup cons] dup cons i`). -func(fn, A, [list([list([symbol(dup), symbol(cons)]), symbol(dup), symbol(cons)])|A]). - -?- sjc(fn, `[dup cons] dup cons i i i i`). -func(fn, A, [list([list([symbol(dup), symbol(cons)]), symbol(dup), symbol(cons)])|A]). - - -In the right context the system will "hallucinate" programs: - -?- sjc(fn, `x`). -func(fn, [list([])|A], [list([])|A]). - -func(fn, [list([int(A)])|B], [int(A), list([int(A)])|B]). - -func(fn, [list([bool(A)])|B], [bool(A), list([bool(A)])|B]). - -func(fn, [list([list(A)])|B], [list(A), list([list(A)])|B]). - -func(fn, [list([symbol(?)])|A], [bool(true), list([symbol(?)])|A]). - -func(fn, [list([symbol(app1)]), list([]), A|B], [A, A|B]). - -func(fn, [list([symbol(app1)]), list([int(A)]), B|C], [int(A), B|C]). - -func(fn, [list([symbol(app1)]), list([bool(A)]), B|C], [bool(A), B|C]). - -With iterative deepening this might be very interesting... - - -Infinite loops are infinite: - -?- sjc(fn, `[x] x`). -ERROR: Out of global-stack. - - -?- sjc(fn, `sum`). -func(fn, [list([])|A], [int(0)|A]). - -func(fn, [list([int(A)])|B], [int(A)|B]) :- - maplist(call, [clpfd:(A in inf..sup)]). - -func(fn, [list([int(C), int(B)])|A], [int(D)|A]) :- - maplist(call, [clpfd:(B+C#=D)]). - -func(fn, [list([int(E), int(D), int(B)])|A], [int(C)|A]) :- - maplist(call, - - [ clpfd:(B+F#=C), - clpfd:(D+E#=F) - ]). - -func(fn, [list([int(G), int(F), int(D), int(B)])|A], [int(C)|A]) :- - maplist(call, - - [ clpfd:(B+E#=C), - clpfd:(D+H#=E), - clpfd:(F+G#=H) - ]). - - -TODO: genrec, fix points. - - - - - ██████╗ ██████╗ ███╗ ███╗██████╗ ██╗██╗ ███████╗██████╗ -██╔════╝██╔═══██╗████╗ ████║██╔══██╗██║██║ ██╔════╝██╔══██╗ -██║ ██║ ██║██╔████╔██║██████╔╝██║██║ █████╗ ██████╔╝ -██║ ██║ ██║██║╚██╔╝██║██╔═══╝ ██║██║ ██╔══╝ ██╔══██╗ -╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ██║███████╗███████╗██║ ██║ - ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ - _ __ __ _ _ ___ _ - | |_ ___ | \/ |__ _ __| |_ (_)_ _ ___ / __|___ __| |___ - | _/ _ \ | |\/| / _` / _| ' \| | ' \/ -_) | (__/ _ \/ _` / -_) - \__\___/ |_| |_\__,_\__|_||_|_|_||_\___| \___\___/\__,_\___| - -Options for getting machine code out of Joy (in Prolog) code? - -1) Translate Joy to Factor and delegate to Factor's native code -generation. - -2) Use e.g. GNU Prolog to compile the Prolog code of Joy. - -3) Translate to: - - 3a) LLVM IR. - - 3b) Some subset of C. - - 3c) Python for Cython. - - 3d) WASM? Something else...? - -But those all rely on a big pile of OPC (Other Ppl's Code). WHich brings -me to... - -4) Oberon RISC CPU machine code. The one I really want to do. I have an -assembler for it, there are emulators and FPGA incarnations, and it's -small and clean. - - 4a) Prolog machine description of the RISC chip. - - 4b) How to actually compile Joy to asm? There is a wealth of - available information and research to draw on, but most of it is in - the context of cenventional languages. Static Joy code presents few - problems but the dynamic nature of most Joy programs does, I think. - (I.e. a lot of Joy code starts by constructing some other Joy code - and running it. It remains to be seen how much of a challenge that - will be. In the limit, you need Prolog at runtime to JIT compile.) - - 4c) Self-hosting requires Prolog-in-Joy. - - - ___ ___ ___ ___ __ __ _ _ ___ _ -| _ |_ _/ __|/ __| | \/ |__ _ __| |_ (_)_ _ ___ / __|___ __| |___ -| /| |\__ | (__ | |\/| / _` / _| ' \| | ' \/ -_) | (__/ _ / _` / -_) -|_|_|___|___/\___| |_| |_\__,_\__|_||_|_|_||_\___| \___\___\__,_\___| - -This is an experimental compiler from Joy expressions to machine code. - -One interesting twist is that Joy doesn't mention variables, just the -operators, so they have to be inferred from the ops. - -So let's take e.g. '+'? - -It seems we want to maintain a mapping from stack locations to registers, -and maybe from locations in lists on the stack, and to memory locations as -well as registers? - -But consider 'pop', the register pointed to by stack_0 is put back in an -available register pool, but then all the stack_N mappings have to point -to stack_N+1 (i.e. stack_0 must now point to what stack_1 pointed to and -stack_1 must point to stack_2, and so on...) - -What if we keep a stack of register/RAM locations in the same order as -the Joy stack? - -Reference counting for registers? Can it be avoided? When you "free" a -register you can just check the stack to see if it's still in there and, -if not, release it back to the free pool. You can amortize that w/o -keeping a counter by keeping a linear list of registers alongside the -stack and pushing and popping registers from it as they are used/free'd -and then checking if a register is ready for reclaimation is just -member/3. Or you can just keep a reference count for each register... -Would it be useful to put CLP(FD) constraints on the ref counts? - -reggy(FreePool, References, ValueMap) - -*/ - -encode_list(List, FP, FP, Addr) --> [], - {addr(list(List))=Addr}. - -get_reggy([], _, _) :- writeln('Out of Registers'), fail. -get_reggy([Reg|FreePool], Reg, FreePool). - -get_reg(Reg, reggy(FreePool0, References, V), reggy(FreePool, [Reg|References], V)) --> [], - {get_reggy(FreePool0, Reg, FreePool)}. - -free_reg(Reg, reggy(FreePool0, References0, V0), reggy(FreePool, References, V)) --> [], - { select(Reg, References0, References), - ( member(Reg, References) % If reg is still in use - -> FreePool= FreePool0, V0=V % we can't free it yet - ; FreePool=[Reg|FreePool0], % otherwise we put it back in the pool. - del_assoc(Reg, V0, _, V) - )}. - -add_ref(Reg, reggy(FreePool, References, V), reggy(FreePool, [Reg|References], V)) --> []. - -assoc_reg(Reg, Value, reggy(FreePool, References, V0), reggy(FreePool, References, V)) --> [], - {put_assoc(Reg, V0, Value, V)}. - -thun_compile(E, Si, So, FP) --> - {empty_assoc(V), - FP0=reggy([r0, r1, r2, r3, - r4, r5, r6, r7, - r8, r9, rA, rB, - rC, rD, rE, rF], [], V)}, - thun_compile(E, Si, So, FP0, FP). - -thun_compile([], S, S, FP, FP) --> []. -thun_compile([Term|Rest], Si, So, FP0, FP1) --> thun_compile(Term, Rest, Si, So, FP0, FP1). - -thun_compile(int(I), E, Si, So, FP0, FP) --> - [mov_imm(R, int(I))], - get_reg(R, FP0, FP1), assoc_reg(R, int(I), FP1, FP2), - thun_compile(E, [R|Si], So, FP2, FP). - -thun_compile(bool(B), E, Si, So, FP0, FP) --> - get_reg(R, FP0, FP1), assoc_reg(R, bool(B), FP1, FP2), - thun_compile(E, [R|Si], So, FP2, FP). - -thun_compile(list(L), E, Si, So, FP0, FP) --> - encode_list(L, FP0, FP1, Addr), - get_reg(R, FP1, FP2), - [load_imm(R, Addr)], - assoc_reg(R, Addr, FP2, FP3), - thun_compile(E, [R|Si], So, FP3, FP). - -thun_compile(symbol(Name), E, Si, So, FP0, FP) --> {def(Name, _)}, !, def_compile(Name, E, Si, So, FP0, FP). -thun_compile(symbol(Name), E, Si, So, FP0, FP) --> {func(Name, _, _)}, !, func_compile(Name, E, Si, So, FP0, FP). -thun_compile(symbol(Name), E, Si, So, FP0, FP) --> {combo(Name, _, _, _, _)}, combo_compile(Name, E, Si, So, FP0, FP). - -% I'm going to assume that any defs that can be compiled to funcs already -% have been. Defs that can't be pre-compiled shove their body expression -% onto the pending expression (continuation) to be compiled "inline". - -def_compile(Def, E, Si, So, FP0, FP) --> - {def(Def, Body), - append(Body, E, Eo)}, - thun_compile(Eo, Si, So, FP0, FP). - - -% swap (et. al.) doesn't change register refs nor introspect values -% so we can delegate its effect to the semantic relation. -non_alloc(swap). -non_alloc(rollup). -non_alloc(rolldown). - -% Functions delegate to a per-function compilation relation. - -func_compile(+, E, [A, B|S], So, FP0, FP) --> !, - free_reg(A, FP0, FP1), - free_reg(B, FP1, FP2), - get_reg(R, FP2, FP3), - assoc_reg(R, int(_), FP3, FP4), - [add(R, A, B)], - % Update value in the context? - thun_compile(E, [R|S], So, FP4, FP). - -func_compile(dup, E, [A|S], So, FP0, FP) --> !, - add_ref(A, FP0, FP1), - thun_compile(E, [A, A|S], So, FP1, FP). - -func_compile(pop, E, [A|S], So, FP0, FP) --> !, - free_reg(A, FP0, FP1), - thun_compile(E, S, So, FP1, FP). - -func_compile(cons, E, [List, Item|S], So, FP0, FP) --> !, - % allocate a cons cell - % https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-33.html#%_sec_5.3 - thun_compile(E, S, So, FP0, FP). - -func_compile(Func, E, Si, So, FP0, FP) --> { non_alloc(Func), !, - func(Func, Si, S) }, - thun_compile(E, S, So, FP0, FP). - -func_compile(_Func, E, Si, So, FP0, FP) --> - % look up function, compile it... - {Si = S}, - thun_compile(E, S, So, FP0, FP). - - -combo_compile(_Combo, E, Si, So, FP0, FP) --> - % look up combinator, compile it... - {Si = S, E = Eo}, - thun_compile(Eo, S, So, FP0, FP). - - -compiler(InputString, MachineCode, StackIn, StackOut) :- - phrase(joy_parse(Expression), InputString), !, - phrase(thun_compile(Expression, StackIn, StackOut, _), MachineCode, []). - - -show_compiler(InputString, StackIn, StackOut) :- - phrase(joy_parse(Expression), InputString), !, - phrase(thun_compile(Expression, StackIn, StackOut, reggy(_, _, V)), MachineCode, []), - maplist(portray_clause, MachineCode), - assoc_to_list(V, VP), - portray_clause(VP). - - -/* - -?- compiler(`1 2 +`, MachineCode, StackIn, StackOut). -MachineCode = [mov_imm(_18272, int(1)), mov_imm(_18298, int(2))], -StackOut = [_18298, _18272|StackIn]. - - -- - - - - - -?- compiler(`1 2 +`, MachineCode, StackIn, StackOut). -MachineCode = [mov_imm(r1, int(1)), mov_imm(r2, int(2)), add(r1, r2, r1)], -StackOut = [r1|StackIn]. - -?- compiler(`1 2 +`, MachineCode, StackIn, StackOut). -MachineCode = [mov_imm(r1, int(1)), mov_imm(r2, int(2)), add(r1, r2, r1)], -StackOut = [r1|StackIn]. - -?- compiler(`1 2 + 3 +`, MachineCode, StackIn, StackOut). -MachineCode = [mov_imm(r1, int(1)), mov_imm(r2, int(2)), add(r1, r2, r1), mov_imm(r3, int(3)), add(r1, r3, r1)], -StackOut = [r1|StackIn]. - -?- compiler(`1 2 + +`, MachineCode, StackIn, StackOut). -MachineCode = [mov_imm(r1, int(1)), mov_imm(r2, int(2)), add(r1, r2, r1), add(_37848, r1, _37848)], -StackIn = StackOut, StackOut = [_37848|_37850]. - -?- compiler(`+ +`, MachineCode, StackIn, StackOut). -MachineCode = [add(_37270, _37264, _37270), add(_37688, _37270, _37688)], -StackIn = [_37264, _37270, _37688|_37690], -StackOut = [_37688|_37690]. - -?- compiler(`+ +`, MachineCode, [r1, r2, r3], StackOut). -MachineCode = [add(r2, r1, r2), add(r3, r2, r3)], -StackOut = [r3]. - -?- compiler(`+ +`, MachineCode, [r1, r2, r3, r4, r5, r6, r7], StackOut). -MachineCode = [add(r2, r1, r2), add(r3, r2, r3)], -StackOut = [r3, r4, r5, r6, r7]. - -- - - - - - - -?- compiler(`1 2 3 + +`, MachineCode, StackIn, StackOut). -MachineCode = [mov_imm(r0, int(1)), mov_imm(r1, int(2)), mov_imm(r2, int(3)), add(r1, r2, r1), add(r0, r1, r0)], -StackOut = [r0|StackIn]. - - -register free seems to work... - -?- compiler(`1 2 + 3 +`, MachineCode, StackIn, StackOut). -MachineCode = [mov_imm(r0, int(1)), mov_imm(r1, int(2)), add(r0, r1, r0), mov_imm(r1, int(3)), add(r0, r1, r0)], -StackOut = [r0|StackIn] ; -false. - -- - - - - -?- compiler(`1 2 dup + 3 +`, MachineCode, StackIn, StackOut). -MachineCode = [mov_imm(r0, int(1)), mov_imm(r1, int(2)), add(r1, r1, r1), mov_imm(r2, int(3)), add(r1, r2, r1)], -StackOut = [r1, r0|StackIn] . - -?- compiler(`dup +`, MachineCode, StackIn, StackOut). -MachineCode = [add(_37000, _37000, _37000)], -StackIn = StackOut, StackOut = [_37000|_37002]. - -?- compiler(`dup +`, MachineCode, [r0], StackOut). -MachineCode = [add(r0, r0, r0)], -StackOut = [r0]. - -?- compiler(`dup +`, MachineCode, [r0], [r0]). -MachineCode = [add(r0, r0, r0)]. - -- - - - - -?- compiler(`1 2 3 4 5 + + + 6 7 + 8 + +`, MachineCode, StackIn, StackOut), maplist(portray_clause, MachineCode). -mov_imm(r0, int(1)). -mov_imm(r1, int(2)). -mov_imm(r2, int(3)). -mov_imm(r3, int(4)). -mov_imm(r4, int(5)). -add(r3, r4, r3). -add(r2, r3, r2). -add(r1, r2, r1). -mov_imm(r2, int(6)). -mov_imm(r3, int(7)). -add(r2, r3, r2). -mov_imm(r3, int(8)). -add(r2, r3, r2). -add(r1, r2, r1). - - -Fun! - -- - - - - -Test that returning registers before asking for new ones -does reuse registers that are unused and preserve registers -that are still in use. - -?- show_compiler(`1 dup 2 + swap 3 +`, StackIn, StackOut). -mov_imm(r0, int(1)). -mov_imm(r1, int(2)). -add(r1, r1, r0). -mov_imm(r2, int(3)). -add(r0, r2, r0). -[r0-int(_), r1-int(_)]. -StackOut = [r0, r1|StackIn] . - - - - -███╗ ███╗███████╗████████╗ █████╗ ██████╗ ██████╗ ██████╗ ██████╗ ██████╗ █████╗ ███╗ ███╗███╗ ███╗██╗███╗ ██╗ ██████╗ -████╗ ████║██╔════╝╚══██╔══╝██╔══██╗ ██╔══██╗██╔══██╗██╔═══██╗██╔════╝ ██╔══██╗██╔══██╗████╗ ████║████╗ ████║██║████╗ ██║██╔════╝ -██╔████╔██║█████╗ ██║ ███████║█████╗██████╔╝██████╔╝██║ ██║██║ ███╗██████╔╝███████║██╔████╔██║██╔████╔██║██║██╔██╗ ██║██║ ███╗ -██║╚██╔╝██║██╔══╝ ██║ ██╔══██║╚════╝██╔═══╝ ██╔══██╗██║ ██║██║ ██║██╔══██╗██╔══██║██║╚██╔╝██║██║╚██╔╝██║██║██║╚██╗██║██║ ██║ -██║ ╚═╝ ██║███████╗ ██║ ██║ ██║ ██║ ██║ ██║╚██████╔╝╚██████╔╝██║ ██║██║ ██║██║ ╚═╝ ██║██║ ╚═╝ ██║██║██║ ╚████║╚██████╔╝ -╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═════╝ - - - - - - - -███████╗██╗ ██╗██████╗ █████╗ ███╗ ██╗██████╗ ██╗ ██████╗ ██████╗ ███╗ ██╗████████╗██████╗ █████╗ ██████╗████████╗ -██╔════╝╚██╗██╔╝██╔══██╗██╔══██╗████╗ ██║██╔══██╗ ██╔╝ ██╔════╝██╔═══██╗████╗ ██║╚══██╔══╝██╔══██╗██╔══██╗██╔════╝╚══██╔══╝ -█████╗ ╚███╔╝ ██████╔╝███████║██╔██╗ ██║██║ ██║ ██╔╝ ██║ ██║ ██║██╔██╗ ██║ ██║ ██████╔╝███████║██║ ██║ -██╔══╝ ██╔██╗ ██╔═══╝ ██╔══██║██║╚██╗██║██║ ██║ ██╔╝ ██║ ██║ ██║██║╚██╗██║ ██║ ██╔══██╗██╔══██║██║ ██║ -███████╗██╔╝ ██╗██║ ██║ ██║██║ ╚████║██████╔╝ ██╔╝ ╚██████╗╚██████╔╝██║ ╚████║ ██║ ██║ ██║██║ ██║╚██████╗ ██║ -╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ - -*/ - -% Simple DCGs to expand/contract definitions. - -expando, Body --> [Def], {def(Def, Body)}. -contracto, [Def] --> {def(Def, Body)}, Body. - -% Apply expando/contracto more than once, and descend into sub-lists. -% The K term is one of expando or contracto, and the J term is used -% on sub-lists, i.e. expando/grow and contracto/shrink. -% BTW, "rebo" is a meaningless name, don't break your brain -% trying to figure it out. - -rebo(K, J) --> K , rebo(K, J). -rebo(K, J), [E] --> [[H|T]], !, {call(J, [H|T], E)}, rebo(K, J). -rebo(K, J), [A] --> [ A ], !, rebo(K, J). -rebo(_, _) --> []. - -to_fixed_point(DCG, Ei, Eo) :- - phrase(DCG, Ei, E), % Apply DCG... - (Ei=E -> Eo=E ; to_fixed_point(DCG, E, Eo)). % ...until a fixed-point is reached. - -grow --> to_fixed_point(rebo(expando, grow )). -shrink --> to_fixed_point(rebo(contracto, shrink)). - -% ?- phrase(grow, [third], Out). -% Out = [rest, rest, first] ; -% Out = [rest, rest, first] ; -% Out = [rest, second] ; -% Out = [third]. - -% ?- phrase(shrink, [rest, rest, first], Out). -% Out = [rrest, first] ; -% Out = [third] ; -% Out = [rest, second] ; -% Out = [rest, rest, first]. - -/* - -███████╗ ██████╗ ██████╗ ███╗ ███╗ █████╗ ████████╗████████╗███████╗██████╗ -██╔════╝██╔═══██╗██╔══██╗████╗ ████║██╔══██╗╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗ -█████╗ ██║ ██║██████╔╝██╔████╔██║███████║ ██║ ██║ █████╗ ██████╔╝ -██╔══╝ ██║ ██║██╔══██╗██║╚██╔╝██║██╔══██║ ██║ ██║ ██╔══╝ ██╔══██╗ -██║ ╚██████╔╝██║ ██║██║ ╚═╝ ██║██║ ██║ ██║ ██║ ███████╗██║ ██║ -╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ - - -?- phrase(joy_parse(E), `22 18 true [false] [1[2[3]]]`), !, format_joy_terms(E, A, []), string_codes(S, A). -E = [int(22), int(18), bool(true), list([bool(false)]), list([int(1), list([...|...])])], -A = [50, 50, 32, 49, 56, 32, 116, 114, 117|...], -S = "22 18 true [false] [1 [2 [3]]]". - -*/ - -format_joy_expression( int(I)) --> { number_codes(I, Codes) }, Codes. -format_joy_expression( bool(B)) --> { atom_codes(B, Codes) }, Codes. -format_joy_expression(symbol(S)) --> { atom_codes(S, Codes) }, Codes. -format_joy_expression( list(J)) --> "[", format_joy_terms(J), "]". - -format_joy_terms( []) --> []. -format_joy_terms( [T]) --> format_joy_expression(T), !. -format_joy_terms([T|Ts]) --> format_joy_expression(T), " ", format_joy_terms(Ts). - -joy_terms_to_string(Expr, String) :- - format_joy_terms(Expr, Codes, []), - string_codes(String, Codes). - - -/* - -██████╗ █████╗ ██████╗ ████████╗██╗ █████╗ ██╗ -██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██║██╔══██╗██║ -██████╔╝███████║██████╔╝ ██║ ██║███████║██║ -██╔═══╝ ██╔══██║██╔══██╗ ██║ ██║██╔══██║██║ -██║ ██║ ██║██║ ██║ ██║ ██║██║ ██║███████╗ -╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ - -██████╗ ███████╗██████╗ ██╗ ██╗ ██████╗███████╗██████╗ -██╔══██╗██╔════╝██╔══██╗██║ ██║██╔════╝██╔════╝██╔══██╗ -██████╔╝█████╗ ██║ ██║██║ ██║██║ █████╗ ██████╔╝ -██╔══██╗██╔══╝ ██║ ██║██║ ██║██║ ██╔══╝ ██╔══██╗ -██║ ██║███████╗██████╔╝╚██████╔╝╚██████╗███████╗██║ ██║ -╚═╝ ╚═╝╚══════╝╚═════╝ ╚═════╝ ╚═════╝╚══════╝╚═╝ ╚═╝ - -Partial Reducer from "The Art of Prolog" by Sterling and Shapiro -Program 18.3, pg. 362 */ - -process(Program, ReducedProgram) :- - findall(PC1, (member(C1, Program), preduce(C1, PC1)), ReducedProgram). - -preduce( (A :- B), (Pa :- Pb) ) :- !, preduce(B, Pb), preduce(A, Pa). -preduce( true, true ) :- !. -preduce( (A, B), Residue ) :- !, preduce(A, Pa), preduce(B, Pb), combine(Pa, Pb, Residue). -% preduce( A, B ) :- should_fold(A, B), !. -preduce( A, Residue ) :- should_unfold(A), !, clause(A, B), preduce(B, Residue). -preduce( A, A ). - -% As {*,1} and {+,0} so we have {(,),true}. Whatsitsname? Monoid or something... -% {*,0} {+,Inf} {(,),fail}... - -combine(true, B, B) :- !. -combine(A, true, A) :- !. -combine(A, B, (A, B)). - -/* - -Partial reduction of thun/3 in the thun/4 relation gives a new -version of thun/4 that is tail-recursive. You generate the new -relation rules like so: - - ?- thunder(C), process(C, R), maplist(portray_clause, R). - -I just cut-n-paste from the SWI terminal and rearrange it. - -*/ - -should_unfold(thun(_, _, _)). -% should_unfold(func(_, _, _)). -% should_unfold(def(_, _)). - -thunder([ % Source code for thun/4. - (thun( int(I), E, Si, So) :- thun(E, [ int(I)|Si], So)), - (thun(bool(B), E, Si, So) :- thun(E, [bool(B)|Si], So)), - (thun(list(L), E, Si, So) :- thun(E, [list(L)|Si], So)), - % (thun(symbol(Def), E, Si, So) :- def(Def, [Head|Body]), append(Body, E, Eo), thun(Head, Eo, Si, So)), - (thun(symbol(Func), E, Si, So) :- func(Func, Si, S), thun(E, S, So)) - % (thun(symbol(Combo), E, Si, So) :- combo(Combo, Si, S, E, Eo), thun(Eo, S, So)) -]). - -/* - -N.B.: in 'thun(symbol(Def)...' the last clause has changed from thun/3 to thun/4. -The earlier version doesn't transform into correct code: - - thun(symbol(B), D, A, A) :- def(B, C), append(C, D, []). - thun(symbol(A), C, F, G) :- def(A, B), append(B, C, [D|E]), thun(D, E, F, G). - -With the change to thun/4 it doesn't transform under reduction w/ thun/3. - -You can also unfold def/2 and func/3 (but you need to check for bugs!) - -Functions become clauses like these: - - thun(symbol(rolldown), [], [C, A, B|D], [A, B, C|D]). - thun(symbol(rolldown), [A|B], [E, C, D|F], G) :- thun(A, B, [C, D, E|F], G). - - thun(symbol(dupd), [], [A, B|C], [A, B, B|C]). - thun(symbol(dupd), [A|B], [C, D|E], F) :- thun(A, B, [C, D, D|E], F). - - thun(symbol(over), [], [B, A|C], [A, B, A|C]). - thun(symbol(over), [A|B], [D, C|E], F) :- thun(A, B, [C, D, C|E], F). - -Definitions become - - thun(symbol(of), A, D, E) :- - append([symbol(swap), symbol(at)], A, [B|C]), - thun(B, C, D, E). - - thun(symbol(pam), A, D, E) :- - append([list([symbol(i)]), symbol(map)], A, [B|C]), - thun(B, C, D, E). - - thun(symbol(popd), A, D, E) :- - append([list([symbol(pop)]), symbol(dip)], A, [B|C]), - thun(B, C, D, E). - -These are tail-recursive and allow for better indexing so I would expect -them to be more efficient than the originals. Ii would be even nicer to -get them looking like this: - - thun(symbol(of), A, D, E) :- thun(symbol(swap), [symbol(at)|A], D, E). - -And then if 'swap' was a definition you could push it out even further, -you could pre-expand definitions and functions (and maybe even some -combinators!) - -*/ \ No newline at end of file