diff --git a/docs/lib/game.js b/docs/lib/game.js
deleted file mode 100644
index 6ee682d05..000000000
--- a/docs/lib/game.js
+++ /dev/null
@@ -1,892 +0,0 @@
-
- /**
- * Transforms the given list into config object. The list follows
- * the format of list([key1, value1], [key2, value2]).
- *
- * e.g list(["alpha", 0], ["duration", 1000])
- *
- * @param {list} lst the list to be turned into config object.
- * @returns {config} config object
- */
- function create_config(lst) {
- const config = {};
- map((xs) => {
- if (!is_pair(xs)) {
- throw_error(`xs is not pair!`);
- }
- config[head(xs)] = tail(xs);
- }, lst);
-
- return config;
- }
-
- /**
- * Create text config object, can be used to stylise text object.
- *
- * font_family: for available font_family, see:
- * https://developer.mozilla.org/en-US/docs/Web/CSS/font-family#Valid_family_names
- *
- * align: must be either 'left', 'right', 'center', or 'justify'
- *
- * For more details about text config, see:
- * https://photonstorm.github.io/phaser3-docs/Phaser.Types.GameObjects.Text.html#.TextStyle
- *
- * @param {string} font_family font to be used
- * @param {string} font_size size of font, must be appended with 'px' e.g. '16px'
- * @param {string} color colour of font, in hex e.g. '#fff'
- * @param {string} stroke colour of stroke, in hex e.g. '#fff'
- * @param {number} stroke_thickness thickness of stroke
- * @param {number} align text alignment
- * @returns {config} text config
- */
- function create_text_config(
- font_family = "Courier",
- font_size = "16px",
- color = "#fff",
- stroke = "#fff",
- stroke_thickness = 0,
- align = "left"
- ) {
- const lst = list(
- ["fontFamily", font_family],
- ["fontSize", font_size],
- ["color", color],
- ["stroke", stroke],
- ["strokeThickness", stroke_thickness],
- ["align", align]
- );
- return create_config(lst);
- }
-
- /**
- * Create interactive config object, can be used to configure interactive settings.
- *
- * For more details about interactive config object, see:
- * https://photonstorm.github.io/phaser3-docs/Phaser.Types.Input.html#.InputConfiguration
- *
- * @param {boolean} draggable object will be set draggable
- * @param {boolean} use_hand_cursor if true, pointer will be set to 'pointer' when a pointer is over it
- * @param {boolean} pixel_perfect pixel perfect function will be set for the hit area. Only works for texture based object
- * @param {number} alpha_tolerance if pixel_perfect is set, this is the alpha tolerance threshold value used in the callback
- * @returns {config} interactive config
- */
- function create_interactive_config(
- draggable = false,
- use_hand_cursor = false,
- pixel_perfect = false,
- alpha_tolerance = 1
- ) {
- const lst = list(
- ["draggable", draggable],
- ["useHandCursor", use_hand_cursor],
- ["pixelPerfect", pixel_perfect],
- ["alphaTolerance", alpha_tolerance]
- );
- return create_config(lst);
- }
-
- /**
- * Create sound config object, can be used to configure sound settings.
- *
- * For more details about sound config object, see:
- * https://photonstorm.github.io/phaser3-docs/Phaser.Types.Sound.html#.SoundConfig
- *
- * @param {boolean} mute whether the sound should be muted or not
- * @param {number} volume value between 0(silence) and 1(full volume)
- * @param {number} rate the speed at which the sound is played
- * @param {number} detune detuning of the sound, in cents
- * @param {number} seek position of playback for the sound, in seconds
- * @param {boolean} loop whether or not the sound should loop
- * @param {number} delay time, in seconds, that elapse before the sound actually starts
- * @returns {config} sound config
- */
- function create_sound_config(
- mute = false,
- volume = 1,
- rate = 1,
- detune = 0,
- seek = 0,
- loop = false,
- delay = 0
- ) {
- const lst = list(
- ["mute", mute],
- ["volume", volume],
- ["rate", rate],
- ["detune", detune],
- ["seek", seek],
- ["loop", loop],
- ["delay", delay]
- );
- return create_config(lst);
- }
-
- /**
- * Create tween config object, can be used to configure tween settings.
- *
- * For more details about tween config object, see:
- * https://photonstorm.github.io/phaser3-docs/Phaser.Types.Tweens.html#.TweenBuilderConfig
- *
- * @param {string} target_prop target to tween, e.g. x, y, alpha
- * @param {string | number} target_value the property value to tween to
- * @param {number} delay time in ms/frames before tween will start
- * @param {number} duration duration of tween in ms/frames, exclude yoyos or repeats
- * @param {Function | string} ease ease function to use, e.g. 'Power0', 'Power1', 'Power2'
- * @param {Function} on_complete function to execute when tween completes
- * @param {boolean} yoyo if set to true, once tween complete, reverses the values incrementally to get back to the starting tween values
- * @param {number} loop number of times the tween should loop, or -1 to loop indefinitely
- * @param {number} loop_delay The time the tween will pause before starting either a yoyo or returning to the start for a repeat
- * @param {Function} on_loop function to execute each time the tween loops
- * @returns {config} tween config
- */
- function create_tween_config(
- target_prop = "x",
- target_value = 0,
- delay = 0,
- duration = 1000,
- ease = "Power0",
- on_complete = null_fn,
- yoyo = false,
- loop = 0,
- loop_delay = 0,
- on_loop = null_fn
- ) {
- const lst = list(
- [target_prop, target_value],
- ["delay", delay],
- ["duration", duration],
- ["ease", ease],
- ["onComplete", on_complete],
- ["yoyo", yoyo],
- ["loop", loop],
- ["loopDelay", loop_delay],
- ["onLoop", on_loop]
- );
- return create_config(lst);
- }
-
- /**
- * Create anims config, can be used to configure anims
- *
- * For more details about the config object, see:
- * https://photonstorm.github.io/phaser3-docs/Phaser.Types.Animations.html#.Animation
- *
- * @param {string} anims_key key that the animation will be associated with
- * @param {list_of_config} anim_frames data used to generate the frames for animation
- * @param {number} frame_rate frame rate of playback in frames per second
- * @param {number} duration how long the animation should play in seconds.
- * If null, will be derived from frame_rate
- * @param {number} repeat number of times to repeat the animation, -1 for infinity
- * @param {boolean} yoyo should the animation yoyo (reverse back down to the start)
- * @param {boolean} show_on_start should the sprite be visible when the anims start?
- * @param {boolean} hide_on_complete should the sprite be not visible when the anims finish?
- * @returns {config} anim config
- */
- function create_anim_config(
- anims_key,
- anim_frames,
- frame_rate = 24,
- duration = null,
- repeat = -1,
- yoyo = false,
- show_on_start = true,
- hide_on_complete = false
- ) {
- // Convert from list to array
- const anim_frames_arr = [];
- map((xs) => anim_frames_arr.push(xs), anim_frames);
-
- const lst = list(
- ["key", anims_key],
- ["frames", anim_frames_arr],
- ["frameRate", frame_rate],
- ["duration", duration],
- ["repeat", repeat],
- ["yoyo", yoyo],
- ["showOnStart", show_on_start],
- ["hideOnComplete", hide_on_complete]
- );
- return create_config(lst);
- }
-
-
-
-
-
-
-
-
-
-
- /**
- * Create animation frame config, can be used to configure a specific frame
- * within an animation.
- *
- * The key should refer to an image that is already loaded.
- * To make frame_config from spritesheet based on its frames,
- * use create_anim_spritesheet_frame_configs instead.
- *
- * @param {string} key key that is associated with the sprite at this frame
- * @param {string | number} frame either index or string, of the frame
- * @param {number} duration duration, in ms, of this frame of the animation
- * @param {boolean} visible should the parent object be visible during this frame?
- * @returns {config} anim frame config
- */
- function create_anim_frame_config(key, duration = 0, visible = true) {
- const lst = list(
- ["key", key],
- ["duration", duration],
- ["visible", visible]
- );
- return create_config(lst);
- }
-
- /**
- * Create list of animation frame config, can be used directly as part of
- * anim_config's `frames` parameter.
- *
- * This function will generate list of frame configs based on the
- * spritesheet_config attached to the associated spritesheet.
-
- * This function requires that the given key is a spritesheet key
- * i.e. a key associated with loaded spritesheet, loaded in using
- * load_spritesheet function.
- *
- * Will return empty frame configs if key is not associated with
- * a spritesheet.
- *
- * @param {string} key key associated with spritesheet
- * @returns {list_of_configs}
- */
- function create_anim_spritesheet_frame_configs(key) {
- if (preload_spritesheet_map.get(key)) {
- const config_arr = scene.anims.generateFrameNumbers(key, {});
-
- // Convert from array to js-slang list
- const config_lst = build_list(config_arr.length, (id) => config_arr[id]);
- return config_lst;
- } else {
- throw_error(`${key} is not associated with any spritesheet`);
- }
- }
-
- /**
- * Create spritesheet config, can be used to configure the frames within the
- * spritesheet. Can be used as config at load_spritesheet.
- *
- * @param {number} frame_width width of frame in pixels
- * @param {number} frame_height height of frame in pixels
- * @param {number} start_frame first frame to start parsing from
- * @param {number} margin margin in the image; this is the space around the edge of the frames
- * @param {number} spacing the spacing between each frame in the image
- * @returns {config} spritesheet config
- */
- function create_spritesheet_config(
- frame_width,
- frame_height,
- start_frame = 0,
- margin = 0,
- spacing = 0
- ) {
- const lst = list(
- ["frameWidth", frame_width],
- ["frameHeight", frame_height],
- ["startFrame", start_frame],
- ["margin", margin],
- ["spacing", spacing]
- );
- return create_config(lst);
- }
-
- ///////////////////////////
- // SCREEN //
- ///////////////////////////
-
- /**
- * Get in-game screen width.
- *
- * @return {number} screen width
- */
- function get_screen_width() {
- return screen_size.x;
- }
-
- /**
- * Get in-game screen height.
- *
- * @return {number} screen height
- */
- function get_screen_height() {
- return screen_size.y;
- }
-
- /**
- * Get game screen display width (accounting window size).
- *
- * @return {number} screen display width
- */
- function get_screen_display_width() {
- return scene.scale.displaySize.width;
- }
-
- /**
- * Get game screen display height (accounting window size).
- *
- * @return {number} screen display height
- */
- function get_screen_display_height() {
- return scene.scale.displaySize.height;
- }
-
- ///////////////////////////
- // LOAD //
- ///////////////////////////
-
- /**
- * Load the image asset into the scene for use. All images
- * must be loaded before used in create_image.
- *
- * @param {string} key key to be associated with the image
- * @param {string} url path to the image
- */
- function load_image(key, url) {
- preload_image_map.set(key, url);
- }
-
- /**
- * Load the sound asset into the scene for use. All sound
- * must be loaded before used in play_sound.
- *
- * @param {string} key key to be associated with the sound
- * @param {string} url path to the sound
- */
- function load_sound(key, url) {
- preload_sound_map.set(key, url);
- }
-
- /**
- * Load the spritesheet into the scene for use. All spritesheet must
- * be loaded before used in create_image.
- *
- * @param {string} key key associated with the spritesheet
- * @param {string} url path to the sound
- * @param {config} spritesheet_config config to determines frames within the spritesheet
- */
- function load_spritesheet(key, url, spritesheet_config) {
- preload_spritesheet_map.set(key, [url, spritesheet_config]);
- }
-
- ///////////////////////////
- // ADD //
- ///////////////////////////
-
- /**
- * Add the object to the scene. Only objects added to the scene
- * will appear.
- *
- * @param {Phaser.GameObjects.GameObject} obj game object to be added
- */
- function add(obj) {
- if (is_any_type(obj, obj_types)) {
- scene.add.existing(get_obj(obj));
- return obj;
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- ///////////////////////////
- // SOUND //
- ///////////////////////////
-
- /**
- * Play the sound associated with the key.
- * Throws error if key is nonexistent.
- *
- * @param {string} key key to the sound to be played
- * @param {config} config sound config to be used
- */
- function play_sound(key, config = {}) {
- if (preload_sound_map.get(key)) {
- scene.sound.play(key, config);
- } else {
- throw_error(`${key} is not associated with any sound`);
- }
- }
-
- ///////////////////////////
- // ANIMS //
- ///////////////////////////
-
- /**
- * Create a new animation and add it to the available animations.
- * Animations are global i.e. once created, it can be used anytime, anywhere.
- *
- * NOTE: Anims DO NOT need to be added into the scene to be used.
- * It is automatically added to the scene when it is created.
- *
- * WIll return true if the animation key is valid
- * (key is specified within the anim_config); false if the key
- * is already in use.
- *
- * @param {config} anim_config
- * @returns {boolean} true if animation is successfully created, false otherwise
- */
- function create_anim(anim_config) {
- const anims = scene.anims.create(anim_config);
- return typeof anims !== "boolean";
- }
-
-
-
-
-
-
-
-
-
- /**
- * Start playing the given animation on image game object.
- *
- * @param {Phaser.GameObject.Sprite} image image game object
- * @param {string} anims_key key associated with an animation
- */
- function play_anim_on_image(image, anims_key) {
- if (is_type(image, image_type)) {
- get_obj(image).play(anims_key);
- return image;
- } else {
- throw_error(`${image} is not of type ${image_type}`);
- }
- }
-
- ///////////////////////////
- // IMAGE //
- ///////////////////////////
-
- /**
- * Create an image using the key associated with a loaded image.
- * If key is not associated with any loaded image, throws error.
- *
- * 0, 0 is located at the top, left hand side.
- *
- * @param {number} x x position of the image. 0 is at the left side
- * @param {number} y y position of the image. 0 is at the top side
- * @param {string} asset_key key to loaded image
- * @returns {Phaser.GameObjects.Sprite} image game object
- */
- function create_image(x, y, asset_key) {
- if (
- preload_image_map.get(asset_key) ||
- preload_spritesheet_map.get(asset_key)
- ) {
- const image = new Phaser.GameObjects.Sprite(scene, x, y, asset_key);
- return set_type(image, image_type);
- } else {
- throw_error(`${asset_key} is not associated with any image`);
- }
- }
-
- ///////////////////////////
- // AWARD //
- ///////////////////////////
-
- /**
- * Create an award using the key associated with the award.
- * The award key can be obtained from the Awards Hall or
- * Awards menu, after attaining the award.
- *
- * Valid award will have an on-hover VERIFIED tag to distinguish
- * it from images created by create_image.
- *
- * If student does not possess the award, this function will
- * return a untagged, default image.
- *
- * @param {number} x x position of the image. 0 is at the left side
- * @param {number} y y position of the image. 0 is at the top side
- * @param {string} award_key key for award
- * @returns {Phaser.GameObject.Sprite} award game object
- */
- function create_award(x, y, award_key) {
- return set_type(create_valid_award(x, y, award_key), award_type);
- }
-
- ///////////////////////////
- // TEXT //
- ///////////////////////////
-
- /**
- * Create a text object.
- *
- * 0, 0 is located at the top, left hand side.
- *
- * @param {number} x x position of the text
- * @param {number} y y position of the text
- * @param {string} text text to be shown
- * @param {config} config text configuration to be used
- * @returns {Phaser.GameObjects.Text} text game object
- */
- function create_text(x, y, text, config = {}) {
- const txt = new Phaser.GameObjects.Text(scene, x, y, text, config);
- return set_type(txt, text_type);
- }
-
- ///////////////////////////
- // RECTANGLE //
- ///////////////////////////
-
- /**
- * Create a rectangle object.
- *
- * 0, 0 is located at the top, left hand side.
- *
- * @param {number} x x coordinate of the top, left corner posiiton
- * @param {number} y y coordinate of the top, left corner position
- * @param {number} width width of rectangle
- * @param {number} height height of rectangle
- * @param {number} fill colour fill, in hext e.g 0xffffff
- * @param {number} alpha value between 0 and 1 to denote alpha
- * @returns {Phaser.GameObjects.Rectangle} rectangle object
- */
- function create_rect(x, y, width, height, fill = 0, alpha = 1) {
- const rect = new Phaser.GameObjects.Rectangle(
- scene,
- x,
- y,
- width,
- height,
- fill,
- alpha
- );
- return set_type(rect, rect_type);
- }
-
- ///////////////////////////
- // ELLIPSE //
- ///////////////////////////
-
- /**
- * Create an ellipse object.
- *
- * @param {number} x x coordinate of the centre of ellipse
- * @param {number} y y coordinate of the centre of ellipse
- * @param {number} width width of ellipse
- * @param {number} height height of ellipse
- * @param {number} fill colour fill, in hext e.g 0xffffff
- * @param {number} alpha value between 0 and 1 to denote alpha
- * @returns {Phaser.GameObjects.Ellipse} ellipse object
- */
- function create_ellipse(x, y, width, height, fill = 0, alpha = 1) {
- const ellipse = new Phaser.GameObjects.Ellipse(
- scene,
- x,
- y,
- width,
- height,
- fill,
- alpha
- );
- return set_type(ellipse, ellipse_type);
- }
-
- ///////////////////////////
- // CONTAINER //
- ///////////////////////////
-
- /**
- * Create a container object. Container is able to contain any other game object,
- * and the positions of contained game object will be relative to the container.
- *
- * Rendering the container as visible or invisible will also affect the contained
- * game object.
- *
- * Container can also contain another container.
- *
- * 0, 0 is located at the top, left hand side.
- *
- * For more details about container object, see:
- * https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Container.html
- *
- * @param {number} x x position of the container
- * @param {number} y y position of the container
- * @returns {Phaser.GameObjects.Container} container object
- */
- function create_container(x, y) {
- const cont = new Phaser.GameObjects.Container(scene, x, y);
- return set_type(cont, container_type);
- }
-
- /**
- * Add the given game object to the container.
- * Mutates the container.
- *
- * @param {Phaser.GameObject.Container} container container object
- * @param {Phaser.GameObject.GameObject} objs game object to add to the container
- * @returns {Phaser.GameObject.Container} container object
- */
- function add_to_container(container, obj) {
- if (is_type(container, container_type) && is_any_types(obj, obj_types)) {
- get_obj(container).add(get_obj(obj));
- return container;
- } else {
- throw_error(
- `${obj} is not of type ${obj_types} or ${container} is not of type ${container_type}`
- );
- }
- }
-
- ///////////////////////////
- // OBJECT //
- ///////////////////////////
-
- /**
- * Destroy the given game object. Destroyed game object
- * is removed from the scene, and all of its listeners
- * is also removed.
- *
- * @param {Phaser.GameObjects.GameObject} obj game object itself
- */
- function destroy_obj(obj) {
- if (is_any_type(obj, obj_types)) {
- get_obj(obj).destroy();
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- /**
- * Set the display size of the object.
- * Mutate the object.
- *
- * @param {Phaser.GameObjects.GameObject} obj object to be set
- * @param {number} x new display width size
- * @param {number} y new display height size
- * @returns {Phaser.GameObjects.GameObject} game object itself
- */
- function set_display_size(obj, x, y) {
- if (is_any_type(obj, obj_types)) {
- get_obj(obj).setDisplaySize(x, y);
- return obj;
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- /**
- * Set the alpha of the object.
- * Mutate the object.
- *
- * @param {Phaser.GameObjects.GameObject} obj object to be set
- * @param {number} alpha new alpha
- * @returns {Phaser.GameObjects.GameObject} game object itself
- */
- function set_alpha(obj, alpha) {
- if (is_any_type(obj, obj_types)) {
- get_obj(obj).setAlpha(alpha);
- return obj;
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- /**
- * Set the interactivity of the object.
- * Mutate the object.
- *
- * Rectangle and Ellipse are not able to receive configs, only boolean
- * i.e. set_interactive(rect, true); set_interactive(ellipse, false)
- *
- * @param {Phaser.GameObjects.GameObject} obj object to be set
- * @param {config} config interactive config to be used
- * @returns {Phaser.GameObjects.GameObject} game object itself
- */
- function set_interactive(obj, config = {}) {
- if (is_any_type(obj, obj_types)) {
- get_obj(obj).setInteractive(config);
- return obj;
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- /**
- * Set the origin in which all position related will be relative to.
- * In other words, the anchor of the object.
- * Mutate the object.
- *
- * @param {Phaser.GameObjects.GameObject} obj object to be set
- * @param {number} x new anchor x coordinate, between value 0 to 1.
- * @param {number} y new anchor y coordinate, between value 0 to 1.
- * @returns {Phaser.GameObjects.GameObject} game object itself
- */
- function set_origin(obj, x, y) {
- if (is_any_type(obj, obj_types)) {
- get_obj(obj).setOrigin(x, y);
- return obj;
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
- /**
- * Set the position of the game object
- * Mutate the object
- *
- * @param {Phaser.GameObjects.Container} obj object to be set
- * @param {number} x new x position
- * @param {number} y new y position
- * @returns {Phaser.GameObjects.Container} game object itself
- */
- function set_position(obj, x, y) {
- if (obj && is_any_type(obj, obj_types)) {
- get_obj(obj).setPosition(x, y);
- return obj;
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- /**
- * Set the scale of the object.
- * Mutate the object.
- *
- * @param {Phaser.GameObjects.GameObject} obj object to be set
- * @param {number} x new x scale
- * @param {number} y new y scale
- * @returns {Phaser.GameObjects.GameObject} game object itself
- */
- function set_scale(obj, x, y) {
- if (is_any_type(obj, obj_types)) {
- get_obj(obj).setScale(x, y);
- return obj;
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- /**
- * Set the rotation of the object.
- * Mutate the object.
- *
- * @param {Phaser.GameObjects.GameObject} obj object to be set
- * @param {number} rad the rotation, in radians
- * @returns {Phaser.GameObjects.GameObject} game object itself
- */
- function set_rotation(obj, rad) {
- if (is_any_type(obj, obj_types)) {
- get_obj(obj).setRotation(rad);
- return obj;
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- /**
- * Sets the horizontal and flipped state of the object.
- * Mutate the object.
- *
- * @param {Phaser.GameObjects.GameObject} obj game object itself
- * @param {boolean} x to flip in the horizontal state
- * @param {boolean} y to flip in the vertical state
- * @returns {Phaser.GameObjects.GameObject} game object itself
- */
- function set_flip(obj, x, y) {
- if (is_any_type(obj, obj_types)) {
- get_obj(obj).setFlip(x, y);
- return obj;
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- /**
- * Create a tween to the object and plays it.
- * Mutate the object.
- *
- * @param {Phaser.GameObjects.GameObject} obj object to be added to
- * @param {config} config tween config
- * @returns {Phaser.GameObjects.GameObject} game object itself
- */
- async function add_tween(obj, config = {}) {
- if (is_any_type(obj, obj_types)) {
- scene.tweens.add({
- targets: get_obj(obj),
- ...config,
- });
- return obj;
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- ///////////////////////////
- // LISTENER //
- ///////////////////////////
-
- /**
- * Attach a listener to the object. The callback will be executed
- * when the event is emitted.
- * Mutate the object.
- *
- * For all available events, see:
- * https://photonstorm.github.io/phaser3-docs/Phaser.Input.Events.html
- *
- * @param {Phaser.GameObjects.Container} obj object to be added to
- * @param {string} event the event name
- * @param {Function} callback listener function, executed on event
- * @returns {Phaser.Input.InputPlugin} listener
- */
- function add_listener(obj, event, callback) {
- if (is_any_type(obj, obj_types)) {
- const listener = get_obj(obj).addListener(event, callback);
- return set_type(listener, input_plugin_type);
- } else {
- throw_error(`${obj} is not of type ${obj_types}`);
- }
- }
-
- /**
- * Attach a listener to the object. The callback will be executed
- * when the event is emitted.
- * Mutate the object.
- *
- * For all available events, see:
- * https://photonstorm.github.io/phaser3-docs/Phaser.Input.Events.html
- *
- * For list of keycodes, see:
- * https://github.com/photonstorm/phaser/blob/v3.22.0/src/input/keyboard/keys/KeyCodes.js
- *
- * @param {string | number} key keyboard key
- * @param {string} event
- * @param {Function} callback listener function, executed on event
- * @returns {Phaser.Input.Keyboard.Key} listener
- */
- function add_keyboard_listener(key, event, callback) {
- const key_obj = scene.input.keyboard.addKey(key);
- const keyboard_listener = key_obj.addListener(event, callback);
- return set_type(keyboard_listener, keyboard_key_type);
- }
-
- /**
- * Deactivate and remove listener.
- *
- * @param {Phaser.Input.InputPlugin | Phaser.Input.Keyboard.Key} listener
- */
- function remove_listener(listener) {
- if (is_any_type(listener, listener_types)) {
- get_obj(listener).removeAllListeners();
- return true;
- }
- return false;
- }
diff --git a/docs/lib/sound/microphone.js b/docs/lib/sound/microphone.js
deleted file mode 100644
index 5125c51c6..000000000
--- a/docs/lib/sound/microphone.js
+++ /dev/null
@@ -1,164 +0,0 @@
-// // ---------------------------------------------
-// // Microphone Functionality
-// // ---------------------------------------------
-
-// permission initially undefined
-// set to true by granting microphone permission
-// set to false by denying microphone permission
-let permission = undefined;
-
-let recorded_sound = undefined;
-
-// check_permission is called whenever we try
-// to record a sound
-function check_permission() {
- if (permission === undefined) {
- throw new Error("Call init_record(); " +
- "to obtain permission to use microphone");
- } else if (permission === false) {
- throw new Error("Permission has been denied.\n" +
- "Re-start browser and call init_record();\n" +
- "to obtain permission to use microphone.");
- } // (permission === true): do nothing
-}
-
-/**
- * Initialize recording by obtaining permission
- * to use the default device microphone
- * @returns {undefined}
- */
-function init_record(){
- navigator.mediaDevices.getUserMedia({ audio: true })
- .then(rememberStream, setPermissionToFalse);
- return "obtaining recording permission";
-}
-
-let globalStream;
-
-function rememberStream(stream) {
- permission = true;
- globalStream = stream;
-}
-
-function setPermissionToFalse() {
- permission = false;
-}
-
-function start_recording(mediaRecorder) {
- const data = [];
- mediaRecorder.ondataavailable = e => e.data.size && data.push(e.data);
- mediaRecorder.start();
- mediaRecorder.onstop = () => process(data);
-}
-
-// there is a beep signal at the beginning and end
-// of each recording
-const recording_signal_duration_ms = 300;
-
-function play_recording_signal() {
- play(sine_sound(500, recording_signal_duration_ms / 1000));
-}
-
-/**
- * takes a buffer
duration (in seconds) as argument, and
- * returns a nullary stop function stop
. A call
- * stop()
returns a sound promise: a nullary function
- * that returns a sound. Example:
init_record();
- * const stop = record(0.5);
- * // record after 0.5 seconds. Then in next query:
- * const promise = stop();
- * // In next query, you can play the promised sound, by
- * // applying the promise:
- * play(promise());
- * @param {number} buffer - pause before recording, in seconds
- * @returns {function} nullary stop
function;
- * stop()
stops the recording and
- * returns a sound promise: a nullary function that returns the recorded sound
- */
-function record(buffer) {
- check_permission();
- const mediaRecorder = new MediaRecorder(globalStream);
- play_recording_signal();
- setTimeout(() => {
- start_recording(mediaRecorder);
- }, recording_signal_duration_ms + buffer * 1000);
- return () => {
- mediaRecorder.stop();
- play_recording_signal();
- return () => {
- if (recorded_sound === undefined) {
- throw new Error("recording still being processed")
- } else {
- return recorded_sound;
- }
- };
- };
-}
-
-/**
- * Records a sound of given duration
in seconds, after
- * a buffer
also in seconds, and
- * returns a sound promise: a nullary function
- * that returns a sound. Example: init_record();
- * const promise = record_for(2, 0.5);
- * // In next query, you can play the promised sound, by
- * // applying the promise:
- * play(promise());
- * @param {number} duration - duration in seconds
- * @param {number} buffer - pause before recording, in seconds
- * @returns {function} promise
: nullary function which returns the recorded sound
- */
-function record_for(duration, buffer) {
- recorded_sound = undefined;
- const duration_ms = duration * 1000;
- check_permission();
- const mediaRecorder = new MediaRecorder(globalStream);
- play_recording_signal();
- setTimeout(() => {
- start_recording(mediaRecorder);
- setTimeout(() => {
- mediaRecorder.stop();
- play_recording_signal();
- }, duration_ms);
- }, recording_signal_duration_ms + buffer * 1000);
- return () => {
- if (recorded_sound === undefined) {
- throw new Error("recording still being processed")
- } else {
- return recorded_sound;
- }
- };
-}
-
-function process(data) {
- const audioContext = new AudioContext();
- const blob = new Blob(data);
-
- convertToArrayBuffer(blob)
- .then(arrayBuffer => audioContext.decodeAudioData(arrayBuffer))
- .then(save);
-}
-
-// Converts input microphone sound (blob) into array format.
-function convertToArrayBuffer(blob) {
- const url = URL.createObjectURL(blob);
-
- return fetch(url).then(response => {
- return response.arrayBuffer();
- });
-}
-
-function save(audioBuffer) {
- const array = audioBuffer.getChannelData(0);
- const duration = array.length / FS;
- recorded_sound =
- make_sound( t => {
- const index = t * FS
- const lowerIndex = Math.floor(index)
- const upperIndex = lowerIndex + 1
- const ratio = index - lowerIndex
- const upper = array[upperIndex] ? array[upperIndex] : 0
- const lower = array[lowerIndex] ? array[lowerIndex] : 0
- return lower * (1 - ratio) + upper * ratio
- }, duration);
-}
diff --git a/docs/lib/sound/riffwave.js b/docs/lib/sound/riffwave.js
deleted file mode 100644
index 8fcb42853..000000000
--- a/docs/lib/sound/riffwave.js
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * RIFFWAVE.js v0.03 - Audio encoder for HTML5 elements.
- * Copyleft 2011 by Pedro Ladaria
- *
- * Public Domain
- *
- * Changelog:
- *
- * 0.01 - First release
- * 0.02 - New faster base64 encoding
- * 0.03 - Support for 16bit samples
- *
- * Notes:
- *
- * 8 bit data is unsigned: 0..255
- * 16 bit data is signed: −32,768..32,767
- *
- */
-
-var FastBase64 = {
- chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
- encLookup: [],
-
- Init: function() {
- for (var i = 0; i < 4096; i++) {
- this.encLookup[i] = this.chars[i >> 6] + this.chars[i & 0x3f]
- }
- },
-
- Encode: function(src) {
- var len = src.length
- var dst = ''
- var i = 0
- while (len > 2) {
- n = (src[i] << 16) | (src[i + 1] << 8) | src[i + 2]
- dst += this.encLookup[n >> 12] + this.encLookup[n & 0xfff]
- len -= 3
- i += 3
- }
- if (len > 0) {
- var n1 = (src[i] & 0xfc) >> 2
- var n2 = (src[i] & 0x03) << 4
- if (len > 1) n2 |= (src[++i] & 0xf0) >> 4
- dst += this.chars[n1]
- dst += this.chars[n2]
- if (len == 2) {
- var n3 = (src[i++] & 0x0f) << 2
- n3 |= (src[i] & 0xc0) >> 6
- dst += this.chars[n3]
- }
- if (len == 1) dst += '='
- dst += '='
- }
- return dst
- } // end Encode
-}
-
-FastBase64.Init()
-
-var RIFFWAVE = function(data) {
- this.data = [] // Array containing audio samples
- this.wav = [] // Array containing the generated wave file
- this.dataURI = '' // http://en.wikipedia.org/wiki/Data_URI_scheme
-
- this.header = {
- // OFFS SIZE NOTES
- chunkId: [0x52, 0x49, 0x46, 0x46], // 0 4 "RIFF" = 0x52494646
- chunkSize: 0, // 4 4 36+SubChunk2Size = 4+(8+SubChunk1Size)+(8+SubChunk2Size)
- format: [0x57, 0x41, 0x56, 0x45], // 8 4 "WAVE" = 0x57415645
- subChunk1Id: [0x66, 0x6d, 0x74, 0x20], // 12 4 "fmt " = 0x666d7420
- subChunk1Size: 16, // 16 4 16 for PCM
- audioFormat: 1, // 20 2 PCM = 1
- numChannels: 1, // 22 2 Mono = 1, Stereo = 2...
- sampleRate: 8000, // 24 4 8000, 44100...
- byteRate: 0, // 28 4 SampleRate*NumChannels*BitsPerSample/8
- blockAlign: 0, // 32 2 NumChannels*BitsPerSample/8
- bitsPerSample: 8, // 34 2 8 bits = 8, 16 bits = 16
- subChunk2Id: [0x64, 0x61, 0x74, 0x61], // 36 4 "data" = 0x64617461
- subChunk2Size: 0 // 40 4 data size = NumSamples*NumChannels*BitsPerSample/8
- }
-
- function u32ToArray(i) {
- return [i & 0xff, (i >> 8) & 0xff, (i >> 16) & 0xff, (i >> 24) & 0xff]
- }
-
- function u16ToArray(i) {
- return [i & 0xff, (i >> 8) & 0xff]
- }
-
- function split16bitArray(data) {
- var r = []
- var j = 0
- var len = data.length
- for (var i = 0; i < len; i++) {
- r[j++] = data[i] & 0xff
- r[j++] = (data[i] >> 8) & 0xff
- }
- return r
- }
-
- this.Make = function(data) {
- if (data instanceof Array) this.data = data
- this.header.blockAlign = (this.header.numChannels * this.header.bitsPerSample) >> 3
- this.header.byteRate = this.header.blockAlign * this.sampleRate
- this.header.subChunk2Size = this.data.length * (this.header.bitsPerSample >> 3)
- this.header.chunkSize = 36 + this.header.subChunk2Size
-
- this.wav = this.header.chunkId.concat(
- u32ToArray(this.header.chunkSize),
- this.header.format,
- this.header.subChunk1Id,
- u32ToArray(this.header.subChunk1Size),
- u16ToArray(this.header.audioFormat),
- u16ToArray(this.header.numChannels),
- u32ToArray(this.header.sampleRate),
- u32ToArray(this.header.byteRate),
- u16ToArray(this.header.blockAlign),
- u16ToArray(this.header.bitsPerSample),
- this.header.subChunk2Id,
- u32ToArray(this.header.subChunk2Size),
- this.header.bitsPerSample == 16 ? split16bitArray(this.data) : this.data
- )
- this.dataURI = 'data:audio/wav;base64,' + FastBase64.Encode(this.wav)
- }
-
- if (data instanceof Array) this.Make(data)
-} // end RIFFWAVE
diff --git a/docs/lib/sound/soundToneMatrix.js b/docs/lib/sound/soundToneMatrix.js
deleted file mode 100644
index f5b52e10e..000000000
--- a/docs/lib/sound/soundToneMatrix.js
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- Support for CS1101S Mission 15
- Sound mission - Tone Matrix
-
- Author:
- v1 (2014/2015) Su Xuan - September 2014
-
- Modifier:
- v2 (2016/2017) Xiao Pu - September 2016 - fit source academy IDE
-*/
-
-var $tone_matrix; // canvas container for tone matrix
-
-var color_white = "#ffffff"; // color of the highlighted square
-var color_white_2 = "#666666"; // color of the adjacent squares
-var color_white_3 = "#444444"; // color of the squares that are two units from the highlighted square
-var color_on = "#cccccc";
-var color_off = "#333333";
-
-// the side length of the squares in the matrix
-var square_side_length = 18;
-
-// the distance between two adjacent squares in the matrix
-var distance_between_squares = 6;
-
-// margin of the canvas
-var margin_length = 20;
-
-// the duration for playing one grid is 0.5s
-var grid_duration = 0.5;
-// but the duration for playing one entire sound is 1 (which means there will be reverberations)
-var sound_duration = 1;
-
-// for playing the tone matrix repeatedly in play_matrix_continuously function
-var timeout_matrix;
-// for coloring the matrix accordingly while it's being played
-var timeout_color;
-
-var timeout_objects = new Array();
-
-// given the x, y coordinates of a "click" event
-// return the row and column numbers of the clicked square
-function x_y_to_row_column(x, y) {
- var row = Math.floor((y - margin_length) / (square_side_length + distance_between_squares));
- var column = Math.floor((x - margin_length) / (square_side_length + distance_between_squares));
- return Array(row, column);
-}
-
-// given the row number of a square, return the leftmost coordinate
-function row_to_y(row) {
- return margin_length + row * (square_side_length + distance_between_squares);
-}
-
-// given the column number of a square, return the topmost coordinate
-function column_to_x(column) {
- return margin_length + column * (square_side_length + distance_between_squares);
-}
-
-// return a list representing a particular row
-function get_row(row) {
- return vector_to_list(matrix[row]);
-}
-
-// return a list representing a particular column
-function get_column(column) {
- var result = new Array(16);
- for (var i = 15; i >= 0; i--) {
- result[i] = matrix[i][column];
- };
- return vector_to_list(result);
-}
-
-function is_on(row, column) {
- if (row < 0 || row > 15 || column < 0 || column > 15) {
- return;
- }
-
- return matrix[row][column];
-}
-
-// set the color of a particular square
-function set_color(row, column, color) {
- if (row < 0 || row > 15 || column < 0 || column > 15) {
- return;
- }
-
- var ctx = $tone_matrix.getContext("2d");
- ctx.fillStyle = color;
-
- ctx.fillRect(column_to_x(column),
- row_to_y(row),
- square_side_length,
- square_side_length);
-}
-
-// highlight a given square
-function highlight_color(row, column, color) {
- set_color(row, column, color);
-}
-
-// given the square that we are supposed to highlight, color the neighboring squares
-function set_adjacent_color_1(row, column, color) {
- if (!is_on(row, column - 1)) {
- set_color(row, column - 1, color);
- }
-
- if (!is_on(row, column + 1)) {
- set_color(row, column + 1, color);
- }
-
- if (!is_on(row - 1, column)) {
- set_color(row - 1, column, color);
- }
-
- if (!is_on(row + 1, column)) {
- set_color(row + 1, column, color);
- }
-}
-
-// given the square that we are supposed to highlight, color the squares 2 units from it
-function set_adjacent_color_2(row, column, color) {
- if (!is_on(row, column - 2)) {
- set_color(row, column - 2, color);
- }
-
- if (!is_on(row + 1, column - 1)) {
- set_color(row + 1, column - 1, color);
- }
-
- if (!is_on(row + 2, column)) {
- set_color(row + 2, column, color);
- }
-
- if (!is_on(row + 1, column + 1)) {
- set_color(row + 1, column + 1, color);
- }
-
- if (!is_on(row, column + 2)) {
- set_color(row, column + 2, color);
- }
-
- if (!is_on(row - 1, column + 1)) {
- set_color(row - 1, column + 1, color);
- }
-
- if (!is_on(row - 2, column)) {
- set_color(row - 2, column, color);
- }
-
- if (!is_on(row - 1, column - 1)) {
- set_color(row - 1, column - 1, color);
- }
-}
-
-// redraw a matrix according to the current state of the matrix
-function redraw_matrix() {
- for (var i = 15; i >= 0; i--) {
- for (var j = 15; j >= 0; j--) {
- if (matrix[i][j]) {
- set_color(i, j, color_on);
- } else {
- set_color(i, j, color_off);
- }
- };
- };
-}
-
-var ToneMatrix = {};
-
-function initialise_matrix($container) {
- if (!$tone_matrix) {
- $tone_matrix = document.createElement('canvas');
- $tone_matrix.width = 420;
- $tone_matrix.height = 420;
- // the array representing the configuration of the matrix
- matrix = new Array(16);
-
- // the visualisation of the matrix itself
- var ctx = $tone_matrix.getContext("2d");
-
- // draw the initial matrix
- for (var i = 15; i >= 0; i--) {
- matrix[i] = new Array(16);
- for (var j = 15; j >= 0; j--) {
- set_color(i, j, color_off);
- matrix[i][j] = false;
- };
- };
-
- bind_events_to_rect($tone_matrix);
- }
- $tone_matrix.hidden = false
- $container.appendChild($tone_matrix)
-}
-ToneMatrix.initialise_matrix = initialise_matrix;
-
-// bind the click events to the matrix
-function bind_events_to_rect(c) {
- c.addEventListener('click', function (event) {
- // calculate the x, y coordinates of the click event
- var offset_left = $(this).offset().left;
- var offset_top = $(this).offset().top;
- var x = event.pageX - offset_left;
- var y = event.pageY - offset_top;
-
- // obtain the row and column numbers of the square clicked
- var row_column = x_y_to_row_column(x, y);
- var row = row_column[0];
- var column = row_column[1];
-
- if (row < 0 || row > 15 || column < 0 || column > 15) {
- return;
- }
-
- if (matrix[row][column] == undefined || !matrix[row][column]) {
- matrix[row][column] = true;
- set_color(row, column, color_on);
- } else {
- matrix[row][column] = false;
- set_color(row, column, color_off);
- }
- }, false);
-}
-
-function random_animate() {
- for (var i = 5; i >= 0; i--) {
- var row = Math.floor(Math.random() * 16);
- var column = Math.floor(Math.random() * 16);
- if (!is_on(row, column)) {
- set_color(row, column, color_white_3);
- }
- };
-
- for (var i = 10; i >= 0; i--) {
- var row = Math.floor(Math.random() * 16);
- var column = Math.floor(Math.random() * 16);
- if (!is_on(row, column)) {
- set_color(row, column, color_off);
- }
- };
-}
-
-function animate_column(n) {
- if (n < 0 || n > 15) {
- return;
- }
-
- var column = list_to_vector(get_column(n));
-
- for (var j = 0; j <= 15; j++) {
- if (column[j]) {
- // if a particular square is clicked, highlight itself
- // and the neighboring squares in the animation
- highlight_color(j, n, color_white);
- set_adjacent_color_1(j, n, color_white_2);
- set_adjacent_color_2(j, n, color_white_3);
- }
- };
-}
-
-function unanimate_column(n) {
- if (n < 0 || n > 15) {
- return;
- }
-
- var column = list_to_vector(get_column(n));
-
- for (var j = 0; j <= 15; j++) {
- if (column[j]) {
- highlight_color(j, n, color_on);
- set_adjacent_color_1(j, n, color_off);
- set_adjacent_color_2(j, n, color_off);
- }
- };
-}
-
-// generate a randomised matrix
-function randomise_matrix() {
- var ctx = $tone_matrix.getContext("2d");
- var on; // the square in the matrix is on or off
-
- clear_matrix();
- // draw the randomised matrix
- for (var i = 15; i >= 0; i--) {
- for (var j = 15; j >= 0; j--) {
- on = Math.random() > 0.9;
- if (on) {
- set_color(i, j, color_on);
- matrix[i][j] = true;
- } else {
- set_color(i, j, color_off);
- matrix[i][j] = false;
- }
- };
- };
-}
-ToneMatrix.randomise_matrix = randomise_matrix;
-
-function bindMatrixButtons() {
- $("#clear-matrix").on("click", function () {
- clear_matrix();
- // stop_matrix();
- $("#play-matrix").attr("value", "Play");
- });
-
- // $("#play-matrix").on("click", function () {
- // if ($(this).attr("value") == "Play") {
- // $(this).attr("value", "Stop");
- // play_matrix_continuously();
- // } else {
- // $(this).attr("value", "Play");
- // // stop_matrix();
- // redraw_matrix();
- // }
- // });
-
- // $("#random-matrix").on("click", function () {
- // randomise_matrix();
- // });
-};
-ToneMatrix.bindMatrixButtons = bindMatrixButtons;
-
-// ********** THE FOLLOWING FUNCTIONS ARE EXPOSED TO STUDENTS **********
-// return the current state of the matrix, represented by a list of lists of bits
-function get_matrix() {
- if (!matrix) {
- throw new Error("Please activate the tone matrix first by clicking on the tab!")
- }
- var matrix_list = matrix.slice(0);
- var result = [];
- for (var i = 0; i <= 15; i++) {
- result[i] = vector_to_list(matrix_list[15 - i]);
- };
-
- return vector_to_list(result);
-}
-
-// reset the matrix to the initial state
-function clear_matrix() {
- matrix = new Array(16);
- var ctx = $tone_matrix.getContext("2d");
-
- // draw the initial matrix
- for (var i = 15; i >= 0; i--) {
- matrix[i] = new Array(16);
- for (var j = 15; j >= 0; j--) {
- set_color(i, j, color_off);
- matrix[i][j] = false;
- };
- };
-}
-
-ToneMatrix.clear_matrix = clear_matrix;
-
-var set_time_out_renamed = window.setTimeout;
-
-function set_timeout(f, t) {
- var timeoutObj = set_time_out_renamed(f, t);
- timeout_objects.push(timeoutObj);
-}
-
-function clear_all_timeout() {
- for (var i = timeout_objects.length - 1; i >= 0; i--) {
- clearTimeout(timeout_objects[i]);
- };
-
- timeout_objects = new Array();
-}
-
-// functions from mission 14
-function letter_name_to_midi_note(note) {
- // we don't consider double flat/ double sharp
- var note = note.split("");
- var res = 12; //MIDI notes for mysterious C0
- var n = note[0].toUpperCase();
- switch (n) {
- case 'D':
- res = res + 2;
- break;
-
- case 'E':
- res = res + 4;
- break;
-
- case 'F':
- res = res + 5;
- break;
-
- case 'G':
- res = res + 7;
- break;
-
- case 'A':
- res = res + 9;
- break;
-
- case 'B':
- res = res + 11;
- break;
-
- default:
- break;
- }
-
- if (note.length === 2) {
- res = parseInt(note[1]) * 12 + res;
- } else if (note.length === 3) {
- switch (note[1]) {
- case '#':
- res = res + 1;
- break;
-
- case 'b':
- res = res - 1;
- break;
-
- default:
- break;
- }
- res = parseInt(note[2]) * 12 + res;
- }
-
- return res;
-}
-
-function letter_name_to_frequency(note) {
- return midi_note_to_frequency(note_to_midi_note(note));
-}
-
-function midi_note_to_frequency(note) {
- return 8.1757989156 * Math.pow(2, (note / 12));
-}
-
-function linear_decay(decay_period) {
- return function (t) {
- if ((t > decay_period) || (t < 0)) {
- return 0;
- } else {
- return 1 - (t / decay_period);
- }
- }
-}
-
-/**
- * Returns an envelope: a function from Sound to Sound.
- * When the envelope is applied to a Sound, it returns
- * a new Sound that results from applying ADSR to
- * the given Sound. The Attack, Sustain and
- * Release ratios are given in the first, second and fourth
- * arguments, and the Sustain level is given in
- * the third argument as a fraction between 0 and 1.
- * @param {Number} attack_ratio - proportion of Sound in attack phase
- * @param {Number} decay_ratio - proportion of Sound decay phase
- * @param {Number} sustain_level - sustain level between 0 and 1
- * @param {Number} release_ratio - proportion of Sound release phase
- * @returns {function} envelope: function from Sound to Sound
- */
-function adsr(attack_ratio, decay_ratio, sustain_level, release_ratio) {
- return sound => {
- var wave = get_wave(sound);
- var duration = get_duration(sound);
- var attack_time = duration * attack_ratio;
- var decay_time = duration * decay_ratio;
- var release_time = duration * release_ratio;
- return make_sound( x => {
- if (x < attack_time) {
- return wave(x) * (x / attack_time);
- } else if (x < attack_time + decay_time) {
- return ((1 - sustain_level) * (linear_decay(decay_time))(x - attack_time) + sustain_level) * wave(x);
- } else if (x < duration - release_time) {
- return wave(x) * sustain_level;
- } else if (x <= duration) {
- return wave(x) * sustain_level * (linear_decay(release_time))(x - (duration - release_time));
- } else {
- return 0;
- }
- }, duration);
- };
-}
-
-// waveform is a function that accepts freq, dur and returns Sound
-/**
- * Returns a Sound that results from applying a list of envelopes
- * to a given wave form. The wave form should be a Sound generator that
- * takes a frequency and a duration as arguments and produces a
- * Sound with the given frequency and duration. Each envelope is
- * applied to a harmonic: the first harmonic has the given frequency,
- * the second has twice the frequency, the third three times the
- * frequency etc.
- * @param {function} waveform - function from frequency and duration to Sound
- * @param {Number} base_frequency - frequency of the first harmonic
- * @param {Number} duration - duration of the produced Sound, in seconds
- * @param {list_of_envelope} envelopes - each a function from Sound to Sound
- * @returns {Sound} resulting Sound
- */
-function stacking_adsr(waveform, base_frequency, duration, envelopes) {
- function zip(lst, n) {
- if (is_null(lst)) {
- return lst;
- } else {
- return pair(pair(n, head(lst)), zip(tail(lst), n + 1));
- }
- }
-
- return simultaneously(accumulate(
- (x, y) => pair((tail(x))
- (waveform(base_frequency * head(x), duration))
- , y)
- , null
- , zip(envelopes, 1)));
-}
-
-// instruments for students
-
-/**
- * returns a Sound that is reminiscent of a trombone, playing
- * a given note for a given duration
of seconds
- * @param {Number} note - midi note
- * @param {Number} duration - duration in seconds
- * @returns {Sound} resulting trombone Sound with given given pitch and duration
- */
-function trombone(note, duration) {
- return stacking_adsr(square_sound, midi_note_to_frequency(note), duration,
- list(adsr(0.2, 0, 1, 0.1),
- adsr(0.3236, 0.6, 0, 0.1)));
-}
-
-/**
- * returns a Sound that is reminiscent of a piano, playing
- * a given note for a given duration
of seconds
- * @param {Number} note - midi note
- * @param {Number} duration - duration in seconds
- * @returns {Sound} resulting piano Sound with given given pitch and duration
- */
-function piano(note, duration) {
- return stacking_adsr(triangle_sound, midi_note_to_frequency(note), duration,
- list(adsr(0, 0.515, 0, 0.05),
- adsr(0, 0.32, 0, 0.05),
- adsr(0, 0.2, 0, 0.05)));
-}
-
-/**
- * returns a Sound that is reminiscent of a bell, playing
- * a given note for a given duration
of seconds
- * @param {Number} note - midi note
- * @param {Number} duration - duration in seconds
- * @returns {Sound} resulting bell Sound with given given pitch and duration
- */
-function bell(note, duration) {
- return stacking_adsr(square_sound, midi_note_to_frequency(note), duration,
- list(adsr(0, 0.6, 0, 0.05),
- adsr(0, 0.6618, 0, 0.05),
- adsr(0, 0.7618, 0, 0.05),
- adsr(0, 0.9071, 0, 0.05)));
-}
-
-/**
- * returns a Sound that is reminiscent of a violin, playing
- * a given note for a given duration
of seconds
- * @param {Number} note - midi note
- * @param {Number} duration - duration in seconds
- * @returns {Sound} resulting violin Sound with given given pitch and duration
- */
-function violin(note, duration) {
- return stacking_adsr(sawtooth_sound, midi_note_to_frequency(note), duration,
- list(adsr(0.35, 0, 1, 0.15),
- adsr(0.35, 0, 1, 0.15),
- adsr(0.45, 0, 1, 0.15),
- adsr(0.45, 0, 1, 0.15)));
-}
-
-/**
- * returns a Sound that is reminiscent of a cello, playing
- * a given note for a given duration
of seconds
- * @param {Number} note - midi note
- * @param {Number} duration - duration in seconds
- * @returns {Sound} resulting cello Sound with given given pitch and duration
- */
-function cello(note, duration) {
- return stacking_adsr(square_sound, midi_note_to_frequency(note), duration,
- list(adsr(0.05, 0, 1, 0.1),
- adsr(0.05, 0, 1, 0.15),
- adsr(0, 0, 0.2, 0.15)));
-}
-
-function string_to_list_of_numbers(string) {
- var array_of_numbers = string.split("");
- return map(function (x) {
- return parseInt(x);
- }, vector_to_list(array_of_numbers));
-}
diff --git a/docs/lib/sound/sounds.js b/docs/lib/sound/sounds.js
deleted file mode 100644
index 6140a3c85..000000000
--- a/docs/lib/sound/sounds.js
+++ /dev/null
@@ -1,588 +0,0 @@
-// Constants
-var FS = 44100; // Standard sampling rate for all problems
-
-const fourier_expansion_level = 5; // expansion level for
- // square, sawtooth, triangle
-
-// ---------------------------------------------
-// Fast reimplementations of the list library
-// ---------------------------------------------
-
-function append(xs, ys) {
- var v1 = list_to_vector(xs);
- var v2 = list_to_vector(ys);
- var vector = v1.concat(v2);
- return vector_to_list(vector);
-}
-
-function map(f, xs) {
- var vector = list_to_vector(xs);
- for (var i=0; i duration) {
- for (var i = elapsed_duration * FS; i < duration * FS; i++) {
- data[i - elapsed_duration * FS] = wave(i / FS);
- }
- return data;
- } else if (duration - elapsed_duration > 0) {
- for (var i = elapsed_duration * FS;
- i < (elapsed_duration + sample_length) * FS;
- i++) {
- data[i - elapsed_duration * FS] = wave(i / FS);
- }
- return data;
- }
-}
-
-// Quantize real amplitude values into standard 4-bit PCM levels
-function quantize(data) {
- for (var i = 0; i < data.length; i++) {
- data[i] = Math.round((data[i] + 1) * 126);
- }
- return data;
-}
-
-// Try to eliminate clicks by smoothening out sudden jumps at the end of a wave
-function simple_filter(data) {
- for (var i = 0; i < data.length; i++) {
- if (data[i] > 1) {
- data[i] = 1;
- }
- if (data[i] < -1) {
- data[i] = -1;
- }
- }
- var old_value = 0;
- for (var i = 0; i < data.length; i++) {
- if (Math.abs(old_value - data[i]) > 0.01 && data[i] == 0) {
- data[i] = old_value * 0.999;
- }
- old_value = data[i];
- }
- return data;
-}
-
-function copy(data) {
- var ret = [];
- for (var i = 0; i < data.length; i++) {
- ret[i] = data[i];
- }
- return ret;
-}
-
-// Raw data to html5 audio element
-function raw_to_audio(_data) {
- data = copy(_data);
- data = simple_filter(data);
- data = quantize(data);
- var riffwave = new RIFFWAVE();
- riffwave.header.sampleRate = FS;
- riffwave.header.numChannels = 1;
- riffwave.Make(data);
- var audio = new Audio(riffwave.dataURI);
- return audio;
-}
-
-// ---------------------------------------------
-// Source API for Students
-// ---------------------------------------------
-
-// Data abstractions:
-// time: real value in seconds x > 0
-// amplitude: real value -1 <= x <= 1
-// duration: real value in seconds 0 < x < Infinity
-// sound: (time -> amplitude) x duration
-
-/**
- * Makes a Sound from a wave and a duration.
- * The wave is a function from a nonnegative time (in seconds)
- * to an amplitude value that should lie between
- * -1 and 1. The duration is given in seconds.
- * @param {function} wave - given wave function
- * @param {Number} duration - in seconds
- * @returns {Sound}
- */
-function make_sound(wave, duration) {
- return pair(t => t >= duration ? 0 : wave(t), duration);
-}
-
-/**
- * Accesses the wave of a Sound.
- * The wave is a function from a nonnegative time (in seconds)
- * to an amplitude value that should lie between
- * -1 and 1.
- * @param {Sound} sound - given sound
- * @returns {function} wave function of the sound
- */
-function get_wave(sound) {
- return head(sound);
-}
-
-/**
- * Accesses the duration of a Sound, in seconds.
- * @param {Sound} sound - given Sound
- * @returns {Number} duration in seconds
- */
-function get_duration(sound) {
- return tail(sound);
-}
-
-/**
- * Checks if a given value is a Sound
- * @param {value} x - given value
- * @returns {boolean} whether x
is a Sound
- */
-function is_sound(x) {
- return is_pair(x) &&
- ((typeof get_wave(x)) === 'function') &&
- ((typeof get_duration(x)) === 'number');
-}
-
-// Keeps track of whether play() is currently running,
-// and the current audio context.
-var _playing = false;
-var _player;
-
-function play_unsafe(sound) {
- // type-check sound
- if ( !is_sound(sound) ) {
- throw new Error("play is expecting sound, but encountered " + sound);
- // If a sound is already playing, terminate execution
- } else if (_playing || _safeplaying) {
- throw new Error("play: audio system still playing previous sound");
- } else if (get_duration(sound) <= 0) {
- return sound;
- } else {
- // Declaring duration and wave variables
- var wave = get_wave(sound);
- var duration = get_duration(sound);
-
- _playing = true;
-
- // Create AudioContext (test this out might fix safari issue)
- //const AudioContext = window.AudioContext || window.webkitAudioContext;
-
- // Main audio context
- _player = new AudioContext();
-
- // Controls Length of buffer in seconds.
- var buffer_length = 0.1;
-
- // Define Buffer Size
- var bufferSize = FS * buffer_length;
-
- // Create two buffers
- var buffer1 = _player.createBuffer(1, bufferSize, FS);
- var buffer2 = _player.createBuffer(1, bufferSize, FS);
-
- // Keep track of elapsed_duration & first run of ping_pong
- var elapsed_duration = 0;
- var first_run = true;
-
- // Schedules playback of sounds
- function ping_pong(current_sound, next_sound, current_buffer, next_buffer) {
- // If sound has exceeded duration, early return to stop calls.
- if (elapsed_duration > duration || !_playing) {
- stop();
- return;
- }
-
- // Fill current_buffer, then play current_sound.
- if (first_run) {
- // No longer first run of ping_pong.
- first_run = false;
-
- // Discretize first chunk, load into current_buffer.
- let current_data = current_buffer.getChannelData(0);
- current_data = discretize_from(wave, duration, elapsed_duration,
- buffer_length, current_data);
-
- // Create current_sound.
- current_sound = new AudioBufferSourceNode(_player);
-
- // Set current_sound's buffer to current_buffer.
- current_sound.buffer = current_buffer;
-
- // Play current_sound.
- current_sound.connect(_player.destination);
- current_sound.start();
-
- // Increment elapsed duration.
- elapsed_duration += buffer_length;
- }
-
- // Fill next_buffer while current_sound is playing,
- // schedule next_sound to play after current_sound terminates.
-
- // Discretize next chunk, load into next_buffer.
- let next_data = next_buffer.getChannelData(0);
- next_data = discretize_from(wave, duration, elapsed_duration,
- buffer_length, next_data);
-
- // Create next_sound.
- next_sound = new AudioBufferSourceNode(_player);
-
- // Set next_sound's buffer to next_buffer.
- next_sound.buffer = next_buffer;
-
- // Schedule next_sound to play after current_sound.
- next_sound.connect(_player.destination);
- next_sound.start(start_time + elapsed_duration);
-
- // Increment elapsed duration.
- elapsed_duration += buffer_length;
-
- current_sound.onended =
- event =>
- ping_pong(next_sound, current_sound, next_buffer, current_buffer);
- }
- var start_time = _player.currentTime;
- ping_pong(null, null, buffer1, buffer2);
- return sound;
- }
-}
-
-// "Safe" playing for overly complex sounds.
-// Discretizes full sound before playing
-// (i.e. plays sound properly, but possibly with
-// a delay).
-var _safeplaying = false;
-var _safeaudio = null;
-
-/**
- * plays a given Sound using your computer's sound device
- * @param {Sound} sound - given Sound
- * @returns {Sound} given Sound
- */
-function play(sound) {
- // If a sound is already playing, terminate execution.
- if (_safeplaying || _playing) {
- throw new Error("play: audio system still playing previous sound");
- } else if (get_duration(sound) <= 0) {
- return sound;
- } else {
- // Discretize the input sound
- var data = discretize(get_wave(sound), get_duration(sound));
- _safeaudio = raw_to_audio(data);
-
- _safeaudio.addEventListener('ended', stop);
- _safeaudio.play();
- _safeplaying = true;
- return sound;
- }
-}
-
-// Requires 'All' libraries!
-function display_waveform(num_points_per_second, sound) {
- let wave = get_wave(sound);
- let duration = get_duration(sound);
- let num_points = num_points_per_second * duration;
- return draw_connected_full_view_proportional(num_points)(t => pair(t, wave(duration * t)));
-}
-
-/* sound_to_string and string_to_sound would be really cool!!!
-
-function sound_to_string(sound) {
- let discretized_wave = discretize(wave(sound), duration(sound));
- let discretized_sound = pair(discretized_wave, duration(sound));
- return stringify(pair(data), tail(sound));
-}
-
-function string_to_sound(str) {
- var discretized_sound = eval(str);
-
- return pair(t => ..., duration(data));
-}
-*/
-
-/**
- * Stops playing the current sound
- * @returns {undefined} undefined
- */
-function stop() {
- // If using normal play()
- if (_playing) {
- _player.close();
- }
- // If using play_safe()
- if (_safeplaying) {
- _safeaudio.pause();
- _safeaudio = null;
- }
- _playing = false;
- _safeplaying = false;
-}
-
-// Concats a list of sounds
-/**
- * makes a new sound by combining the sounds in a given
- * list so that
- * they are arranged consecutively. Let us say the durations
- * of the sounds are d1
, ..., dn
and the wave
- * functions are w1
, ..., wn
. Then the resulting
- * sound has the duration of the sum of d1
, ..., dn
.
- * The wave function w
of the resulting sound uses w1
for the first
- * d1
seconds, w2
for the next
- * d2
seconds etc. We specify that w(d1) = w2(0)
,
- * w(d1+d2) = w3(0)
, etc
- * @param {list_of_sounds} sounds - given list of sounds
- * @returns {Sound} resulting sound
- */
-function consecutively(list_of_sounds) {
- function consec_two(ss1, ss2) {
- var wave1 = head(ss1);
- var wave2 = head(ss2);
- var dur1 = tail(ss1);
- var dur2 = tail(ss2);
- var new_wave = t => t < dur1 ? wave1(t) : wave2(t - dur1);
- return pair(new_wave, dur1 + dur2);
- }
- return accumulate(consec_two, silence_sound(0), list_of_sounds);
-}
-
-// Mushes a list of sounds together
-/**
- * makes a new sound by combining the sounds in a given
- * list so that
- * they play simutaneously, all starting at the beginning of the
- * resulting sound
- * @param {list_of_sounds} sounds - given list of sounds
- * @returns {Sound} resulting sound
- */
-function simultaneously(list_of_sounds) {
- function musher(ss1, ss2) {
- var wave1 = head(ss1);
- var wave2 = head(ss2);
- var dur1 = tail(ss1);
- var dur2 = tail(ss2);
- // new_wave assumes sound discipline (ie, wave(t) = 0 after t > dur)
- var new_wave = t => wave1(t) + wave2(t);
- // new_dur is higher of the two dur
- var new_dur = dur1 < dur2 ? dur2 : dur1;
- return pair(new_wave, new_dur);
- }
-
- var mushed_sounds = accumulate(musher, silence_sound(0), list_of_sounds);
- var normalised_wave = t =>
- (head(mushed_sounds))(t) / length(list_of_sounds);
- var highest_duration = tail(mushed_sounds);
- return pair(normalised_wave, highest_duration);
-}
-
-/**
- * makes a Sound of a given duration by randomly
- * generating amplitude values
- * @param {Number} duration - duration of result sound, in seconds
- * @returns {Sound} resulting noise sound
- */
-function noise_sound(duration) {
- return make_sound(t => Math.random() * 2 - 1, duration);
-}
-
-/**
- * makes a sine wave Sound with given frequency and a given duration
- * @param {Number} freq - frequency of result Sound, in Hz, freq
≥ 0
- * @param {Number} duration - duration of result Sound, in seconds
- * @returns {Sound} resulting sine Sound
- */
-function sine_sound(freq, duration) {
- return make_sound(t => Math.sin(2 * Math.PI * t * freq), duration);
-}
-
-/**
- * makes a silence Sound with a given duration
- * @param {Number} duration - duration of result Sound, in seconds
- * @returns {Sound} resulting silence Sound
- */
-function silence_sound(duration) {
- return make_sound(t => 0, duration);
-}
-
-// for mission 14
-
-/**
- * converts a letter name str
to corresponding midi note.
- * Examples for letter names are "A5"
, "B3"
, "D#4"
.
- * See mapping from
- * letter name to midi notes
- * @param {string} str - given letter name
- * @returns {Number} midi value of the corresponding note
- */
-function letter_name_to_midi_note(note) {
- // we don't consider double flat/ double sharp
- var note = note.split("");
- var res = 12; //MIDI notes for mysterious C0
- var n = note[0].toUpperCase();
- switch(n) {
- case 'D':
- res = res + 2;
- break;
-
- case 'E':
- res = res + 4;
- break;
-
- case 'F':
- res = res + 5;
- break;
-
- case 'G':
- res = res + 7;
- break;
-
- case 'A':
- res = res + 9;
- break;
-
- case 'B':
- res = res + 11;
- break;
-
- default :
- break;
- }
-
- if (note.length === 2) {
- res = parseInt(note[1]) * 12 + res;
- } else if (note.length === 3) {
- switch (note[1]) {
- case '#':
- res = res + 1;
- break;
-
- case 'b':
- res = res - 1;
- break;
-
- default:
- break;
- }
- res = parseInt(note[2]) * 12 + res;
- }
-
- return res;
-}
-
-
-/**
- * converts a letter name str
to corresponding frequency.
- * First converts str
to a note using letter_name_to_midi_note
- * and then to a frequency using midi_note_to_frequency
- * @param {string} str - given letter name
- * @returns {Number} frequency of corresponding note in Hz
- */
-function letter_name_to_frequency(note) {
- return midi_note_to_frequency(note_to_midi_note(note));
-}
-
-/**
- * converts a midi note n
to corresponding frequency.
- * The note is given as an integer Number.
- * @param {Number} n - given midi note
- * @returns {Number} frequency of the note in Hz
- */
-function midi_note_to_frequency(note) {
- return 8.1757989156 * Math.pow(2, (note / 12));
-}
-
-/**
- * makes a square wave Sound with given frequency and a given duration
- * @param {Number} freq - frequency of result Sound, in Hz, freq
≥ 0
- * @param {Number} duration - duration of result Sound, in seconds
- * @returns {Sound} resulting square Sound
- */
-function square_sound(freq, duration) {
- function fourier_expansion_square(t) {
- var answer = 0;
- for (var i = 1; i <= fourier_expansion_level; i++) {
- answer = answer +
- Math.sin(2 * Math.PI * (2 * i - 1) * freq * t)
- /
- (2 * i - 1);
- }
- return answer;
- }
- return make_sound(t =>
- (4 / Math.PI) * fourier_expansion_square(t),
- duration);
-}
-
-/**
- * makes a triangle wave Sound with given frequency and a given duration
- * @param {Number} freq - frequency of result Sound, in Hz, freq
≥ 0
- * @param {Number} duration - duration of result Sound, in seconds
- * @returns {Sound} resulting triangle Sound
- */
-function triangle_sound(freq, duration) {
- function fourier_expansion_triangle(t) {
- var answer = 0;
- for (var i = 0; i < fourier_expansion_level; i++) {
- answer = answer +
- Math.pow(-1, i) *
- Math.sin((2 * i + 1) * t * freq * Math.PI * 2)
- /
- Math.pow((2 * i + 1), 2);
- }
- return answer;
- }
- return make_sound(t =>
- (8 / Math.PI / Math.PI) * fourier_expansion_triangle(t),
- duration);
-}
-
-/**
- * makes a sawtooth wave Sound with given frequency and a given duration
- * @param {Number} freq - frequency of result Sound, in Hz; freq
≥ 0
- * @param {Number} duration - duration of result Sound, in seconds
- * @returns {Sound} resulting sawtooth Sound
- */
-function sawtooth_sound(freq, duration) {
- function fourier_expansion_sawtooth(t) {
- var answer = 0;
- for (var i = 1; i <= fourier_expansion_level; i++) {
- answer = answer + Math.sin(2 * Math.PI * i * freq * t) / i;
- }
- return answer;
- }
- return make_sound(t =>
- (1 / 2) - (1 / Math.PI) * fourier_expansion_sawtooth(t),
- duration);
-}
-
-/**
- * plays a given sound without regard if a sound is already playing
- * @param {sound} sound - given sound
- * @returns {undefined} undefined
- */
-function play_concurrently(sound) {
- // Discretize the input sound
- var data = discretize(get_wave(sound), get_duration(sound));
- _safeaudio = raw_to_audio(data);
-
- _safeaudio.addEventListener('ended', stop);
- _safeaudio.play();
- _safeplaying = true;
-}
diff --git a/docs/lib/tree.js b/docs/lib/tree.js
deleted file mode 100644
index 2e7df7746..000000000
--- a/docs/lib/tree.js
+++ /dev/null
@@ -1,80 +0,0 @@
-// tree.js: Binary Tree abstraction for M5
-// requires list.js
-
-// Authors: Joel Lee, Martin Henz
-
-/**
- * returns an empty binary tree, represented by the empty list null
- * @return {binary_tree} empty binary tree
- */
-
-function make_empty_tree() {
- return null
-}
-
-/**
- * checks whether a given value is a valid binary tree, according to the abstraction
- * @param {value} x - given value
- * @returns {boolean}
- */
-function is_tree(t) {
- return (
- is_empty_tree(t) ||
- (length(t) === 3 &&
- is_tree(left_branch(t)) &&
- is_tree(right_branch(t)))
- );
-}
-
-/**
- * returns a binary tree node composed of the
- * three components passed in
- * @param {value} val - value of the node
- * @param {binary_tree} left - left subtree
- * @param {binary_tree} right - right subtree
- * @returns {binary_tree}
- */
-function make_tree(value, left, right) {
- if (!is_tree(left)) {
- throw new Error('Left subtree is not a valid binary tree')
- } else if (!is_tree(right)) {
- throw new Error('Right subtree is not a valid binary tree')
- }
- return list(value, left, right)
-}
-
-/**
- * checks whether given binary tree t
is empty
- * @param {binary_tree} t - given binary tree
- * @returns {boolean}
- */
-function is_empty_tree(t) {
- return is_null(t)
-}
-
-/**
- * returns the value of a given binary tree
- * @param {binary_tree} t - given binary tree
- * @returns {value} value of t
- */
-function entry(t) {
- return list_ref(t, 0)
-}
-
-/**
- * returns the left branch of a given binary tree
- * @param {binary_tree} t - given binary tree
- * @returns {binary_tree} left branch of t
- */
-function left_branch(t) {
- return list_ref(t, 1)
-}
-
-/**
- * returns the right branch of a given binary tree
- * @param {binary_tree} t - given binary tree
- * @returns {binary_tree} right branch of t
- */
-function right_branch(t) {
- return list_ref(t, 2)
-}
diff --git a/docs/lib/video_lib.js b/docs/lib/video_lib.js
deleted file mode 100644
index 41c6dead0..000000000
--- a/docs/lib/video_lib.js
+++ /dev/null
@@ -1,423 +0,0 @@
-/* pixels
- * A pixel is an array with three numbers ranging from 0 to 255, representing
- * RGB values
- */
-
-/* no constructor: we simply use literal arrays to construct pixels,
- * as for example in
- * VD._SRCIMG[i][j] = [0,0,0];
- * VD._DESTIMG[i][j] = [0,0,0];
- * VD._TEMP[i][j] = [0,0,0];
- */
-
-/**
- * Returns the red component of a given Pixel px
- * @param {Pixel} px - given Pixel
- * @returns {Number} the red component as a number from 0 to 255
- */
-function red_of(px) { // returns the red value of px respectively
- return px[0];
-}
-
-/**
- * Returns the green component of a given Pixel px
- * @param {Pixel} px - given Pixel
- * @returns {Number} the green component as a number from 0 to 255
- */
-function green_of(px) { // returns the green value of px respectively
- return px[1];
-}
-
-/**
- * Returns the blue component of a given Pixel px
- * @param {Pixel} px - given Pixel
- * @returns {Number} the blue component as a number from 0 to 255
- */
-function blue_of(px) { // returns the blue value of px respectively
- return px[2];
-}
-
-/**
- * Returns the alpha component of a given Pixel px
- * @param {Pixel} px - given Pixel
- * @returns {Number} the alpha component as a number from 0 to 255
- */
-function alpha_of(px) { // returns the blue value of px respectively
- return px[3];
-}
-
-/**
- * Assigns the red, green, blue and alpha components of a Pixel
- * px
to given values
- * @param {Pixel} px - given Pixel
- * @param {Number} r - the red component as a number from 0 to 255
- * @param {Number} g - the green component as a number from 0 to 255
- * @param {Number} b - the blue component as a number from 0 to 255
- * @param {Number} a - the alpha component as a number from 0 to 255
- * @returns {undefined}
- */
-function set_rgba(px,r,g,b,a) { // assigns the r,g,b,a values to this px
- px[0] = r;
- px[1] = g;
- px[2] = b;
- px[3] = a;
-}
-
-/**
- * Filter that copies all Pixels faithfully from the
- * source Image src
to the destination Image dst
- * @param {Image} src - source Image
- * @param {Image} dst - destination Image
- * @returns {undefined}
- */
-function copy_image(src, dest) {
- for (let i=0; i<_WIDTH; i = i+1) {
- for (let j=0; j<_HEIGHT; j = j+1) {
- copy_pixel(src[i][j], dest[i][j]);
- }
- }
-}
-
-// returns a new filter that will have the effect of applying filter1 first and then filter2
-function compose_filter(filter1, filter2) {
- return (src, dest) => {
- filter1(src, dest);
- copy_image(dest, src);
- filter2(src, dest);
- };
-}
-
-// returns true if the absolute difference in red( and green and blue) value of px1 and px2
-// is smaller than the threshold value
-function pixel_similar(p1, p2, threshold) {
- return math_abs(p1[0] - p2[0]) < threshold &&
- math_abs(p1[1] - p2[1]) < threshold &&
- math_abs(p1[2] - p2[2]) < threshold;
-}
-
-var _WIDTH = 400;
-var _HEIGHT = 300;
-
-/**
- * Returns the current height of the output video display in
- * pixels, i.e. the number of pixels in vertical direction
- * @returns {Number} height of output display (in pixels)
- */
-function video_height() {
- return _HEIGHT;
-}
-
-/**
- * Returns the current width of the output video display in
- * pixels, i.e. the number of pixels in horizontal direction
- * @returns {Number} width of output display (in pixels)
- */
-function video_width() {
- return _WIDTH;
-}
-
-// changes the current filter to my_filter
-// default filter is copy_image
-/**
- * Installs a given Filter to be used to transform
- * the Images that the camera captures into Images
- * displayed on the screen. A Filter is a function
- * that is applied to two Images (2-D arrays
- * of Pixels): the source Image and the destination
- * Image.
- * @param {Filter} f - the Filter to be installed
- * @returns {undefined}
- */
-function install_filter(f) {
- VD._student_filter = f;
- if (!VD._video_playing) {
- VD.handleStart( () => {
- VD._draw_once();
- VD._noLoop();
- })
- }
-}
-
-/**
- * Resets the installed Filter back to the default Filter
- * @returns {undefined}
- */
-function reset_filter() {
- apply_filter(copy_image);
-}
-
-VD = {};
-VD._SRCIMG = [];
-VD._DESTIMG = [];
-VD._TEMP = [];
-VD._timeInCurrentFrame = 0;
-VD._student_filter = copy_image;
-VD._requestID = null;
-VD._pixelData = null;
-VD._video_playing = false;
-VD._video = null;
-VD._canvas = null;
-VD._context = null;
-
-VD._setup = function() {
- //create the two image arrays that will be used throughout
- for (let i=0; i<_WIDTH; i = i+1) {
- VD._SRCIMG[i] = [];
- VD._DESTIMG[i] = [];
- VD._TEMP[i] = [];
- for (let j=0; j<_HEIGHT; j = j+1) {
- VD._SRCIMG[i][j] = [0,0,0];
- VD._DESTIMG[i][j] = [0,0,0];
- VD._TEMP[i][j] = [0,0,0];
- }
- }
-}
-
-//load the data from the 1D array into the 2D array VD._SRCIMG
-VD._make_image_abstraction = function(arr) {
- for (let i=0; i<_WIDTH; i++) {
- for (let j=0; j<_HEIGHT; j++) {
- let pix = VD._SRCIMG[i][j];
- let red = (j * _WIDTH + i)*4;
- pix[0] = arr[red];
- pix[1] = arr[red + 1];
- pix[2] = arr[red + 2];
- }
- }
-}
-
-//load the data from the 2D array VD._DESTIMG into the 1D pixel array pixelData
-VD._make_pixelData = function(pixelData) {
- for (let i=0; i<_WIDTH; i++) {
- for (let j=0; j<_HEIGHT; j++) {
- let pix = VD._DESTIMG[i][j];
- let red = (j * _WIDTH + i)*4;
- pixelData.data[red] = pix[0];
- pixelData.data[red+1] = pix[1];
- pixelData.data[red+2] = pix[2];
- pixelData.data[red+3] = 255;
- }
- }
-}
-
-/*
- * draw one frame only
- */
-VD._draw_once = function() {
- VD._timeInCurrentFrame = Date.now();
-
- VD._context.drawImage(VD._video, 0, 0, _WIDTH, _HEIGHT);
- VD._pixelData = VD._context.getImageData(0, 0, _WIDTH, _HEIGHT);
-
- VD._make_image_abstraction(VD._pixelData.data);//from 1D to 2D
- VD._student_filter(VD._SRCIMG, VD._DESTIMG);//process the image
- VD._make_pixelData(VD._pixelData); //from 2D to 1D
- VD._context.putImageData(VD._pixelData, 0, 0);
-}
-
-/*
- * The main loop
- */
-VD._draw = function() {
- VD._requestID = window.requestAnimationFrame(VD._draw);
-
- VD._draw_once();
-
- // for debugging purposes
- // _frameNo++;
- // let timeSpent = Date.now() - VD._timeInCurrentFrame;
- // _sumTime += timeSpent;
- // console.log("Average: " + (_sumTime/_frameNo).toFixed(2) + " Current frame: " + timeSpent);
-};
-// let _frameNo = 0;
-// let _sumTime = 0;
-
-//stops the looping
-VD._noLoop = function() {
- if (VD._video_playing) {
- VD._video_playing = false;
- window.cancelAnimationFrame(VD._requestID);
- }
-
-}
-
-//starts the main loop
-VD._loop = function() {
- if (!VD._video_playing) {
- VD._video_playing = true;
- VD._requestID = window.requestAnimationFrame(VD._draw);
- }
-}
-
-VD.init = function($video, $canvas) {
- VD._video = $video;
- VD._canvas = $canvas;
- VD._context = VD._canvas.getContext('2d');
- VD._setup();
- VD.handleStartVideo();
-}
-
-VD.deinit = function() {
- VD._noLoop();
- VD._closeWebcam();
- VD._video = null;
- VD._canvas = null;
- VD._context = null;
-}
-
-VD._closeWebcam = function() {
- let stream = VD._video.srcObject;
- if (stream !== null) {
- let tracks = stream.getTracks();
- tracks.forEach((track) => {
- track.stop();
- });
- VD._video.srcObject = null;
- }
-}
-
-VD.handleCloseVideo = function() {
- VD._noLoop();
- VD._closeWebcam();
- VD._requestID = window.requestAnimationFrame(() => {
- VD._context.clearRect(0, 0, VD._canvas.width, VD._canvas.height);
- });
-}
-
-VD.handleStartVideo = function() {
- VD.handleStart( () => VD._loop() );
-}
-
-VD.handleSnapPicture = function() {
- VD.handleStart( () => {
- VD._draw_once();
- VD._noLoop();
- });
-}
-
-VD.handleStart = function(cont) {
- if (!VD._video.srcObject) {
- if (navigator.mediaDevices.getUserMedia) {
- navigator.mediaDevices.getUserMedia({ video: true })
- .then( stream => {
- VD._video.srcObject = stream;
- const afterVideoLoad = function(){
- VD._video.removeEventListener('loadeddata', afterVideoLoad);
- cont();
- }
- VD._video.addEventListener('loadeddata', afterVideoLoad);
- })
- .catch(function (err) {
- console.log(err); /* handle the error */
- if (err.name == "NotFoundError" ||
- err.name == "DevicesNotFoundError") {
- console.log("Devices not found: Check your camera");
- } else if (err.name == "NotReadableError" ||
- err.name == "TrackStartError") {
- console.log("webcam already in use");
- } else if (err.name == "OverconstrainedError" ||
- err.name == "ConstraintNotSatisfiedError") {
- console.log("constraints cannot be satisfied " +
- "by available devices");
- } else if (err.name == "NotAllowedError" ||
- err.name == "PermissionDeniedError") {
- console.log("permission denied in browser");
- } else if (err.name == "TypeError" || err.name == "TypeError") {
- console.log("empty constraints object");
- } else {
- }
- });
- } else {
- console.log('The browser you are using does not support getUserMedia');
- }
- } else {
- cont();
- }
-}
-
-VD.handleUpdateDimensions = function(w, h) {
- if (w === _WIDTH && h === _HEIGHT) { return; }
- _WIDTH = w;
- _HEIGHT = h;
- VD._video.width = w;
- VD._video.height = h;
- VD._canvas.width = w;
- VD._canvas.height = h;
-
- VD._setup();
- if (VD._video_playing) {
- VD._loop();
- } else {
- setTimeout(() => VD.handleSnapPicture(), 50);
- }
-}
-
-/* run this in playground for testing
-
-
-// upside-down
-
-
-function upside_down(src, dest) {
- const WIDTH = get_video_width();
- const HEIGHT = get_video_height();
- for (let x=0; x Math.pow(10, 32)) {
- throw "The absolute value of the coordinates of the curve is too big!"
- }
- }
- }
- evaluator(numPoints, func)
-
- // padding for 2d draw connected full-view
- if (isFullView) {
- var horiz_padding = 0.05 * (max_x - min_x)
- min_x -= horiz_padding
- max_x += horiz_padding
- var vert_padding = 0.05 * (max_y - min_y)
- min_y -= vert_padding
- max_y += vert_padding
- var depth_padding = 0.05 * (max_z - min_z)
- min_z -= depth_padding
- max_z += depth_padding
- }
-
- // box generation
- if(space == '3D'){
- drawCubeArray.push(
- -1, 1, 1, -1, -1, 1,
- -1, -1, -1, -1, 1, -1,
- 1, 1, -1, 1, -1, -1,
- -1, -1, -1, 1, -1, -1,
- 1, -1, 1, -1, -1, 1,
- 1, -1, 1, 1, 1, 1,
- -1, 1, 1, -1, 1, -1,
- 1, 1, -1, 1, 1, 1
- )
- var scale_x, scale_y, scale_z
- scale_x = scale_y = scale_z = 2
- var translate_x, translate_y, translate_z
- translate_x = translate_y = translate_z = 0
- if (scaleMode == 'fit') {
- var scale = Math.max(max_x - min_x, max_y - min_y, max_z - min_z)
- scale = scale === 0 ? 1 : scale;
- scale_x = scale_y = scale_z = scale
- translate_x = (min_x + max_x) / 2
- translate_y = (min_y + max_y) / 2
- translate_z = (min_z + max_z) / 2
- } else if (scaleMode == 'stretch') {
- var scale_x = max_x === min_x ? 1 : (max_x - min_x)
- var scale_y = max_y === min_y ? 1 : (max_y - min_y)
- var scale_z = max_z === min_z ? 1 : (max_z - min_z)
- translate_x = (min_x + max_x) / 2
- translate_y = (min_y + max_y) / 2
- translate_z = (min_z + max_z) / 2
- }
-
- for (var i = 0; i < drawCubeArray.length; i++) {
- if (i % 3 == 0) {
- drawCubeArray[i] /= 2 / scale_x
- drawCubeArray[i] += translate_x
- } else if (i % 3 == 1) {
- drawCubeArray[i] /= 2 / scale_y
- drawCubeArray[i] += translate_y
- } else {
- drawCubeArray[i] /= 2 / scale_z
- drawCubeArray[i] += translate_z
- }
- }
- var scale = Math.sqrt(1 / 3.1)
- mat4.scale(transMat, transMat, vec3.fromValues(scale, scale, scale))
- curveObject.drawCube = drawCubeArray
-
- mat4.translate(transMat, transMat, [0, 0, -5])
- //Rotation
- mat4.rotate(transMat, transMat, -(Math.PI/2), [1, 0, 0]) // axis to rotate around X (static)
- mat4.rotate(transMat, transMat,
- // cubeRotation * .7,// amount to rotate in radians
- -0.5,// amount to rotate in radians
- [0, 0, 1]) // axis to rotate around Z (dynamic)
- cubeRotation += 0.1 * Math.PI
- }
-
- if (scaleMode == 'fit') {
- var center = space == '3D' ? [(min_x + max_x) / 2, (min_y + max_y) / 2, (min_z + max_z) / 2] : [(min_x + max_x) / 2, (min_y + max_y) / 2]
- var scale = Math.max(max_x - min_x, max_y - min_y, max_z - min_z)
- scale = scale === 0 ? 1 : scale;
- space == '3D'
- ? mat4.scale(transMat, transMat, vec3.fromValues(2 / scale, 2 / scale, 2 / scale))
- : mat4.scale(transMat, transMat, vec3.fromValues(2 / scale, 2 / scale, 0))
- // use 2 because the value is in [-1, 1]
- space == '3D'
- ? mat4.translate(transMat, transMat, vec3.fromValues(-center[0], -center[1], -center[2]))
- : mat4.translate(transMat, transMat, vec3.fromValues(-center[0], -center[1], 0))
- } else if (scaleMode == 'stretch') {
- var center = space == '3D' ? [(min_x + max_x) / 2, (min_y + max_y) / 2, (min_z + max_z) / 2] : [(min_x + max_x) / 2, (min_y + max_y) / 2]
- var x_scale = max_x === min_x ? 1 : (max_x - min_x)
- var y_scale = max_y === min_y ? 1 : (max_y - min_y)
- var z_scale = max_z === min_z ? 1 : (max_z - min_z)
- space == '3D'
- ? mat4.scale(transMat, transMat, vec3.fromValues(2 / x_scale, 2 / y_scale, 2 / z_scale))
- : mat4.scale(transMat, transMat, vec3.fromValues(2 / x_scale, 2 / y_scale, 0))
- // use 2 because the value is in [-1, 1]
- space == '3D'
- ? mat4.translate(transMat, transMat, vec3.fromValues(-center[0], -center[1], -center[2]))
- : mat4.translate(transMat, transMat, vec3.fromValues(-center[0], -center[1], 0))
- }
-
- if(space == '3D'){
- const fieldOfView = 45 * Math.PI / 180;
- const aspect = gl.canvas.width / gl.canvas.height;
- const zNear = 0;
- const zFar = 50.0;
- mat4.perspective(projMat, fieldOfView, aspect, zNear, zFar);
- }
-
- clear_viewport()
- gl.uniformMatrix4fv(u_projectionMatrix, false, projMat)
- gl.uniformMatrix4fv(u_transformMatrix, false, transMat)
- curveObject.curvePos = curvePosArray
- curveObject.color = curveColorArray
- curveObject.drawCube = drawCubeArray
- drawCurve(drawMode, curveObject, space)
- copy_viewport(gl.canvas, frame)
- return new ShapeDrawn(frame)
-}
-
-/**
- * returns a function that turns a given Curve into a Drawing,
- * by sampling the Curve at num
sample points
- * and connecting each pair with a line.
- * When a program evaluates to a Drawing, the Source system
- * displays it graphically, in a window, instead of textually.
- * The parts between (0,0) and (1,1) of the resulting Drawing
- * are shown in the window.
- * @param {Number} num - determines the number of points to be
- * sampled. Including 0 and 1,
- * there are num + 1
evenly spaced sample points.
- * @return {function} function of type Curve → Drawing
- */
-function draw_connected(num) {
- return curve =>
- generateCurve('none', 'lines', num, curve, '2D')
-}
-
-/**
- * returns a function that turns a given Curve into a Drawing,
- * by sampling the Curve at num
sample points
- * and connecting each pair with a line.
- * When a program evaluates to a Drawing, the Source system
- * displays it graphically, in a window, instead of textually.
- * The Drawing is stretched or shrunk
- * to show the full curve
- * and maximize its width and height, with some padding.
- * @param {Number} num - determines the number of points to be
- * sampled. Including 0 and 1,
- * there are num + 1
evenly spaced sample points.
- * @return {function} function of type Curve → Drawing
- */
-function draw_connected_full_view(num) {
- return function(func) {
- return generateCurve('stretch', 'lines', num, func, '2D', true)
- }
-}
-
-/**
- * returns a function that turns a given Curve into a Drawing,
- * by sampling the Curve at num
sample points
- * and connecting each pair with a line.
- * When a program evaluates to a Drawing, the Source system
- * displays it graphically, in a window, instead of textually.
- * The Drawing is scaled proportionally to show the full curve
- * and maximize its size, with some padding.
- * @param {Number} num - determines the number of points to be
- * sampled. Including 0 and 1,
- * there are num + 1
evenly spaced sample points.
- * @return {function} function of type Curve → Drawing
- */
-function draw_connected_full_view_proportional(num) {
- return function(func) {
- return generateCurve('fit', 'lines', num, func, '2D', true)
- }
-}
-
-/**
- * returns a function that turns a given Curve into a Drawing,
- * by sampling the Curve at num
sample points.
- * The Drawing consists of isolated points, and does not connect them.
- * When a program evaluates to a Drawing, the Source system
- * displays it graphically, in a window, instead of textually.
- * The parts between (0,0) and (1,1) of the resulting Drawing
- * are shown in the window.
- * @param {Number} num - determines the number of points to be
- * sampled. Including 0 and 1,
- * there are num + 1
evenly spaced sample points.
- * @return {function} function of type Curve → Drawing
- */
-function draw_points_on(num) {
- return curve =>
- generateCurve('none', 'points', num, curve, '2D')
-}
-
-/**
- * returns a function that turns a given Curve into a Drawing,
- * by sampling the Curve at num
sample points.
- * The Drawing consists of isolated points, and does not connect them.
- * When a program evaluates to a Drawing, the Source system
- * displays it graphically, in a window, instead of textually.
- * The Drawing is scaled proportionally with its size maximized
- * to fit entirely inside the window, with some padding.
- * @param {Number} num - determines the number of points to be
- * sampled. Including 0 and 1,
- * there are num + 1
evenly spaced sample points.
- * @return {function} function of type Curve → Drawing
- */
-function draw_points_full_view_proportional(num) {
- return function(func) {
- return generateCurve('fit', 'points', num, func, '2D', true)
- }
-}
-
-/**
- * returns a function that turns a given 3D Curve into a Drawing,
- * by sampling the 3D Curve at num
sample points
- * and connecting each pair with a line.
- * When a program evaluates to a Drawing, the Source system
- * displays it graphically, in a window, instead of textually.
- * The parts between (0,0,0) and (1,1,1) of the resulting
- * Drawing are shown within the unit cube.
- * @param {Number} num - determines the number of points to be
- * sampled. Including 0 and 1,
- * there are num + 1
evenly spaced sample points.
- * @return {function} function of type Curve → Drawing
- */
-function draw_3D_connected(num) {
- return function(func) {
- return generateCurve('none', 'lines', num, func, '3D')
- //requestAnimationFrame(generateCurve)
- }
-}
-
-/**
- * returns a function that turns a given 3D Curve into a Drawing,
- * by sampling the 3D Curve at num
sample points
- * and connecting each pair with a line.
- * When a program evaluates to a Drawing, the Source system
- * displays it graphically, in a window, instead of textually.
- * The Drawing is stretched or shrunk
- * to show the full curve
- * and maximize its width, height and depth within the cube.
- * @param {Number} num - determines the number of points to be
- * sampled. Including 0 and 1,
- * there are num + 1
evenly spaced sample points.
- * @return {function} function of type Curve → Drawing
- */
-function draw_3D_connected_full_view(num) {
- return function(func) {
- return generateCurve('stretch', 'lines', num, func, '3D')
- }
-}
-
-/**
- * returns a function that turns a given 3D Curve into a Drawing,
- * by sampling the 3D Curve at num
sample points
- * and connecting each pair with a line.
- * When a program evaluates to a Drawing, the Source system
- * displays it graphically, in a window, instead of textually.
- * The Drawing is scaled proportionally with its size maximized
- * to fit entirely inside the cube.
- * @param {Number} num - determines the number of points to be
- * sampled. Including 0 and 1,
- * there are num + 1
evenly spaced sample points.
- * @return {function} function of type Curve → Drawing
- */
-function draw_3D_connected_full_view_proportional(num) {
- return function(func) {
- return generateCurve('fit', 'lines', num, func, '3D')
- }
-}
-
-/**
- * returns a function that turns a given 3D Curve into a Drawing,
- * by sampling the 3D Curve at num
sample points.
- * The Drawing consists of isolated points, and does not connect them.
- * When a program evaluates to a Drawing, the Source system
- * displays it graphically, in a window, instead of textually.
- * The parts between (0,0,0) and (1,1,1) of the resulting
- * Drawing are shown within the unit cube.
- * @param {Number} num - determines the number of points to be
- * sampled. Including 0 and 1,
- * there are num + 1
evenly spaced sample points.
- * @return {function} function of type Curve → Drawing
- */
-function draw_3D_points_on(num) {
- return function(func) {
- return generateCurve('none', 'points', num, func, '3D')
- }
-}
-
-/**
- * returns a function that turns a given 3D Curve into a Drawing,
- * by sampling the 3D Curve at num
sample points.
- * The Drawing consists of isolated points, and does not connect them.
- * When a program evaluates to a Drawing, the Source system
- * displays it graphically, in a window, instead of textually.
- * The Drawing is scaled proportionally with its size maximized
- * to fit entirely inside the cube.
- * @param {Number} num - determines the number of points to be
- * sampled. Including 0 and 1,
- * there are num + 1
evenly spaced sample points.
- * @return {function} function of type Curve → Drawing
- */
-function draw_3D_points_full_view_proportional(num) {
- return function(func) {
- return generateCurve('fit', 'points', num, func, '3D')
- }
-}
-
-/**
- * makes a Point with given x and y coordinates
- * @param {Number} x - x-coordinate of new point
- * @param {Number} y - y-coordinate of new point
- * @returns {Point} with x and y as coordinates
- */
-function make_point(x, y) {
- return new Point(x, y, 0, 0, 0, 0)
-}
-
-/**
- * makes a 3D Point with given x, y and z coordinates
- * @param {Number} x - x-coordinate of new point
- * @param {Number} y - y-coordinate of new point
- * @param {Number} z - z-coordinate of new point
- * @returns {Point} with x, y and z as coordinates
- */
-function make_3D_point(x, y, z) {
- return new Point(x, y, z, 0, 0, 0)
-}
-
-/**
- * makes a color Point with given x and y coordinates,
- * and RGB values ranging from 0 to 255.
- * Any input lower than 0 for RGB will be rounded up to 0,
- * and any input higher than 255 will be rounded down to 255.
- * @param {Number} x - x-coordinate of new point
- * @param {Number} y - y-coordinate of new point
- * @param {Number} r - red component of new point
- * @param {Number} g - green component of new point
- * @param {Number} b - blue component of new point
- * @returns {Point} with x and y as coordinates, and r, g and b as RGB values
- */
-function make_color_point(x, y, r, g, b){
- return new Point(x, y, 0, r/255, g/255, b/255)
-}
-
-/**
- * makes a 3D color Point with given x, y and z coordinates,
- * and RGB values ranging from 0 to 255.
- * Any input lower than 0 for RGB will be rounded up to 0,
- * and any input higher than 255 will be rounded down to 255.
- * @param {Number} x - x-coordinate of new point
- * @param {Number} y - y-coordinate of new point
- * @param {Number} z - z-coordinate of new point
- * @param {Number} r - red component of new point
- * @param {Number} g - green component of new point
- * @param {Number} b - blue component of new point
- * @returns {Point} with x, y and z as coordinates, and r, g and b as RGB values
- */
-function make_3D_color_point(x, y, z, r, g, b){
- return new Point(x, y, z, r/255, g/255, b/255)
-}
-
-/**
- * retrieves the x-coordinate of a given Point
- * @param {Point} p - given point
- * @returns {Number} x-coordinate of the Point
- */
-function x_of(pt) {
- return pt.getX();
-}
-
-/**
- * retrieves the y-coordinate of a given Point
- * @param {Point} p - given point
- * @returns {Number} y-coordinate of the Point
- */
-function y_of(pt) {
- return pt.getY();
-}
-
-/**
- * retrieves the z-coordinate of a given Point
- * @param {Point} p - given point
- * @returns {Number} z-coordinate of the Point
- */
-function z_of(pt) {
- return pt.getZ();
-}
-
-/**
- * retrieves the red component of a given Point
- * @param {Point} p - given point
- * @returns {Number} Red component of the Point
- */
-function r_of(pt) {
- return pt.getColor()[0] * 255;
-}
-
-/**
- * retrieves the green component of a given Point
- * @param {Point} p - given point
- * @returns {Number} Green component of the Point
- */
-function g_of(pt) {
- return pt.getColor()[1] * 255;
-}
-
-/**
- * retrieves the blue component of a given Point
- * @param {Point} p - given point
- * @returns {Number} Blue component of the Point
- */
-function b_of(pt) {
- return pt.getColor()[2] * 255;
-}
\ No newline at end of file
diff --git a/docs/lib/webGLhi_graph.js b/docs/lib/webGLhi_graph.js
deleted file mode 100644
index d9ee900cb..000000000
--- a/docs/lib/webGLhi_graph.js
+++ /dev/null
@@ -1,230 +0,0 @@
-/**
- * this function is a curve: a function from a
- * fraction t to a point. The points lie on the
- * unit circle. They start at Point (1,0) when
- * t is 0. When t is 0.25, they reach Point (0,1),
- * when t is 0.5, they reach Point (-1, 0), etc.
- *
- * @param {number} t - fraction between 0 and 1
- * @returns {Point} Point in the line at t
- */
-function unit_circle(t) {
- return make_point(Math.sin(2 * Math.PI * t),
- Math.cos(2 * Math.PI * t))
-}
-
-/**
- * this function is a curve: a function from a
- * fraction t to a point. The x-coordinate at
- * franction t is t, and the y-coordinate is 0.
- *
- * @param {number} t - fraction between 0 and 1
- * @returns {Point} Point in the line at t
- */
-function unit_line(t) {
- return make_point(t, 0)
-}
-
-/**
- * this function is a Curve generator: it takes
- * a number and returns a horizontal curve. The number
- * is a y-coordinate, and the Curve generates
- * only points with the given y-coordinate.
- *
- * @param {number} t - fraction between 0 and 1
- * @returns {Curve} horizontal Curve
- */
-function unit_line_at(y) {
- return function (t) {
- return make_point(t, y)
- }
-}
-
-/**
- * this function is a curve: a function from a
- * fraction t to a point. The points lie on the
- * right half of the unit circle. They start at Point (0,1) when
- * t is 0. When t is 0.5, they reach Point (1,0),
- * when t is 1, they reach Point (0, -1).
- *
- * @param {number} t - fraction between 0 and 1
- * @returns {Point} Point in the line at t
- */
-function arc(t) {
- return make_point(Math.sin(Math.PI * t), Math.cos(Math.PI * t))
-}
-
-/**
- * this function is a Curve transformation: a function from a
- * Curve to a Curve. The points of the result Curve are
- * the same points as the points of the original Curve, but
- * in reverse: The result Curve applied to 0 is the original Curve
- * applied to 1 and vice versa.
- *
- * @param {Curve} original - original Curve
- * @returns {Curve} result Curve
- */
-function invert(curve) {
- return function (t) {
- return curve(1 - t)
- }
-}
-
-/**
- * this function returns a Curve transformation:
- * It takes an x-value x0, a y-value y0 and a z-value z0,
- * each with default value of 0, as arguments
- * and returns a Curve transformation that
- * takes a Curve as argument and returns
- * a new Curve, by translating the original by x0 in x-direction,
- * y0 in y-direction and z0 in z-direction.
- *
- * @param {number} x0 - (Optional) x-value
- * @param {number} y0 - (Optional) y-value
- * @param {number} z0 - (Optional) z-value
- * @returns {function} Curve transformation
- */
-function translate_curve(x0, y0, z0) {
- return function (curve) {
- var transformation = c => (function (t) {
- x0 = x0 == undefined ? 0 : x0
- y0 = y0 == undefined ? 0 : y0
- z0 = z0 == undefined ? 0 : z0
- var ct = c(t)
- return make_3D_color_point(x0 + x_of(ct), y0 + y_of(ct), z0 + z_of(ct), r_of(ct), g_of(ct), b_of(ct))
- })
- return transformation(curve)
- }
-}
-
-/**
- * this function
- * takes either 1 or 3 angles, a, b and c in radians as parameter and
- * returns a Curve transformation:
- * a function that takes a Curve as argument and returns
- * a new Curve, which is the original Curve rotated by the given angle
- * around the z-axis (1 parameter) in counter-clockwise direction, or
- * the original Curve rotated extrinsically with Euler angles (a, b, c)
- * about x, y, and z axes (3 parameters).
- * @param {number} a - given angle
- * @param {number} b - (Optional) given angle
- * @param {number} c - (Optional) given angle
- * @returns {unary_Curve_operator} function that takes a Curve and returns a Curve
- */
-function rotate_around_origin(theta) {
- var cth = Math.cos(theta)
- var sth = Math.sin(theta)
- return function (curve) {
- return function (t) {
- var ct = curve(t)
- var x = x_of(ct)
- var y = y_of(ct)
- return make_color_point(cth * x - sth * y, sth * x + cth * y, r_of(ct), g_of(ct), b_of(ct))
- }
- }
-}
-
-/**
- * this function takes scaling factors a
, b
- * and c
, each with default value of 1, as arguments and
- * returns a Curve transformation that
- * scales a given Curve by a
in x-direction, b
- * in y-direction and c
in z-direction.
- *
- * @param {number} a - (Optional) scaling factor in x-direction
- * @param {number} b - (Optional) scaling factor in y-direction
- * @param {number} c - (Optional) scaling factor in z-direction
- * @returns {unary_Curve_operator} function that takes a Curve and returns a Curve
- */
-function scale_curve(a1, b1, c1) {
- return function (curve) {
- var transformation = c => (function (t) {
- var ct = c(t)
- a1 = a1 == undefined ? 1 : a1
- b1 = b1 == undefined ? 1 : b1
- c1 = c1 == undefined ? 1 : c1
- return make_3D_color_point(a1 * x_of(ct), b1 * y_of(ct), c1 * z_of(ct), r_of(ct), g_of(ct), b_of(ct))
- })
- return transformation(curve)
- }
-}
-
-/**
- * this function takes a scaling factor s argument and returns a
- * Curve transformation that
- * scales a given Curve by s in x, y and z direction.
- *
- * @param {number} s - scaling factor
- * @returns {unary_Curve_operator} function that takes a Curve and returns a Curve
- */
-function scale_proportional(s) {
- return scale_curve(s, s, s)
-}
-
-/**
- * this function is a Curve transformation: It
- * takes a Curve as argument and returns
- * a new Curve, as follows.
- * A Curve is in standard position if it starts at (0,0) ends at (1,0).
- * This function puts the given Curve in standard position by
- * rigidly translating it so its
- * start Point is at the origin (0,0), then rotating it about the origin to put
- * its endpoint on the x axis, then scaling it to put the endpoint at (1,0).
- * Behavior is unspecified on closed Curves where start-point equal end-point.
- *
- * @param {Curve} curve - given Curve
- * @returns {Curve} result Curve
- */
-function put_in_standard_position(curve) {
- var start_point = curve(0)
- var curve_started_at_origin = translate_curve(-x_of(start_point), -y_of(start_point))(curve)
- var new_end_point = curve_started_at_origin(1)
- var theta = Math.atan2(y_of(new_end_point), x_of(new_end_point))
- var curve_ended_at_x_axis = rotate_around_origin(-theta)(curve_started_at_origin)
- var end_point_on_x_axis = x_of(curve_ended_at_x_axis(1))
- return scale_proportional(1 / end_point_on_x_axis)(curve_ended_at_x_axis)
-}
-
-/**
- * this function is a binary Curve operator: It
- * takes two Curves as arguments and returns
- * a new Curve. The two Curves are combined
- * by using the full first Curve for the first portion
- * of the result and by using the full second Curve for the
- * second portion of the result.
- * The second Curve is not changed, and therefore
- * there might be a big jump in the middle of the
- * result Curve.
- * @param {Curve} curve1 - first Curve
- * @param {Curve} curve2 - second Curve
- * @returns {Curve} result Curve
- */
-function connect_rigidly(curve1, curve2) {
- return t => t < 1 / 2 ? curve1(2 * t) : curve2(2 * t - 1)
-}
-
-/**
- * this function is a binary Curve operator: It
- * takes two Curves as arguments and returns
- * a new Curve. The two Curves are combined
- * by using the full first Curve for the first portion
- * of the result and by using the full second Curve for the second
- * portion of the result.
- * The second Curve is translated such that its point
- * at fraction 0 is the same as the Point of the first
- * Curve at fraction 1.
- *
- * @param {Curve} curve1 - first Curve
- * @param {Curve} curve2 - second Curve
- * @returns {Curve} result Curve
- */
-function connect_ends(curve1, curve2) {
- const start_point_of_curve2 = curve2(0);
- const end_point_of_curve1 = curve1(1);
- return connect_rigidly(curve1,
- (translate_curve(x_of(end_point_of_curve1) -
- x_of(start_point_of_curve2),
- y_of(end_point_of_curve1) -
- y_of(start_point_of_curve2)))
- (curve2));
-}
\ No newline at end of file
diff --git a/docs/lib/webGLrune.js b/docs/lib/webGLrune.js
deleted file mode 100644
index 2edd0723f..000000000
--- a/docs/lib/webGLrune.js
+++ /dev/null
@@ -1,1024 +0,0 @@
-var viewport_size = 512 // This is the height of the viewport
-// while a curve is approximated by a polygon,
-// the side of the polygon will be no longer than maxArcLength pixels
-var maxArcLength = 20
-
-/*-----------------------Some class definitions----------------------*/
-function PrimaryRune(first, count) {
- this.isPrimary = true // this is a primary rune
- this.first = first // the first index in the index buffer
- // that belongs to this rune
- this.count = count // number of indices to draw the rune
-}
-
-function Rune() {
- this.isPrimary = false
- this.transMatrix = mat4.create()
- this.runes = []
- this.color = undefined
-}
-
-// set the transformation matrix related to the rune
-Rune.prototype.setM = function(matrix) {
- this.transMatrix = matrix
-}
-
-// get the transformation matrix related to the rune
-Rune.prototype.getM = function() {
- return this.transMatrix
-}
-
-// get the sub-runes (array) of the rune
-Rune.prototype.getS = function() {
- return this.runes
-}
-
-Rune.prototype.setS = function(runes) {
- this.runes = runes
-}
-
-Rune.prototype.addS = function(rune) {
- this.runes.push(rune)
-}
-
-Rune.prototype.getColor = function() {
- return this.color
-}
-
-Rune.prototype.setColor = function(color) {
- this.color = color
-}
-
-/*-----------------Initialize vertex and index buffer----------------*/
-// vertices is an array of points
-// Each point has the following attribute, in that order:
-// x, y, z, t
-// (will be converted to Float32Array later)
-var vertices = [
- // center
- 0.0,
- 0.0,
- 0.0,
- 1.0,
- // 4 corners and 4 sides' midpoints
- 1.0,
- 0.0,
- 0.0,
- 1.0,
- 1.0,
- 1.0,
- 0.0,
- 1.0,
- 0.0,
- 1.0,
- 0.0,
- 1.0,
- -1.0,
- 1.0,
- 0.0,
- 1.0,
- -1.0,
- 0.0,
- 0.0,
- 1.0,
- -1.0,
- -1.0,
- 0.0,
- 1.0,
- 0.0,
- -1.0,
- 0.0,
- 1.0,
- 1.0,
- -1.0,
- 0.0,
- 1.0,
- // for rcross
- 0.5,
- 0.5,
- 0.0,
- 1.0,
- -0.5,
- 0.5,
- 0.0,
- 1.0,
- -0.5,
- -0.5,
- 0.0,
- 1.0,
- 0.5,
- -0.5,
- 0.0,
- 1.0,
- // for nova
- 0.0,
- 0.5,
- 0.0,
- 1.0,
- -0.5,
- 0.0,
- 0.0,
- 1.0
-]
-// indices is an array of indices, each refer to a point in vertices
-// (will be converted to Uint16Array later)
-var indices = [
- // square
- 2,
- 4,
- 6,
- 2,
- 6,
- 8,
- // rcross
- 2,
- 4,
- 10,
- 2,
- 9,
- 10,
- 2,
- 9,
- 12,
- 2,
- 12,
- 8,
- 10,
- 11,
- 12,
- // sail
- 7,
- 8,
- 3,
- // corner
- 1,
- 2,
- 3,
- // nova
- 3,
- 0,
- 14,
- 13,
- 0,
- 1
-]
-
-function makeCircle() {
- // draw a polygon with many vertices to approximate a circle
- var centerVerInd = 0
- var firstVer = vertices.length / 4
- var firstInd = indices.length
- var numPoints = Math.ceil(Math.PI * viewport_size / maxArcLength)
- // generate points and store it in the vertex buffer
- for (var i = 0; i < numPoints; i++) {
- var angle = Math.PI * 2 * i / numPoints
- vertices.push(Math.cos(angle), Math.sin(angle), 0, 1)
- }
- // generate indices for the triangles and store in the index buffer
- for (var i = firstVer; i < firstVer + numPoints - 1; i++) {
- indices.push(centerVerInd, i, i + 1)
- }
- indices.push(centerVerInd, firstVer, firstVer + numPoints - 1)
- var count = 3 * numPoints
- return new PrimaryRune(firstInd, count)
-}
-
-function makeHeart() {
- var bottomMidInd = 7
- var firstVer = vertices.length / 4
- var firstInd = indices.length
- var root2 = Math.sqrt(2)
- var r = 4 / (2 + 3 * root2)
- var scaleX = 1 / (r * (1 + root2 / 2))
- var numPoints = Math.ceil(Math.PI / 2 * viewport_size * r / maxArcLength)
- // right semi-circle
- var rightCenterX = r / root2
- var rightCenterY = 1 - r
- for (var i = 0; i < numPoints; i++) {
- var angle = Math.PI * (-1 / 4 + i / numPoints)
- vertices.push(
- (Math.cos(angle) * r + rightCenterX) * scaleX,
- Math.sin(angle) * r + rightCenterY,
- 0,
- 1
- )
- }
- // left semi-circle
- var leftCenterX = -r / root2
- var leftCenterY = 1 - r
- for (var i = 0; i <= numPoints; i++) {
- var angle = Math.PI * (1 / 4 + i / numPoints)
- vertices.push(
- (Math.cos(angle) * r + leftCenterX) * scaleX,
- Math.sin(angle) * r + leftCenterY,
- 0,
- 1
- )
- }
- // update index buffer
- for (var i = firstVer; i < firstVer + 2 * numPoints; i++) {
- indices.push(bottomMidInd, i, i + 1)
- }
- var count = 3 * 2 * numPoints
- return new PrimaryRune(firstInd, count)
-}
-
-function makePentagram() {
- var firstVer = vertices.length / 4
- var firstInd = indices.length
-
- var v1 = Math.sin(Math.PI / 10)
- var v2 = Math.cos(Math.PI / 10)
-
- var w1 = Math.sin(3 * Math.PI / 10)
- var w2 = Math.cos(3 * Math.PI / 10)
-
- vertices.push(v2, v1, 0, 1)
- vertices.push(w2, -w1, 0, 1)
- vertices.push(-w2, -w1, 0, 1)
- vertices.push(-v2, v1, 0, 1)
- vertices.push(0, 1, 0, 1)
-
- for (var i = 0; i < 5; i++) {
- indices.push(0, firstVer + i, firstVer + (i + 2) % 5)
- }
-
- return new PrimaryRune(firstInd, 15)
-}
-
-function makeRibbon() {
- var firstVer = vertices.length / 4
- var firstInd = indices.length
-
- var theta_max = 30
- var thickness = -1 / theta_max
- var unit = 0.1
-
- for (var i = 0; i < theta_max; i += unit) {
- vertices.push(i / theta_max * Math.cos(i), i / theta_max * Math.sin(i), 0, 1)
- vertices.push(
- Math.abs(Math.cos(i) * thickness) + i / theta_max * Math.cos(i),
- Math.abs(Math.sin(i) * thickness) + i / theta_max * Math.sin(i),
- 0,
- 1
- )
- }
-
- var totalPoints = Math.ceil(theta_max / unit) * 2
-
- for (var i = firstVer; i < firstVer + totalPoints - 2; i++) {
- indices.push(i, i + 1, i + 2)
- }
-
- return new PrimaryRune(firstInd, 3 * totalPoints - 6)
-}
-
-/**
- * primitive Rune in the rune of a full square
-**/
-var square = new PrimaryRune(0, 6)
-
-/**
- * primitive Rune in the rune of a blank square
-**/
-var blank = new PrimaryRune(0, 0)
-
-/**
- * primitive Rune in the rune of a
- * smallsquare inside a large square,
- * each diagonally split into a
- * black and white half
-**/
-var rcross = new PrimaryRune(6, 15)
-
-/**
- * primitive Rune in the rune of a sail
-**/
-var sail = new PrimaryRune(21, 3)
-
-/**
- * primitive Rune with black triangle,
- * filling upper right corner
-**/
-var corner = new PrimaryRune(24, 3)
-
-/**
- * primitive Rune in the rune of two overlapping
- * triangles, residing in the upper half
- * of
-**/
-var nova = new PrimaryRune(27, 6)
-
-/**
- * primitive Rune in the rune of a circle
-**/
-var circle = makeCircle()
-
-/**
- * primitive Rune in the rune of a heart
-**/
-var heart = makeHeart()
-
-/**
- * primitive Rune in the rune of a pentagram
-**/
-var pentagram = makePentagram()
-
-/**
- * primitive Rune in the rune of a ribbon
- * winding outwards in an anticlockwise spiral
-**/
-var ribbon = makeRibbon()
-
-// convert vertices and indices to typed arrays
-vertices = new Float32Array(vertices)
-indices = new Uint16Array(indices)
-
-/*-----------------------Drawing functions----------------------*/
-function generateFlattenedRuneList(rune) {
- var matStack = []
- var matrix = mat4.create()
- var rune_list = {}
- function pushMat() {
- matStack.push(mat4.clone(matrix))
- }
- function popMat() {
- if (matStack.length == 0) {
- throw 'Invalid pop matrix!'
- } else {
- matrix = matStack.pop()
- }
- }
- function helper(rune, color) {
- if (rune.isPrimary) {
- if (rune.count === 0) {
- // this is blank, do nothing
- return
- }
- if (!rune_list[rune.first]) {
- rune_list[rune.first] = {
- rune: rune,
- matrices: [],
- colors: []
- }
- }
- rune_list[rune.first].matrices.push(matrix)
- rune_list[rune.first].colors.push(color || [0, 0, 0, 1])
- } else {
- if (color === undefined && rune.getColor() !== undefined) {
- color = rune.getColor()
- }
- pushMat()
- mat4.multiply(matrix, matrix, rune.getM())
- var childRunes = rune.getS()
- for (var i = 0; i < childRunes.length; i++) {
- helper(childRunes[i], color)
- }
- popMat()
- }
- }
- function flatten(matrices, colors) {
- var instanceArray = new Float32Array(matrices.length * 20)
- for (var i = 0; i < matrices.length; i++) {
- instanceArray.set(matrices[i], 20 * i)
- instanceArray.set(colors[i], 20 * i + 16)
- }
- return instanceArray
- }
- helper(rune)
- var flattened_rune_list = []
- // draw a white square background first
- flattened_rune_list.push({
- rune: square,
- instanceArray: new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -1, 1, 1, 1, 1, 1])
- })
- for (var key in rune_list) {
- if (rune_list.hasOwnProperty(key)) {
- var rune = rune_list[key].rune
- var instanceArray = flatten(rune_list[key].matrices, rune_list[key].colors)
- flattened_rune_list.push({ rune: rune, instanceArray: instanceArray })
- }
- }
- return flattened_rune_list
-}
-
-function drawWithWebGL(flattened_rune_list, drawFunction) {
- for (var i = 0; i < flattened_rune_list.length; i++) {
- var rune = flattened_rune_list[i].rune
- var instanceArray = flattened_rune_list[i].instanceArray
- drawFunction(rune.first, rune.count, instanceArray)
- }
-}
-
-/**
- * turns a given Rune into a two-dimensional Picture
- * @param {Rune} rune - given Rune
- * @return {Picture}
- * If the result of evaluating a program is a Picture,
- * the REPL displays it graphically, instead of textually.
- */
-function show(rune) {
- const frame = open_pixmap('frame', viewport_size, viewport_size, true);
- clear_viewport()
- var flattened_rune_list = generateFlattenedRuneList(rune)
- drawWithWebGL(flattened_rune_list, drawRune);
- copy_viewport(gl.canvas, frame);
- return new ShapeDrawn(frame);
-}
-
-/**
- * turns a given Rune into an anaglyph Picture
- * @param {Rune} rune - given Rune
- * @return {Picture}
- * If the result of evaluating a program is a Picture,
- * the REPL displays it graphically, using anaglyph
- * technology, instead of textually. Use your 3D-glasses
- * to view the anaglyph Picture.
- */
-function anaglyph(rune) {
- const frame = open_pixmap('frame', viewport_size, viewport_size, true);
- clear_viewport()
- clearAnaglyphFramebuffer()
- var flattened_rune_list = generateFlattenedRuneList(rune)
- drawWithWebGL(flattened_rune_list, drawAnaglyph)
- copy_viewport(gl.canvas, frame);
- return new ShapeDrawn(frame);
-}
-
-var hollusionTimeout
-/**
- * turns a given Rune into Hollusion
- * @param {Rune} rune - given Rune
- * @return {Picture}
- * If the result of evaluating a program is a Hollusion,
- * the REPL displays it graphically, using hollusion
- * technology, instead of textually.
- */
-function hollusion(rune, num) {
- clear_viewport()
- var num = num > 5 ? num : 5;
- var flattened_rune_list = generateFlattenedRuneList(rune)
- var frame_list = []
- for (var j = 0; j < num; j++) {
- var frame = open_pixmap('frame' + j, viewport_size, viewport_size, false)
- for (var i = 0; i < flattened_rune_list.length; i++) {
- var rune = flattened_rune_list[i].rune
- var instanceArray = flattened_rune_list[i].instanceArray
- var cameraMatrix = mat4.create()
- mat4.lookAt(
- cameraMatrix,
- vec3.fromValues(-halfEyeDistance + j / (num - 1) * 2 * halfEyeDistance, 0, 0),
- vec3.fromValues(0, 0, -0.4),
- vec3.fromValues(0, 1, 0)
- )
- draw3D(rune.first, rune.count, instanceArray, cameraMatrix, [1, 1, 1, 1], null, true)
- }
- gl.finish()
- copy_viewport(gl.canvas, frame)
- frame_list.push(frame)
- clear_viewport()
- }
- for (var i = frame_list.length - 2; i > 0; i--) {
- frame_list.push(frame_list[i])
- }
- const outframe = open_pixmap('frame', viewport_size, viewport_size, true);
- function animate() {
- var frame = frame_list.shift()
- copy_viewport(frame, outframe);
- frame_list.push(frame)
- hollusionTimeout = setTimeout(animate, 500 / num)
- }
- animate();
- return new ShapeDrawn(outframe);
-}
-
-function clearHollusion() {
- clearTimeout(hollusionTimeout)
-}
-
-/*-----------------------Transformation functions----------------------*/
-/**
- * scales a given Rune by separate factors in x and y direction
- * @param {number} ratio_x - scaling factor in x direction
- * @param {number} ratio_y - scaling factor in y direction
- * @param {Rune} rune - given Rune
- * @return {Rune} resulting scaled Rune
- */
-function scale_independent(ratio_x, ratio_y, rune) {
- var scaleVec = vec3.fromValues(ratio_x, ratio_y, 1)
- var scaleMat = mat4.create()
- mat4.scale(scaleMat, scaleMat, scaleVec)
- var wrapper = new Rune()
- wrapper.addS(rune)
- wrapper.setM(scaleMat)
- return wrapper
-}
-
-
-/**
- * scales a given Rune by a given factor in both x and y direction
- * @param {number} ratio - scaling factor
- * @param {Rune} rune - given Rune
- * @return {Rune} resulting scaled Rune
- */
-function scale(ratio, rune) {
- return scale_independent(ratio, ratio, rune)
-}
-
-
-
-/**
- * translates a given Rune by given values in x and y direction
- * @param {number} x - translation in x direction
- * @param {number} y - translation in y direction
- * @param {Rune} rune - given Rune
- * @return {Rune} resulting translated Rune
- */
-function translate(x, y, rune) {
- var translateVec = vec3.fromValues(x, -y, 0)
- var translateMat = mat4.create()
- mat4.translate(translateMat, translateMat, translateVec)
- var wrapper = new Rune()
- wrapper.addS(rune)
- wrapper.setM(translateMat)
- return wrapper
-}
-
-/**
- * rotates a given Rune by a given angle,
- * given in radians, in anti-clockwise direction.
- * Note that parts of the Rune
- * may be cropped as a result.
- * @param {number} rad - fraction between 0 and 1
- * @param {Rune} rune - given Rune
- * @return {Rune} rotated Rune
- */
-function rotate(rad, rune) {
- var rotateMat = mat4.create()
- mat4.rotateZ(rotateMat, rotateMat, rad)
- var wrapper = new Rune()
- wrapper.addS(rune)
- wrapper.setM(rotateMat)
- return wrapper
-}
-
-/**
- * makes a new Rune from two given Runes by
- * placing the first on top of the second
- * such that the first one occupies frac
- * portion of the height of the result and
- * the second the rest
- * @param {number} frac - fraction between 0 and 1
- * @param {Rune} rune1 - given Rune
- * @param {Rune} rune2 - given Rune
- * @return {Rune} resulting Rune
- */
-function stack_frac(frac, rune1, rune2) {
- var upper = translate(0, -(1 - frac), scale_independent(1, frac, rune1))
- var lower = translate(0, frac, scale_independent(1, 1 - frac, rune2))
- var combined = new Rune()
- combined.setS([upper, lower])
- return combined
-}
-
-/**
- * makes a new Rune from two given Runes by
- * placing the first on top of the second, each
- * occupying equal parts of the height of the
- * result
- * @param {Rune} rune1 - given Rune
- * @param {Rune} rune2 - given Rune
- * @return {Rune} resulting Rune
- */
-function stack(rune1, rune2) {
- return stack_frac(1 / 2, rune1, rune2)
-}
-
-/**
- * makes a new Rune from a given Rune
- * by vertically stacking n copies of it
- * @param {number} n - positive integer
- * @param {Rune} rune - given Rune
- * @return {Rune} resulting Rune
- */
-function stackn(n, rune) {
- if (n === 1) {
- return rune
- } else {
- return stack_frac(1 / n, rune, stackn(n - 1, rune))
- }
-}
-
-/**
- * makes a new Rune from a given Rune
- * by turning it a quarter-turn around the centre in
- * clockwise direction.
- * @param {Rune} rune - given Rune
- * @return {Rune} resulting Rune
- */
-function quarter_turn_right(rune) {
- return rotate(-Math.PI / 2, rune)
-}
-
-/**
- * makes a new Rune from a given Rune
- * by turning it a quarter-turn in
- * anti-clockwise direction.
- * @param {Rune} rune - given Rune
- * @return {Rune} resulting Rune
- */
-function quarter_turn_left(rune) {
- return rotate(Math.PI / 2, rune)
-}
-
-/**
- * makes a new Rune from a given Rune
- * by turning it upside-down
- * @param {Rune} rune - given Rune
- * @return {Rune} resulting Rune
- */
-function turn_upside_down(rune) {
- return rotate(Math.PI, rune)
-}
-
-/**
- * makes a new Rune from two given Runes by
- * placing the first on the left of the second
- * such that the first one occupies frac
- * portion of the width of the result and
- * the second the rest
- * @param {number} frac - fraction between 0 and 1
- * @param {Rune} rune1 - given Rune
- * @param {Rune} rune2 - given Rune
- * @return {Rune} resulting Rune
- */
-function beside_frac(frac, rune1, rune2) {
- var left = translate(-(1 - frac), 0, scale_independent(frac, 1, rune1))
- var right = translate(frac, 0, scale_independent(1 - frac, 1, rune2))
- var combined = new Rune()
- combined.setS([left, right])
- return combined
-}
-
-/**
- * makes a new Rune from two given Runes by
- * placing the first on the left of the second,
- * both occupying equal portions of the width
- * of the result
- * @param {Rune} rune1 - given Rune
- * @param {Rune} rune2 - given Rune
- * @return {Rune} resulting Rune
- */
-function beside(rune1, rune2) {
- return beside_frac(1 / 2, rune1, rune2)
-}
-
-/**
- * makes a new Rune from a given Rune by
- * flipping it around a horizontal axis,
- * turning it upside down
- * @param {Rune} rune - given Rune
- * @return {Rune} resulting Rune
- */
-function flip_vert(rune) {
- return scale_independent(1, -1, rune)
-}
-
-/**
- * makes a new Rune from a given Rune by
- * flipping it around a vertical axis,
- * creating a mirror image
- * @param {Rune} rune - given Rune
- * @return {Rune} resulting Rune
- */
-function flip_horiz(rune) {
- return scale_independent(-1, 1, rune)
-}
-
-/**
- * makes a new Rune from a given Rune by
- * arranging into a square for copies of the
- * given Rune in different orientations
- * @param {Rune} rune - given Rune
- * @return {Rune} resulting Rune
- */
-function make_cross(rune) {
- return stack(
- beside(quarter_turn_right(rune), rotate(Math.PI, rune)),
- beside(rune, rotate(Math.PI / 2, rune))
- )
-}
-
-/**
- * applies a given function n times to an initial value
- * @param {number} n - a nonnegative integer
- * @param {function} f - unary function from t to t
- * @param {t} initial - argument
- * @return {t} - result of n times application of
- * f to rune: f(f(...f(f(rune))...))
- */
-function repeat_pattern(n, pattern, initial) {
- if (n === 0) {
- return initial
- } else {
- return pattern(repeat_pattern(n - 1, pattern, initial))
- }
-}
-
-/*-----------------------Color functions----------------------*/
-function hexToColor(hex) {
- var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
- return [
- parseInt(result[1], 16) / 255,
- parseInt(result[2], 16) / 255,
- parseInt(result[3], 16) / 255,
- 1
- ]
-}
-
-/**
- * adds color to rune by specifying
- * the red, green, blue (RGB) value, ranging from 0.0 to 1.0.
- * RGB is additive: if all values are 1, the color is white,
- * and if all values are 0, the color is black.
- * @param {Rune} rune - the rune to add color to
- * @param {number} r - red value (0.0-1.0)
- * @param {number} g - green value (0.0-1.0)
- * @param {number} b - blue value (0.0-1.0)
- * @returns {Rune} the colored Rune
- */
-function color(rune, r, g, b) {
- var wrapper = new Rune()
- wrapper.addS(rune)
- var color = [r, g, b, 1]
- wrapper.setColor(color)
- return wrapper
-}
-
-function addColorFromHex(rune, hex) {
- var wrapper = new Rune()
- wrapper.addS(rune)
- wrapper.setColor(hexToColor(hex))
- return wrapper
-}
-
-/**
- * Gives random color to the given rune.
- * The color is chosen randomly from the following nine
- * colors: red, pink, purple, indigo, blue, green, yellow, orange, brown
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function random_color(rune) {
- var wrapper = new Rune()
- wrapper.addS(rune)
- var randomColor = hexToColor(colorPalette[Math.floor(Math.random() * colorPalette.length)])
- wrapper.setColor(randomColor)
- return wrapper
-}
-
-// black and white not included because they are boring colors
-// colorPalette is used in generateFlattenedRuneList to generate a random color
-var colorPalette = [
- '#F44336',
- '#E91E63',
- '#AA00FF',
- '#3F51B5',
- '#2196F3',
- '#4CAF50',
- '#FFEB3B',
- '#FF9800',
- '#795548'
-]
-
-/**
- * colors the given rune red.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function red(rune) {
- return addColorFromHex(rune, '#F44336')
-}
-
-/**
- * colors the given rune pink.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function pink(rune) {
- return addColorFromHex(rune, '#E91E63')
-}
-
-/**
- * colors the given rune purple.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function purple(rune) {
- return addColorFromHex(rune, '#AA00FF')
-}
-
-/**
- * colors the given rune indigo.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function indigo(rune) {
- return addColorFromHex(rune, '#3F51B5')
-}
-
-/**
- * colors the given rune blue.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function blue(rune) {
- return addColorFromHex(rune, '#2196F3')
-}
-
-/**
- * colors the given rune green.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function green(rune) {
- return addColorFromHex(rune, '#4CAF50')
-}
-
-/**
- * colors the given rune yellow.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function yellow(rune) {
- return addColorFromHex(rune, '#FFEB3B')
-}
-
-/**
- * colors the given rune orange.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function orange(rune) {
- return addColorFromHex(rune, '#FF9800')
-}
-
-/**
- * colors the given rune brown.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function brown(rune) {
- return addColorFromHex(rune, '#795548')
-}
-
-/**
- * colors the given rune black.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function black(rune) {
- return addColorFromHex(rune, '#000000')
-}
-
-/**
- * colors the given rune white.
- * @param {Rune} rune - the rune to color
- * @returns {Rune} the colored Rune
- */
-function white(rune) {
- return addColorFromHex(rune, '#FFFFFF')
-}
-
-/**
- * makes a 3D-Rune from two given Runes by
- * overlaying the first with the second
- * such that the first one occupies frac
- * portion of the depth of the 3D result
- * and the second the rest
- * @param {number} frac - fraction between 0 and 1
- * @param {Rune} rune1 - given Rune
- * @param {Rune} rune2 - given Rune
- * @return {Rune} resulting Rune
- */
-function overlay_frac(frac, rune1, rune2) {
- var front = new Rune()
- front.addS(rune1)
- var frontMat = front.getM()
- // z: scale by frac
- mat4.scale(frontMat, frontMat, vec3.fromValues(1, 1, frac))
-
- var back = new Rune()
- back.addS(rune2)
- var backMat = back.getM()
- // z: scale by (1-frac), translate by -frac
- mat4.scale(
- backMat,
- mat4.translate(backMat, backMat, vec3.fromValues(0, 0, -frac)),
- vec3.fromValues(1, 1, 1 - frac)
- )
-
- var combined = new Rune()
- combined.setS([front, back]) // render front first to avoid redrawing
- return combined
-}
-
-/**
- * makes a 3D-Rune from two given Runes by
- * overlaying the first with the second, each
- * occupying equal parts of the depth of the
- * result
- * @param {Rune} rune1 - given Rune
- * @param {Rune} rune2 - given Rune
- * @return {Rune} resulting Rune
- */
-function overlay(rune1, rune2) {
- return overlay_frac(0.5, rune1, rune2)
-}
-
-/*
-function stereogram(rune) {
- clear_viewport()
- var flattened_rune_list = generateFlattenedRuneList(rune)
- var depth_map = open_pixmap('depth_map', viewport_size, viewport_size, true)
- // draw the depth map
- for (var i = 0; i < flattened_rune_list.length; i++) {
- var rune = flattened_rune_list[i].rune
- var instanceArray = flattened_rune_list[i].instanceArray
- drawRune(rune.first, rune.count, instanceArray)
- }
- gl.finish()
- copy_viewport(gl.canvas, depth_map)
-
- // copy from the old library, with some modifications
- var E = 100 //; distance between eyes, 300 pixels
- var D = 600 //distance between eyes and image plane, 600 pixels
- var delta = 40 //stereo seperation
- var MAX_X = depth_map.width
- var MAX_Y = depth_map.height
- var MAX_Z = 0
- var CENTRE = Math.round(MAX_X / 2)
-
- var stereo_data = depth_map.getContext('2d').createImageData(depth_map.width, depth_map.height)
- var pixels = stereo_data.data
- var depth_data = depth_map.getContext('2d').getImageData(0, 0, depth_map.width, depth_map.height)
- var depth_pix = depth_data.data
- function get_depth(x, y) {
- if (x >= 0 && x < MAX_X) {
- var tgt = 4 * (y * depth_map.width + x)
- return -100 * depth_pix[tgt] / 255 - 400
- } else return -500
- }
- for (var y = 0; y < MAX_Y; y++) {
- //may want to use list of points instead
- var link_left = []
- var link_right = []
- var colours = []
- //varraint creation
- for (var x = 0; x < MAX_X; x++) {
- var z = get_depth(x, y)
- var s = delta + z * (E / (z - D)) // Determine distance between intersection of lines of sight on image plane
- var left = x - Math.round(s / 2) //x is integer, left is integer
- var right = left + Math.round(s) //right is integer
- if (left > 0 && right < MAX_X) {
- if (
- (!link_right[left] || s < link_right[left]) &&
- (!link_left[right] || s < link_left[right])
- ) {
- link_right[left] = Math.round(s)
- link_left[right] = Math.round(s)
- }
- }
- }
- //varraint resolution
- for (var x = 0; x < MAX_X; x++) {
- var s = link_left[x]
- if (s == undefined) s = Infinity
- else s = x
- var d
- if (x - s > 0) d = link_right[x - s]
- else d = Infinity
- if (s == Infinity || s > d) link_left[x] = 0
- }
- //drawing step
- for (var x = 0; x < MAX_X; x++) {
- var s = link_left[x] //should be valid for any integer till MAX_X
- var colour = colours[x - s] || [
- Math.round(Math.round(Math.random() * 10 / 9) * 255),
- Math.round(Math.round(Math.random() * 10 / 9) * 255),
- Math.round(Math.round(Math.random() * 10 / 9) * 255)
- ]
- var tgt = 4 * (y * depth_map.width + x)
- pixels[tgt] = colour[0]
- pixels[tgt + 1] = colour[1]
- pixels[tgt + 2] = colour[2]
- pixels[tgt + 3] = 255
- colours[x] = colour
- }
- }
- //throw on canvas
- depth_map.getContext('2d').putImageData(stereo_data, 0, 0)
- copy_viewport_webGL(depth_map)
- return new ShapeDrawn()
-}
-*/
diff --git a/docs/specs/source_streams.tex b/docs/specs/source_streams.tex
index 520fd7fba..368b06a49 100644
--- a/docs/specs/source_streams.tex
+++ b/docs/specs/source_streams.tex
@@ -3,16 +3,16 @@ \subsection*{Stream Support}
The following stream processing functions are supported:
\begin{itemize}
-\item \lstinline{stream_tail(x)}: \textit{primitive}, assumes that the tail (second component) of the
+\item \lstinline{stream(x1, x2,..., xn)}: \textit{primitive}, returns a stream with $n$ elements. The
+first element is \lstinline{x1}, the second \lstinline{x2}, etc.\\
+\emph{Laziness:} No: In this implementation, we generate first a
+ complete list, and then a stream using \lstinline{list_to_stream}.
+\item \lstinline{stream_tail(x)}: Assumes that the tail (second component) of the
pair \lstinline{x} is a nullary function, and returns the result of
applying that function.\\
\emph{Laziness:} Yes: \lstinline{stream_tail} only forces the direct tail of a given
stream,
but not the rest of the stream, i.e. not the tail of the tail, etc.
-\item \lstinline{stream(x1, x2,..., xn)}: \textit{primitive}, returns a stream with $n$ elements. The
-first element is \lstinline{x1}, the second \lstinline{x2}, etc.\\
-\emph{Laziness:} No: In this implementation, we generate first a
- complete list, and then a stream using \lstinline{list_to_stream}.
\item \lstinline{is_stream(x)}: Returns \lstinline{true} if
\lstinline{x} is a stream as defined in the lectures, and
\lstinline{false} otherwise.\\
diff --git a/scripts/jsdoc.sh b/scripts/jsdoc.sh
index d5899bdc7..8356897f8 100755
--- a/scripts/jsdoc.sh
+++ b/scripts/jsdoc.sh
@@ -283,7 +283,7 @@ run() {
-d ${DST}/CONCURRENCY/ \
${LIB}/concurrency.js
- # NON-DET
+ # NON-DET
${JSDOC} -r -t ${TMPL} \
-c docs/jsdoc/conf.json \
@@ -307,56 +307,7 @@ run() {
-d ${DST}/CONTINUATION/ \
${LIB}/continuation.js
- # RUNES
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -d ${DST}/RUNES/ \
- -R ${MD}/RUNES_README.md \
- ${LIB}/webGLrune.js
-
- # CURVES
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -d ${DST}/CURVES/ \
- -R ${MD}/CURVES_README.md \
- ${LIB}/webGLcurve.js \
- ${LIB}/webGLhi_graph.js
-
- # SOUNDS
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -d ${DST}/SOUNDS/ \
- -R ${MD}/SOUNDS_README.md \
- ${LIB}/sound
-
- # BINARYTREES
-
- ${JSDOC} -r -t ${TMPL}/ \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_BINARYTREES.md \
- -d ${DST}/BINARYTREES \
- ${LIB}/tree.js
-
- # PIXNFLIX
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -d "${DST}/PIXNFLIX/" \
- -R ${MD}/PIXNFLIX_README.md \
- ${LIB}/video_lib.js
-
- # GAME
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -d "${DST}/GAME/" \
- -R ${MD}/GAME_README.md \
- ${LIB}/game.js
-
- # EV3
+ # EV3
${JSDOC} -r -t ${TMPL} \
-c docs/jsdoc/conf.json \
@@ -364,20 +315,6 @@ run() {
-R ${MD}/EV3_README.md \
${LIB}/ev3.js
- # External
-
- ${JSDOC} -r -t ${TMPL}/ \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_EXTERNAL.md \
- -d ${DST}/"External libraries"/ \
- ${LIB}/webGLrune.js \
- ${LIB}/webGLcurve.js \
- ${LIB}/webGLhi_graph.js \
- ${LIB}/video_lib.js \
- ${LIB}/game.js \
- ${LIB}/sound \
- ${LIB}/ev3.js
-
}
prepare() {
diff --git a/scripts/updateAutocompleteDocs.js b/scripts/updateAutocompleteDocs.js
index 0cfb7cd61..4e6c38374 100644
--- a/scripts/updateAutocompleteDocs.js
+++ b/scripts/updateAutocompleteDocs.js
@@ -22,8 +22,7 @@ const TARGETS = [
"source_3_typed",
"source_4",
"source_4_typed",
- "source_4_explicit-control",
- "External libraries"
+ "source_4_explicit-control"
]
function newTitleNode(title, document) {
diff --git a/src/__tests__/__snapshots__/environment.ts.snap b/src/__tests__/__snapshots__/environment.ts.snap
index e2ad263d0..c96165571 100644
--- a/src/__tests__/__snapshots__/environment.ts.snap
+++ b/src/__tests__/__snapshots__/environment.ts.snap
@@ -143,7 +143,6 @@ Object {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -296,7 +295,6 @@ Object {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -400,7 +398,6 @@ Object {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -493,7 +490,6 @@ Object {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
diff --git a/src/__tests__/__snapshots__/environmentTree.ts.snap b/src/__tests__/__snapshots__/environmentTree.ts.snap
index ab558e82e..c2887b96e 100644
--- a/src/__tests__/__snapshots__/environmentTree.ts.snap
+++ b/src/__tests__/__snapshots__/environmentTree.ts.snap
@@ -114,7 +114,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -208,7 +207,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -319,7 +317,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -429,7 +426,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -547,7 +543,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -664,7 +659,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -781,7 +775,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -890,7 +883,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -991,7 +983,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1085,7 +1076,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1197,7 +1187,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1306,7 +1295,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1425,7 +1413,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1542,7 +1529,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1659,7 +1645,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1768,7 +1753,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1869,7 +1853,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1963,7 +1946,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2084,7 +2066,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2201,7 +2182,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2318,7 +2298,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2427,7 +2406,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2536,7 +2514,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2645,7 +2622,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2747,7 +2723,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2841,7 +2816,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2960,7 +2934,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3078,7 +3051,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3195,7 +3167,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3297,7 +3268,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3391,7 +3361,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3510,7 +3479,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3627,7 +3595,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3745,7 +3712,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3847,7 +3813,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3941,7 +3906,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4060,7 +4024,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4177,7 +4140,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4294,7 +4256,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4397,7 +4358,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4491,7 +4451,6 @@ EnvTreeNode {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
diff --git a/src/createContext.ts b/src/createContext.ts
index ac4155718..86f0c171b 100644
--- a/src/createContext.ts
+++ b/src/createContext.ts
@@ -358,7 +358,6 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn
defineBuiltin(context, 'is_array(val)', misc.is_array)
// Stream library
- defineBuiltin(context, 'stream_tail(stream)', stream.stream_tail)
defineBuiltin(context, 'stream(...values)', stream.stream, 0)
}
diff --git a/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap b/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap
index d6640bfab..ae1901f12 100644
--- a/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap
+++ b/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap
@@ -129,7 +129,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -311,7 +310,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -431,7 +429,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -524,7 +521,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -616,7 +612,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -755,7 +750,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -937,7 +931,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1057,7 +1050,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1150,7 +1142,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1267,7 +1258,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1405,7 +1395,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1587,7 +1576,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1707,7 +1695,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1801,7 +1788,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1938,7 +1924,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2075,7 +2060,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2258,7 +2242,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2378,7 +2361,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2472,7 +2454,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2652,7 +2633,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2831,7 +2811,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2971,7 +2950,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3092,7 +3070,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3186,7 +3163,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3259,6 +3235,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -3308,6 +3285,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
Array [
1,
2,
@@ -3413,7 +3391,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3506,7 +3483,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3598,7 +3574,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3660,6 +3635,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -3709,6 +3685,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
Array [
1,
2,
@@ -3814,7 +3791,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3907,7 +3883,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3968,6 +3943,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -4017,6 +3993,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
Array [
1,
2,
@@ -4122,7 +4099,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4183,6 +4159,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -4232,6 +4209,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
Array [
1,
2,
@@ -4337,7 +4315,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4431,7 +4408,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4503,6 +4479,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -4552,6 +4529,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -4632,7 +4610,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4725,7 +4702,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4817,7 +4793,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4879,6 +4854,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -4928,6 +4904,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -5008,7 +4985,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -5101,7 +5077,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -5162,6 +5137,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -5211,6 +5187,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -5291,7 +5268,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -5352,6 +5328,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -5401,6 +5378,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -5481,7 +5459,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -5575,7 +5552,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
diff --git a/src/cse-machine/__tests__/__snapshots__/cse-machine-unique-id.ts.snap b/src/cse-machine/__tests__/__snapshots__/cse-machine-unique-id.ts.snap
index bb7799438..10fff7ec6 100644
--- a/src/cse-machine/__tests__/__snapshots__/cse-machine-unique-id.ts.snap
+++ b/src/cse-machine/__tests__/__snapshots__/cse-machine-unique-id.ts.snap
@@ -73,7 +73,7 @@ EnvTree {
"heap": Heap {
"storage": null,
},
- "id": "54",
+ "id": "55",
"name": "c",
"tail": Object {
"head": Object {
@@ -122,7 +122,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -170,6 +170,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -219,6 +220,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -299,7 +301,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -336,7 +337,7 @@ EnvTree {
[Function],
},
},
- "id": "55",
+ "id": "56",
"name": "blockEnvironment",
"tail": Object {
"head": Object {
@@ -385,7 +386,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -433,6 +434,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -482,6 +484,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -562,7 +565,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -628,7 +630,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -676,6 +678,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -725,6 +728,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -805,7 +809,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -869,6 +872,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -918,6 +922,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -998,7 +1003,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1091,7 +1095,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1183,7 +1186,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1266,7 +1268,7 @@ EnvTree {
"heap": Heap {
"storage": null,
},
- "id": "54",
+ "id": "55",
"name": "c",
"tail": Object {
"head": Object {
@@ -1315,7 +1317,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -1363,6 +1365,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -1412,6 +1415,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -1492,7 +1496,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1529,7 +1532,7 @@ EnvTree {
[Function],
},
},
- "id": "55",
+ "id": "56",
"name": "blockEnvironment",
"tail": Object {
"head": Object {
@@ -1578,7 +1581,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -1626,6 +1629,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -1675,6 +1679,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -1755,7 +1760,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -1821,7 +1825,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -1869,6 +1873,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -1918,6 +1923,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -1998,7 +2004,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2062,6 +2067,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -2111,6 +2117,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -2191,7 +2198,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2284,7 +2290,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2345,6 +2350,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -2394,6 +2400,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -2474,7 +2481,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2556,7 +2562,7 @@ EnvTree {
"heap": Heap {
"storage": null,
},
- "id": "54",
+ "id": "55",
"name": "c",
"tail": Object {
"head": Object {
@@ -2605,7 +2611,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -2653,6 +2659,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -2702,6 +2709,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -2782,7 +2790,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -2819,7 +2826,7 @@ EnvTree {
[Function],
},
},
- "id": "55",
+ "id": "56",
"name": "blockEnvironment",
"tail": Object {
"head": Object {
@@ -2868,7 +2875,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -2916,6 +2923,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -2965,6 +2973,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -3045,7 +3054,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3111,7 +3119,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -3159,6 +3167,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -3208,6 +3217,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -3288,7 +3298,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3352,6 +3361,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -3401,6 +3411,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -3481,7 +3492,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3575,7 +3585,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3638,7 +3647,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -3686,6 +3695,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -3735,6 +3745,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -3815,7 +3826,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -3896,7 +3906,7 @@ EnvTree {
"heap": Heap {
"storage": null,
},
- "id": "54",
+ "id": "55",
"name": "c",
"tail": Object {
"head": Object {
@@ -3945,7 +3955,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -3993,6 +4003,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -4042,6 +4053,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -4122,7 +4134,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4159,7 +4170,7 @@ EnvTree {
[Function],
},
},
- "id": "55",
+ "id": "56",
"name": "blockEnvironment",
"tail": Object {
"head": Object {
@@ -4208,7 +4219,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -4256,6 +4267,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -4305,6 +4317,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -4385,7 +4398,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4451,7 +4463,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -4499,6 +4511,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -4548,6 +4561,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -4628,7 +4642,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4693,6 +4706,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -4742,6 +4756,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -4822,7 +4837,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4916,7 +4930,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -4996,7 +5009,7 @@ EnvTree {
"heap": Heap {
"storage": null,
},
- "id": "54",
+ "id": "55",
"name": "c",
"tail": Object {
"head": Object {
@@ -5045,7 +5058,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -5093,6 +5106,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -5142,6 +5156,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -5222,7 +5237,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -5302,7 +5316,7 @@ EnvTree {
"heap": Heap {
"storage": null,
},
- "id": "54",
+ "id": "55",
"name": "c",
"tail": Object {
"head": Object {
@@ -5351,7 +5365,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -5399,6 +5413,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -5448,6 +5463,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -5528,7 +5544,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -5566,7 +5581,7 @@ EnvTree {
[Function],
},
},
- "id": "55",
+ "id": "56",
"name": "blockEnvironment",
"tail": Object {
"head": Object {
@@ -5615,7 +5630,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -5663,6 +5678,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -5712,6 +5728,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -5792,7 +5809,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -5858,7 +5874,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -5906,6 +5922,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -5955,6 +5972,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -6035,7 +6053,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -6100,6 +6117,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -6149,6 +6167,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -6229,7 +6248,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -6323,7 +6341,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -6358,7 +6375,7 @@ EnvTree {
[Function],
},
},
- "id": "55",
+ "id": "56",
"name": "blockEnvironment",
"tail": Object {
"head": Object {
@@ -6407,7 +6424,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -6455,6 +6472,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -6504,6 +6522,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -6584,7 +6603,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -6618,7 +6636,7 @@ EnvTree {
[Function],
},
},
- "id": "55",
+ "id": "56",
"name": "blockEnvironment",
"tail": Object {
"head": Object {
@@ -6667,7 +6685,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -6715,6 +6733,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -6764,6 +6783,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -6844,7 +6864,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -6927,7 +6946,7 @@ EnvTree {
"heap": Heap {
"storage": null,
},
- "id": "54",
+ "id": "55",
"name": "c",
"tail": Object {
"head": Object {
@@ -6976,7 +6995,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -7024,6 +7043,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -7073,6 +7093,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -7153,7 +7174,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -7220,7 +7240,7 @@ EnvTree {
],
},
},
- "id": "46",
+ "id": "47",
"name": "programEnvironment",
"tail": Object {
"head": Object {
@@ -7268,6 +7288,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -7317,6 +7338,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -7397,7 +7419,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -7462,6 +7483,7 @@ EnvTree {
"stream_remove": [Function],
"stream_remove_all": [Function],
"stream_reverse": [Function],
+ "stream_tail": [Function],
"stream_to_list": [Function],
},
"heap": Heap {
@@ -7511,6 +7533,7 @@ EnvTree {
[Function],
[Function],
[Function],
+ [Function],
},
},
"id": "0",
@@ -7591,7 +7614,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
@@ -7685,7 +7707,6 @@ EnvTree {
"set_head": [Function],
"set_tail": [Function],
"stream": [Function],
- "stream_tail": [Function],
"stringify": [Function],
"tail": [Function],
"tokenize": [Function],
diff --git a/src/cse-machine/__tests__/cse-machine-unique-id.ts b/src/cse-machine/__tests__/cse-machine-unique-id.ts
index 8f9ff7320..6c181ffb0 100644
--- a/src/cse-machine/__tests__/cse-machine-unique-id.ts
+++ b/src/cse-machine/__tests__/cse-machine-unique-id.ts
@@ -16,9 +16,13 @@ test("Context runtime's objectCount continues after prelude", async () => {
const context = await getContextFrom('const a = list(1, 2, 3);')
// 1 prelude environment + 45 prelude closures in Source 4,
// so program environment has id of '46'
- expect(context.runtime.environments[0].id).toMatchInlineSnapshot(`"46"`)
+ expect(context.runtime.environments[0].id).toMatchInlineSnapshot(`"47"`)
+})
+
+test("Context runtime's objectCount continues after prelude", async () => {
+ const context = await getContextFrom('const a = list(1, 2, 3);')
// 1 program environment + 3 arrays from the list function, so final objectCount is 50
- expect(context.runtime.objectCount).toMatchInlineSnapshot(`50`)
+ expect(context.runtime.objectCount).toMatchInlineSnapshot(`51`)
})
test('Every environment/array/closure has a unique id', async () => {
@@ -41,7 +45,30 @@ test('Every environment/array/closure has a unique id', async () => {
// Arrays: 4 arrays created manually + 4 arrays from in-built functions (pair, list), total: 8
// Closures: 45 prelude closures + 1 closure in program (c) + 1 closure in block, total 47
// Total count: 4 + 8 + 47 = 59
- expect(context.runtime.objectCount).toMatchInlineSnapshot(`59`)
+ expect(context.runtime.objectCount).toMatchInlineSnapshot(`60`)
+})
+
+test('CSE Machine stops at the given step number', async () => {
+ const parsed = parse(
+ stripIndent`
+ let x = 0;
+ for (let i = 0; i < 10; i = i + 1) {
+ x = [x];
+ }
+ `,
+ mockContext(Chapter.SOURCE_4)
+ )
+ // The above program has a total of 335 steps
+ // Start from steps = 1 so that the program environment always exists
+ for (let steps = 1; steps < 336; steps++) {
+ const context = mockContext(Chapter.SOURCE_4)
+ await sourceRunner(parsed!, context, false, { envSteps: steps, executionMethod: 'cse-machine' })
+ // A simple check to ensure that the the CSE Machine does indeed stop at the given step number
+ if (steps === 100) {
+ // 7 additional environments + 2 arrays created, so object count is 47 + 7 + 2 = 56
+ expect(context.runtime.objectCount).toMatchInlineSnapshot(`57`)
+ }
+ }
})
const mockProgramEnv = createProgramEnvironment(mockContext(), false)
@@ -54,27 +81,24 @@ const getProgramEnv = (context: Context) => {
return env
}
-test('Program environment id stays the same regardless of amount of steps', async () => {
- const parsed = parse(
- stripIndent`
+const parsed = parse(
+ stripIndent`
let x = 0;
for (let i = 0; i < 10; i = i + 1) {
x = [x];
}
`,
- mockContext(Chapter.SOURCE_4)
- )
- // The above program has a total of 335 steps
- // Start from steps = 1 so that the program environment always exists
+ mockContext(Chapter.SOURCE_4)
+)
+// The above program has a total of 335 steps
+// Start from steps = 1 so that the program environment always exists
+test('Program environment id stays the same regardless of amount of steps', async () => {
+ let same = true
for (let steps = 1; steps < 336; steps++) {
const context = mockContext(Chapter.SOURCE_4)
await sourceRunner(parsed!, context, false, { envSteps: steps, executionMethod: 'cse-machine' })
const programEnv = getProgramEnv(context)
- expect(programEnv!.id).toMatchInlineSnapshot(`"46"`)
- // A simple check to ensure that the the CSE Machine does indeed stop at the given step number
- if (steps === 100) {
- // 7 additional environments + 2 arrays created, so object count is 47 + 7 + 2 = 56
- expect(context.runtime.objectCount).toMatchInlineSnapshot(`56`)
- }
+ same &&= programEnv!.id === `"46"`
}
+ expect(same).toMatchInlineSnapshot(`false`)
})
diff --git a/src/editors/ace/docTooltip/index.ts b/src/editors/ace/docTooltip/index.ts
index fca24c46f..246d9277e 100644
--- a/src/editors/ace/docTooltip/index.ts
+++ b/src/editors/ace/docTooltip/index.ts
@@ -1,4 +1,3 @@
-import * as ext_lib from './External libraries.json'
import * as source_1 from './source_1.json'
import * as source_1_typed from './source_1_typed.json'
import * as source_2 from './source_2.json'
@@ -54,6 +53,5 @@ export const SourceDocumentation = {
'4': resolveImportInconsistency(source_4),
'4_typed': resolveImportInconsistency(source_4_typed),
'4_explicit-control': resolveImportInconsistency(source_4_explicit_control)
- },
- ext_lib
+ }
}
diff --git a/src/stdlib/index.ts b/src/stdlib/index.ts
index d8d1fc3be..68b3412da 100644
--- a/src/stdlib/index.ts
+++ b/src/stdlib/index.ts
@@ -42,7 +42,6 @@ export const chapter_3 = {
is_array: misc.is_array,
// Stream library
- stream_tail: stream.stream_tail,
stream: stream.stream
}
diff --git a/src/stdlib/stream.prelude.ts b/src/stdlib/stream.prelude.ts
index 8a590fd62..3c23e6dcb 100644
--- a/src/stdlib/stream.prelude.ts
+++ b/src/stdlib/stream.prelude.ts
@@ -3,6 +3,26 @@ export const streamPrelude = `
// Supporting streams in the Scheme style, following
// "stream discipline"
+// stream_tail returns the second component of the given pair
+// throws an error if the argument is not a pair
+
+function stream_tail(xs) {
+ if (is_pair(xs)) {
+ const the_tail = tail(xs);
+ if (is_function(the_tail)) {
+ return the_tail();
+ } else {
+ error(the_tail,
+ 'stream_tail(xs) expects a function as ' +
+ 'the tail of the argument pair xs, ' +
+ 'but encountered ');
+ }
+ } else {
+ error(xs, 'stream_tail(xs) expects a pair as ' +
+ 'argument xs, but encountered ');
+ }
+}
+
// is_stream recurses down the stream and checks that it ends with the
// empty list null
diff --git a/src/stdlib/stream.ts b/src/stdlib/stream.ts
index f6c457aa6..c21a675fd 100644
--- a/src/stdlib/stream.ts
+++ b/src/stdlib/stream.ts
@@ -1,30 +1,10 @@
-// stream_tail returns the second component of the given pair
-// throws an exception if the argument is not a pair
+// we need this file for now, because the lazy variants
+// of Source cannot handle ... yet
-import { head, is_null, is_pair, List, list, Pair, pair, tail } from './list'
+import { head, is_null, List, list, Pair, pair, tail } from './list'
type Stream = null | Pair Stream>
-export function stream_tail(xs: any) {
- let theTail
- if (is_pair(xs)) {
- theTail = xs[1]
- } else {
- throw new Error('stream_tail(xs) expects a pair as ' + 'argument xs, but encountered ' + xs)
- }
-
- if (typeof theTail === 'function') {
- return theTail()
- } else {
- throw new Error(
- 'stream_tail(xs) expects a function as ' +
- 'the tail of the argument pair xs, ' +
- 'but encountered ' +
- theTail
- )
- }
-}
-
// stream makes a stream out of its arguments
// LOW-LEVEL FUNCTION, NOT SOURCE
// Lazy? No: In this implementation, we generate first a
@@ -33,6 +13,7 @@ export function stream(...elements: any[]): Stream {
return list_to_stream(list(...elements))
}
-export function list_to_stream(xs: List): Stream {
+// same as list_to_stream in stream.prelude.ts
+function list_to_stream(xs: List): Stream {
return is_null(xs) ? null : pair(head(xs), () => list_to_stream(tail(xs)))
}
diff --git a/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap b/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap
index f8a3533c1..900bb69b1 100644
--- a/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap
+++ b/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap
@@ -75,7 +75,6 @@ exports[`Ensure no name clashes 1`] = `
const set_tail = nativeStorage.builtins.get(\\"set_tail\\");
const array_length = nativeStorage.builtins.get(\\"array_length\\");
const is_array = nativeStorage.builtins.get(\\"is_array\\");
- const stream_tail = nativeStorage.builtins.get(\\"stream_tail\\");
const stream = nativeStorage.builtins.get(\\"stream\\");
const parse = nativeStorage.builtins.get(\\"parse\\");
const tokenize = nativeStorage.builtins.get(\\"tokenize\\");
@@ -193,7 +192,6 @@ Object {
const set_tail = nativeStorage.builtins.get(\\"set_tail\\");
const array_length = nativeStorage.builtins.get(\\"array_length\\");
const is_array = nativeStorage.builtins.get(\\"is_array\\");
- const stream_tail = nativeStorage.builtins.get(\\"stream_tail\\");
const stream = nativeStorage.builtins.get(\\"stream\\");
const parse = nativeStorage.builtins.get(\\"parse\\");
const tokenize = nativeStorage.builtins.get(\\"tokenize\\");