parent
fbe522ebc0
commit
b57d751da2
@ -0,0 +1,203 @@ |
||||
var queryParams = require('./query-params'); |
||||
|
||||
function Compiler(editor, renderContracts, renderError, errortype, fileNameFromKey, fileKey, handleGithubCall, outputField, hidingRHP) { |
||||
|
||||
var compileJSON; |
||||
var compilerAcceptsMultipleFiles; |
||||
|
||||
var previousInput = ''; |
||||
var sourceAnnotations = []; |
||||
|
||||
var cachedRemoteFiles = {}; |
||||
var worker = null; |
||||
|
||||
var compileTimeout = null; |
||||
|
||||
function onChange() { |
||||
var input = editor.getValue(); |
||||
if (input === "") { |
||||
window.localStorage.setItem(editor.getCacheFile(), ''); |
||||
return; |
||||
} |
||||
if (input === previousInput) |
||||
return; |
||||
previousInput = input; |
||||
if (compileTimeout) window.clearTimeout(compileTimeout); |
||||
compileTimeout = window.setTimeout(compile, 300); |
||||
} |
||||
|
||||
editor.onChangeSetup(onChange); |
||||
|
||||
var compile = function(missingInputs) { |
||||
editor.clearAnnotations(); |
||||
sourceAnnotations = []; |
||||
outputField.empty(); |
||||
var input = editor.getValue(); |
||||
window.localStorage.setItem(editor.getCacheFile(), input); |
||||
|
||||
var files = {}; |
||||
files[fileNameFromKey(editor.getCacheFile())] = input; |
||||
gatherImports(files, missingInputs, function(input, error) { |
||||
outputField.empty(); |
||||
if (input === null) { |
||||
renderError(error); |
||||
} else { |
||||
var optimize = queryParams.get().optimize; |
||||
compileJSON(input, optimize ? 1 : 0); |
||||
} |
||||
}); |
||||
}; |
||||
this.compile = compile; |
||||
|
||||
this.addAnnotation = function(annotation) { |
||||
sourceAnnotations[sourceAnnotations.length] = annotation; |
||||
editor.setAnnotations(sourceAnnotations); |
||||
}; |
||||
|
||||
this.setCompileJSON = function() { |
||||
compileJSON = function(source, optimize) { compilationFinished('{}'); };
|
||||
}; |
||||
|
||||
function onCompilerLoaded(setVersionText) { |
||||
if (worker === null) { |
||||
var compile; |
||||
var missingInputs = []; |
||||
if ('_compileJSONCallback' in Module) { |
||||
compilerAcceptsMultipleFiles = true; |
||||
var missingInputsCallback = Module.Runtime.addFunction(function(path, contents, error) { |
||||
missingInputs.push(Module.Pointer_stringify(path)); |
||||
}); |
||||
var compileInternal = Module.cwrap("compileJSONCallback", "string", ["string", "number", "number"]); |
||||
compile = function(input, optimize) { |
||||
missingInputs.length = 0; |
||||
return compileInternal(input, optimize, missingInputsCallback); |
||||
}; |
||||
} else if ('_compileJSONMulti' in Module) { |
||||
compilerAcceptsMultipleFiles = true; |
||||
compile = Module.cwrap("compileJSONMulti", "string", ["string", "number"]); |
||||
} else { |
||||
compilerAcceptsMultipleFiles = false; |
||||
compile = Module.cwrap("compileJSON", "string", ["string", "number"]); |
||||
} |
||||
compileJSON = function(source, optimize, cb) { |
||||
try { |
||||
var result = compile(source, optimize); |
||||
} catch (exception) { |
||||
result = JSON.stringify({error: 'Uncaught JavaScript exception:\n' + exception}); |
||||
} |
||||
compilationFinished(result, missingInputs); |
||||
}; |
||||
setVersionText(Module.cwrap("version", "string", [])()); |
||||
} |
||||
previousInput = ''; |
||||
onChange(); |
||||
}; |
||||
this.onCompilerLoaded = onCompilerLoaded; |
||||
|
||||
function compilationFinished(result, missingInputs) { |
||||
var data; |
||||
var noFatalErrors = true; // ie warnings are ok
|
||||
|
||||
try { |
||||
data = JSON.parse(result); |
||||
} catch (exception) { |
||||
renderError('Invalid JSON output from the compiler: ' + exception); |
||||
return; |
||||
} |
||||
|
||||
if (data['error'] !== undefined) { |
||||
renderError(data['error']); |
||||
if (errortype(data['error']) !== 'warning') noFatalErrors = false; |
||||
} |
||||
if (data['errors'] != undefined) { |
||||
data['errors'].forEach(function(err) { |
||||
renderError(err); |
||||
if (errortype(err) !== 'warning') noFatalErrors = false; |
||||
}); |
||||
} |
||||
|
||||
if (missingInputs !== undefined && missingInputs.length > 0) |
||||
this.compile(missingInputs); |
||||
else if (noFatalErrors && !hidingRHP()) |
||||
renderContracts(data, editor.getValue()); |
||||
} |
||||
|
||||
this.initializeWorker = function(version, setVersionText) { |
||||
if (worker !== null) |
||||
worker.terminate(); |
||||
worker = new Worker('worker.js'); |
||||
worker.addEventListener('message', function(msg) { |
||||
var data = msg.data; |
||||
switch (data.cmd) { |
||||
case 'versionLoaded': |
||||
setVersionText(data.data); |
||||
compilerAcceptsMultipleFiles = !!data.acceptsMultipleFiles; |
||||
onCompilerLoaded(setVersionText); |
||||
break; |
||||
case 'compiled': |
||||
compilationFinished(data.data, data.missingInputs); |
||||
break; |
||||
}; |
||||
}); |
||||
worker.onerror = function(msg) { console.log(msg.data); }; |
||||
worker.addEventListener('error', function(msg) { console.log(msg.data); }); |
||||
compileJSON = function(source, optimize) { |
||||
worker.postMessage({cmd: 'compile', source: source, optimize: optimize}); |
||||
}; |
||||
worker.postMessage({cmd: 'loadVersion', data: 'https://ethereum.github.io/solc-bin/bin/' + version}); |
||||
}; |
||||
|
||||
function gatherImports(files, importHints, cb) { |
||||
importHints = importHints || []; |
||||
if (!compilerAcceptsMultipleFiles) |
||||
{ |
||||
cb(files[fileNameFromKey(editor.getCacheFile())]); |
||||
return; |
||||
} |
||||
var importRegex = /^\s*import\s*[\'\"]([^\'\"]+)[\'\"];/g; |
||||
var reloop = false; |
||||
do { |
||||
reloop = false; |
||||
for (var fileName in files) { |
||||
var match; |
||||
while (match = importRegex.exec(files[fileName])) |
||||
importHints.push(match[1]); |
||||
} |
||||
while (importHints.length > 0) { |
||||
var m = importHints.pop(); |
||||
if (m in files) continue; |
||||
if (editor.getFiles().indexOf(fileKey(m)) !== -1) { |
||||
files[m] = window.localStorage[fileKey(m)]; |
||||
reloop = true; |
||||
} else if (m.startsWith('./') && editor.getFiles().indexOf(fileKey(m.slice(2))) !== -1) { |
||||
files[m] = window.localStorage[fileKey(m.slice(2))]; |
||||
reloop = true; |
||||
} else if (m in cachedRemoteFiles) { |
||||
files[m] = cachedRemoteFiles[m]; |
||||
reloop = true; |
||||
} else if (githubMatch = /^(https?:\/\/)?(www.)?github.com\/([^\/]*\/[^\/]*)\/(.*)/.exec(m)) { |
||||
handleGithubCall(function(result) { |
||||
if ('content' in result) |
||||
{ |
||||
var content = Base64.decode(result.content); |
||||
cachedRemoteFiles[m] = content; |
||||
files[m] = content; |
||||
gatherImports(files, importHints, cb); |
||||
} |
||||
else |
||||
cb(null, "Unable to import \"" + m + "\""); |
||||
}).fail(function(){ |
||||
cb(null, "Unable to import \"" + m + "\""); |
||||
}); |
||||
return; |
||||
} else { |
||||
cb(null, "Unable to import \"" + m + "\""); |
||||
return; |
||||
} |
||||
} |
||||
} while (reloop); |
||||
cb(JSON.stringify({'sources':files})); |
||||
} |
||||
} |
||||
|
||||
module.exports = Compiler |
Loading…
Reference in new issue