Skip to content
This repository has been archived by the owner on Mar 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #32 from trufflesuite/develop
Browse files Browse the repository at this point in the history
Merge develop -> master for Truffle 4 release
  • Loading branch information
gnidan authored Oct 31, 2017
2 parents e320bcf + ebb9e1b commit 6fa455d
Show file tree
Hide file tree
Showing 9 changed files with 377 additions and 60 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules
yarn.lock
package-lock.json
2 changes: 1 addition & 1 deletion compileerror.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ inherits(CompileError, TruffleError);

function CompileError(message) {
// Note we trim() because solc likes to add extra whitespace.
var fancy_message = message.trim() + "\n" + colors.red("Compiliation failed. See above.");
var fancy_message = message.trim() + "\n" + colors.red("Compilation failed. See above.");
var normal_message = message.trim();

CompileError.super_.call(this, normal_message);
Expand Down
41 changes: 26 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
var Profiler = require("./profiler");
var OS = require("os");
var solc = require("solc");

// Clean up after solc.
var listeners = process.listeners("uncaughtException");
var solc_listener = listeners[listeners.length - 1];

if (solc_listener) {
process.removeListener("uncaughtException", solc_listener);
}

var path = require("path");
var fs = require("fs");
Expand All @@ -18,6 +9,7 @@ var CompileError = require("./compileerror");
var expect = require("truffle-expect");
var find_contracts = require("truffle-contract-sources");
var Config = require("truffle-config");
var debug = require("debug")("compile");

// Most basic of the compile commands. Takes a hash of sources, where
// the keys are file or module paths and the values are the bodies of
Expand All @@ -44,9 +36,21 @@ var compile = function(sources, options, callback) {
"solc"
]);

// Load solc module only when compilation is actually required.
var solc = require("solc");
// Clean up after solc.
var listeners = process.listeners("uncaughtException");
var solc_listener = listeners[listeners.length - 1];

if (solc_listener) {
process.removeListener("uncaughtException", solc_listener);
}


// Ensure sources have operating system independent paths
// i.e., convert backslashes to forward slashes; things like C: are left intact.
var operatingSystemIndependentSources = {};
var originalPathMappings = {};

Object.keys(sources).forEach(function(source) {
// Turn all backslashes into forward slashes
Expand All @@ -60,6 +64,9 @@ var compile = function(sources, options, callback) {

// Save the result
operatingSystemIndependentSources[replacement] = sources[source];

// Map the replacement back to the original source path.
originalPathMappings[replacement] = source;
});

var solcStandardInput = {
Expand Down Expand Up @@ -137,15 +144,19 @@ var compile = function(sources, options, callback) {

var contract_definition = {
contract_name: contract_name,
sourcePath: source_path,
sourcePath: originalPathMappings[source_path], // Save original source path, not modified ones
source: operatingSystemIndependentSources[source_path],
sourceMap: contract.evm.bytecode.sourceMap,
runtimeSourceMap: contract.evm.deployedBytecode.sourceMap,
deployedSourceMap: contract.evm.deployedBytecode.sourceMap,
ast: standardOutput.sources[source_path].legacyAST,
abi: contract.abi,
bytecode: "0x" + contract.evm.bytecode.object,
runtimeBytecode: "0x" + contract.evm.deployedBytecode.object,
unlinked_binary: "0x" + contract.evm.bytecode.object // deprecated
deployedBytecode: "0x" + contract.evm.deployedBytecode.object,
unlinked_binary: "0x" + contract.evm.bytecode.object, // deprecated
compiler: {
"name": "solc",
"version": solc.version()
}
}

// Go through the link references and replace them with older-style
Expand All @@ -162,14 +173,14 @@ var compile = function(sources, options, callback) {
});
});

// Now for the runtime bytecode
// Now for the deployed bytecode
Object.keys(contract.evm.deployedBytecode.linkReferences).forEach(function(file_name) {
var fileLinks = contract.evm.deployedBytecode.linkReferences[file_name];

Object.keys(fileLinks).forEach(function(library_name) {
var linkReferences = fileLinks[library_name] || [];

contract_definition.runtimeBytecode = replaceLinkReferences(contract_definition.runtimeBytecode, linkReferences, library_name);
contract_definition.deployedBytecode = replaceLinkReferences(contract_definition.deployedBytecode, linkReferences, library_name);
});
});

Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
{
"name": "truffle-compile",
"version": "2.0.7",
"version": "3.0.1",
"description": "Compiler helper and artifact manager",
"main": "index.js",
"dependencies": {
"async": "^2.1.4",
"colors": "^1.1.2",
"debug": "^3.1.0",
"graphlib": "^2.1.1",
"solc": "0.4.15",
"solidity-parser": "^0.3.0",
"solc": "0.4.18",
"truffle-config": "^1.0.2",
"truffle-contract-sources": "^0.0.1",
"truffle-error": "^0.0.2",
"truffle-expect": "^0.0.3"
},
"devDependencies": {},
"devDependencies": {
"mocha": "^3.5.3",
"truffle-resolver": "2.0.0"
},
"scripts": {
"test": "mocha"
},
Expand Down
124 changes: 124 additions & 0 deletions parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
var CompileError = require("./compileerror");
var solc = require("solc");

// Clean up after solc.
var listeners = process.listeners("uncaughtException");
var solc_listener = listeners[listeners.length - 1];

if (solc_listener) {
process.removeListener("uncaughtException", solc_listener);
}

module.exports = {
parse: function(body, fileName) {
// Here, we want a valid AST even if imports don't exist. The way to
// get around that is to tell the compiler, as they happen, that we
// have source for them (an empty file).

var fileName = fileName || "ParsedContract.sol";

var solcStandardInput = {
language: "Solidity",
sources: {
[fileName]: {
content: body
}
},
settings: {
outputSelection: {
[fileName]: {
"*": ["ast"]
}
}
}
};

var output = solc.compileStandard(JSON.stringify(solcStandardInput), function(file_path) {
// Tell the compiler we have source code for the dependency
return {contents: "pragma solidity ^0.4.0;"};
});

output = JSON.parse(output);

if (output.errors) {
throw new CompileError(output.errors[0].formattedMessage);
}

return {
contracts: Object.keys(output.contracts[fileName]),
ast: output.sources[fileName].ast
};
},

// This needs to be fast! It is fast (as of this writing). Keep it fast!
parseImports: function(body) {
var self = this;

// WARNING: Kind of a hack (an expedient one).

// So we don't have to maintain a separate parser, we'll get all the imports
// in a file by sending the file to solc and evaluating the error messages
// to see what import statements couldn't be resolved. To prevent full-on
// compilation when a file has no import statements, we inject an import
// statement right on the end; just to ensure it will error and we can parse
// the imports speedily without doing extra work.

// Helper to detect import errors with an easy regex.
var importErrorKey = "TRUFFLE_IMPORT";

// Inject failing import.
var failingImportFileName = "__Truffle__NotFound.sol";

body = body + "\n\nimport '" + failingImportFileName + "';\n";

var solcStandardInput = {
language: "Solidity",
sources: {
"ParsedContract.sol": {
content: body
}
},
settings: {
outputSelection: {
"ParsedContract.sol": {
"*": [] // We don't need any output.
}
}
}
};

var output = solc.compileStandard(JSON.stringify(solcStandardInput), function() {
// The existence of this function ensures we get a parsable error message.
// Without this, we'll get an error message we *can* detect, but the key will make it easier.
// Note: This is not a normal callback. See docs here: https://github.com/ethereum/solc-js#from-version-021
return {error: importErrorKey};
});

output = JSON.parse(output);

var nonImportErrors = output.errors.filter(function(solidity_error) {
// If the import error key is not found, we must not have an import error.
// This means we have a *different* parsing error which we should show to the user.
// Note: solc can return multiple parsing errors at once.
return solidity_error.formattedMessage.indexOf(importErrorKey) < 0;
});

// Should we try to throw more than one? (aside; we didn't before)
if (nonImportErrors.length > 0) {
throw new CompileError(nonImportErrors[0].formattedMessage);
}

// Now, all errors must be import errors.
// Filter out our forced import, then get the import paths of the rest.
var imports = output.errors.filter(function(solidity_error) {
return solidity_error.message.indexOf(failingImportFileName) < 0;
}).map(function(solidity_error) {
var matches = solidity_error.formattedMessage.match(/import[^'"]+("|')([^'"]+)("|');/);

// Return the item between the quotes.
return matches[2];
});

return imports;
}
}
Loading

0 comments on commit 6fa455d

Please sign in to comment.