    {LRParser,LRParsingTable,Grammar,CanonicalCollection,LRParserGenerator} = require 'syntax-cli'
    {EntryType} = LRParsingTable
    SpecialSymbols = require 'syntax-cli/dist/special-symbols.js'
    Stream = require 'stream'
    vm = require 'vm'

    class StreamingLRParserGenerator extends LRParserGenerator
      constructor: ({grammar,options = {}}) ->
        super {grammar,options}

        @context =
          yytext: ''
          yyleng: 0
          __: null
          __handler: []
        context = vm.createContext @context
        @vm =
          eval: (code) -> vm.runInContext code, context

        return

This is in `traits`.

      buildSemanticAction: (production) ->
        # action is the text
        action = @getSemanticActionCode production

        return null unless action

        # args is the Array containing the argument names
        args = @getSemanticActionParams production

        # Save the action, they are injected later.
        # "__handler[1]", "__handler[2]", etc.
        index = production.getNumber()
        name = "__handler[#{index}]"
        handler = @vm.eval "__handler[#{index}] = async function (#{args}) {\n#{action}\n}"
        name

      generateModuleInclude: ->
        moduleInclude = @_grammar.getModuleInclude()
        if moduleInclude?
          @vm.eval moduleInclude
        return

Replaces the "template"

    class StreamingLRParser

      constructor: (generator) ->
        @_generator = generator
        @_grammar = generator._grammar
        @_table = generator.getTable()

        @_stack = []

        @_startingState = @_table._canonicalCollection
          .getStartingState()
          .getNumber()

        @_stack.push @_startingState
        @_shiftedToken = null

        return

      _peek: LRParser::_peek
      _shift: LRParser::_shift
      _reduce: (entry,token) ->

        productionNumber = entry.slice(1)
        production = this._grammar.getProduction(productionNumber)
        hasSemanticAction = production.hasSemanticAction()
        semanticValueArgs = if hasSemanticAction then [] else null

        locationArgs =
          if hasSemanticAction and this._grammar.shouldCaptureLocations() then [] else null

        # Pop 2x symbols from the stack (RHS + state number for each),
        # unless it's an ε-production for which nothing to pop.
        unless production.isEpsilon()
          rhsLengh = production.getRHS().length
          while rhsLengh--
            # Pop state number
            this._stack.pop()
            # Pop production symbol.
            stackEntry = this._stack.pop()

            if (hasSemanticAction)
              semanticValueArgs.unshift(stackEntry.semanticValue)

              if (locationArgs)
                locationArgs.unshift(stackEntry.loc)

        previousState = @_peek()
        symbolToReduceWith = production.getLHS().getSymbol()

        reduceStackEntry = {symbol: symbolToReduceWith}

        if hasSemanticAction
          @_generator.context.yytext = if token then token.value else ''
          @_generator.context.yyleng = if token then token.value.length else 0

          semanticActionArgs =
            if locationArgs isnt null
              semanticValueArgs.concat(locationArgs)
            else
              semanticValueArgs

          # Run corresponding semantic action, result is in $$ (__).
          handler = @_generator.context.__handler[productionNumber]
          await handler(semanticActionArgs...).catch console.error

          reduceStackEntry.semanticValue = @_generator.context.__

          if (locationArgs)
            reduceStackEntry.loc = CodeUnit.getSandbox().$$loc

        # Then push LHS.
        this._stack.push(reduceStackEntry)

        nextState = this._table.get()[previousState][symbolToReduceWith]

        # And push the next state (goto)
        this._stack.push(nextState)
        return

    class ParserTransform extends Stream.Transform

      constructor: (grammar,options = {}) ->
        options.objectMode = true
        super options

        generator = new StreamingLRParserGenerator {grammar}
        generator.generateParserData()
        generator.context.emit = (chunk) => @push chunk
        @parser = new StreamingLRParser generator
        return

      _transform: (chunk,encoding,next) ->

        token =
          type: if chunk.eof then SpecialSymbols.EOF else chunk.token
          value: chunk.text
          line: chunk.line
          column: chunk.column

        unless @parser._stack.length >= 1
          next new Error "Parser stack too small"
          return

        state = @parser._peek()
        column = token.type
        entry = @parser._table.get()[state][column]

        unless entry
          next new Error "Unexpected token #{column} in state #{state} at line #{token.line} column #{token.column}"
          return

        switch LRParsingTable.getEntryType(entry)

          when EntryType.SHIFT
            @parser._shift token, entry
            @parser._shiftedToken = token
            next()

          when EntryType.REDUCE
            do =>
              try
                await @parser._reduce entry, @parser._shiftedToken
                # Don't advance tokens on reduce.
                @_transform chunk,encoding,next
              catch error
                next error
                return

          when EntryType.SR_CONFLICT
            next new Error "ConflictError: shift-reduce in #{state}, #{column}"

          when EntryType.RR_CONFLICT
            next new Error "ConflictError: reduce-reduce in #{state}, #{column}"

          when EntryType.ACCEPT
            # Pop starting production and its state number.
            @parser._stack.pop()
            parsed = @parser._stack.pop()

            unless @parser._stack.length is 1 and @parser._stack[0] is @parser._startingState and chunk.eof
              next new Error "Unexpected token #{token}"
              return

            result = {status: 'accept'}

            if parsed.hasOwnProperty 'semanticValue'
              result.value = parsed.semanticValue

            @emit 'success', result
            next()

        return

      _final: (next) ->
        do =>
          error = null

          try
            while @parser._stack.length > 1
              await new Promise (resolve) =>
                @_transform eof:true, null, resolve
          catch error

          if error?
            next error
          else
            next()
          return
        return

    module.exports = ParserTransform
