Giter Club home page Giter Club logo

jankscripten's Issues

The visitor used to desugar JavaScript does not support mutating ancestors of the parent node

Although the values of a node are &mut, when it is further up the stack, that &mut is behind a &Context, thus is immutable. The technique that we used for blocks -- where the node accumulates a list of patches that we later apply -- will work in general. Here is an example using a binary tree:

use std::cell::Cell;

pub enum BinTree {
    Leaf,
    Node(Box<BinTree>, usize, Box<BinTree>)
}

pub struct Replaceable<'a, T> {
    value: &'a mut T,
    new_value: Cell<Option<T>>
}

impl<'a, T> Replaceable<'a, T> {
    fn new(value: &'a mut T) -> Replaceable<'a, T> {
        Replaceable {
            value: value,
            new_value: Cell::new(None)
        }
    }

    fn get(&self) -> &T {
        self.value
    }

    fn set(&self, value: T) { 
        self.new_value.set(Some(value));
    }

    fn update(&mut self)  {
        if let Some(x) = self.new_value.take() {
            *self.value = x;
        }
    }
}

pub enum Context1<'a> {
    Left(&'a Replaceable<'a, usize>, &'a Replaceable<'a, BinTree>),
    Right(&'a Replaceable<'a, BinTree>, &'a Replaceable<'a, usize>)
}

pub enum Context<'a> {
    Nil,
    Cons(Context1<'a>, &'a Context<'a>)
}

pub trait Visitor {
    fn enter(&mut self, _node: &mut BinTree, _context: &Context) {
        // Do nothing by default
    }

    fn exit(&mut self, _node: &mut BinTree, _context: &Context) {
        // Do nothing by default
    }
}

pub fn visit_rec<'a, 'b>(tree: &'a mut BinTree, cxt: &'a Context<'a>, visitor: &mut impl Visitor) {
    visitor.enter(tree, cxt);
    match tree {
        BinTree::Leaf => { },
        BinTree::Node(lhs, value, rhs) => {
                  
                let mut value_cell = Replaceable::new(value);
                let mut rhs_cell = Replaceable::new(rhs.as_mut());
                let lhs_cxt = Context::Cons(Context1::Left(&value_cell, &rhs_cell), cxt);
                visit_rec(lhs, &lhs_cxt, visitor);
                value_cell.update();
                rhs_cell.update();
                
                let mut value_cell = Replaceable::new(value);
                let mut lhs_cell = Replaceable::new(lhs.as_mut());
                let mut rhs_cxt = Context::Cons(Context1::Right(&lhs_cell, &value_cell), cxt);
                visit_rec(rhs, &mut rhs_cxt, visitor);
                value_cell.update();
                lhs_cell.update();
        }
    }
    visitor.exit(tree, cxt);
}


pub fn visit(tree: & mut BinTree, visitor: &mut impl Visitor) {
    let mut cxt = Context::Nil;
    visit_rec(tree, &mut cxt, visitor);
}

GotoWasm: loop guard

Consider the case when the goto target is inside a loop. Given a while loop:

while (atom) block, we can rewrite atom using ideas similar to what we have done for if-statements.

NotWasm has an unguarded loop, so we would need to wrap the whole loop in an if-statement.

Correctly handle `var`, `let`, and `const`

Currently, all 3 ways of declaring a variable are handled like var inside jankscripten. This stemmed from a parser bug in the old parser, and I had to replicate the bug in the new parser in order to get the tests to pass.

I'm not sure if we already decided to support let or const, but I don't think there's any machinery implemented for them already. We might be able to get away with treating const like var. let might be trickier to ignore, since it has different scoping rules than var, which some of our programs may rely on.

Consolidate desugar testing

Right now, we have tests for desugaring scattered across a number of modules. We should instead do the following:

  • Ensure that all desugaring passes are called by the main desugar function
  • Ensure that all tests use desugar_okay
  • Ensure that all tests end with an expression that is likely to return the wrong value if desugaring goes wrong.
  • Collect all tests in a single module.

GotoWasm: condition on false branches missing

The false branch of an if statement needs a guard as well:

S[[if (e) s1 else s2]] = 
  if ((!inGoto && e) || (inGoto && gotoTarget ∊ L[[s1]])) S[[s1]]
  else (!inGoto || (inGoto && gotoTarget ∊ L[[s2]])) S[[s2]]

Recommend Projects

  • React photo React

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

  • Vue.js photo Vue.js

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

  • Typescript photo Typescript

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

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

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

  • web

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

  • server

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

  • Machine learning

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

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

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

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.