moinejf/abc2svg

syntax errors in injected code within modules

Closed this issue · 6 comments

bwl21 commented

I tried to integrate the new 1.8.0 and faced some problems:

perc.js:270 injected line is not terminated

abc2svg.inject += '\
Abc.prototype.get_maps = function maps() { return maps }
var perc = {\n\
`

same in

midi.js:135

It is somehow a maintenance problem that the module approach requires JS-code provided as string. So you do not have syntax highlighting and while editing the same. Also there is no syntax validation on load time.

I propose the following approach (inspired by https://stackoverflow.com/questions/2108973/inject-javascript-into-a-javascript-function):

  1. define the code to be injected as the body of a function
  2. get_injectcode takes the source of this function an strips the first and the last line such that only the body is left over.
  3. This can then be passed eval.

The following example shows that

  1. the body of inject has access to the variables in the scope of eval - statement (in this case foo)
  2. after evaluating the injected code, variables defined therein are available within foo
function inject(){
  console.log('injected ' + a);
  var b = 2 * a
}

function get_injectcode(func){
  return func.toString().split("\n").slice(1,-1).join("\n")
}


function foo(){
  var a=10;
  console.log('global ' + a);
  code = get_injectcode(inject)
  eval(code)
  console.log(b)
}


console.log(inject.toString())

foo();
bwl21 commented

I still don't fully understand how the modules work, but I think

// inject code inside the core
abc2svg.inject += '\
Abc.prototype.get_maps = function maps() { return maps }\n\
var perc = {\n\
	psc: do_pscom,\n\
	svp: set_vp\n\
}\n\
do_pscom = function(text) {\n\
	if (text.slice(0, 8) == "percmap ")\n\
		abc2svg.perc.do_perc(self, text)\n\
	else\n\
		perc.psc(text)\n\
}\n\
set_vp = function(a) {\n\
	abc2svg.perc.set_perc(self, a);\n\
	perc.svp(a)\n\
}\n\
'

could be replaced by (you see we get syntax higlighting for the injected code as well)

// inject code inside the core
abc2svg.inject += get_injectcode(function () {
    Abc.prototype.get_maps = function maps() {
      return maps
    }
    var perc = {
      psc: do_pscom,
      svp: set_vp
    }
    do_pscom = function (text) {
      if (text.slice(0, 8) == "percmap ")
        abc2svg.perc.do_perc(self, text)
      else
        perc.psc(text)
    }
    set_vp = function (a) {
      abc2svg.perc.set_perc(self, a);
      perc.svp(a)
    }
  }
))

This approach would drastically improve IDE support for injected code (code formatting, partial cross referencing etc.).

bwl21 commented

I investigated further how the approach works with minified code.

  1. need to use a regular expression in get_injectcode such that it does not depend the line breaks in the the source.
function get_injectcode(func){
  re = /^function.*\{(.*)\}/
  return func.toString().replace(re, $1);
}
  1. uglifyjs removes var if the such defined object is not used further within the function

  2. I am not sure about the consequences of name mangling. For example perc will be mangled and therefore not be available outside of the injected block.

bwl21 commented

If you plan to change the code according to my proposal, then we keep it open. Otherwise please feel free to close it.

About name mangling, I hope noone will set this option in uglify: this asks for a lot of computation and the gain is really small.
I found an other solution: only exporting functions and setting hooks would call eval().
I have done the job for %%capo and %%grid. Do you want to have a look?

bwl21 commented

In which commit can i find thIs?

bwl21 commented

This issue is solved with the new module system

  • 2158e36 - core: remove old module interface
  • commits for all modules
  • 0ceed88 - core: add a new inject mecanism for the modules