# Solc AST generator

**URL:** <https://forum.soliditylang.org/t/solc-ast-generator/3258>\
**Category:** Uncategorized\
**Created:** [January 31, 2025, 2:04pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258 "2025-01-31T14:04:42Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![eldanba](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/eldanba/32/1111_2.png) [@eldanba](https://forum.soliditylang.org/u/eldanba)\
**Post date:** [January 31, 2025, 2:04pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/1 "2025-01-31T14:04:42Z")

</div>

I’m trying to obtain an AST from a solidity contract  
I cannot find anyway to achieve that using solc

I saw on previous versions there were --ast options in command line  
or other ast commands…  
Now i cannot find any of that

Tried also doing an input json with the contract but i get

> > > Cannot retry compilation with SMT because there are no SMT solvers available.  
> > > {“sources”:{“SolcTest.sol”:{“id”:0}}}  
> > > every time…

Is there a way to obtain an AST using solc ?

thanks

---

<div class="post-metadata">

**Author:** ![bonistech](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/bonistech/32/1478_2.png) [@bonistech](https://forum.soliditylang.org/u/bonistech)\
**Post date:** [February 5, 2025, 8:38am UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/2 "2025-02-05T08:38:27Z")

</div>

There are many ways to achieve such output. For example:

- `solc path/to/Contract.sol --ast-compact-json` returns AST in a JSON format.
- `solc path/to/Contract.sol --ir-ast-json` returns AST of Intermediate Representation (IR) of contract in a JSON format.
- `solc path/to/Contract.sol --ir-optimized-ast-json` returns AST of optimized Intermediate Representation (IR) of the contract in a JSON format.
- `solc path/to/Contract.sol --combined-json ast` returns a single JSON document containing the AST.

You can use `solc --help` and search for all the options you can use to get the AST.

---

<div class="post-metadata">

**Author:** ![eldanba](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/eldanba/32/1111_2.png) [@eldanba](https://forum.soliditylang.org/u/eldanba)\
**Post date:** [February 24, 2025, 11:54am UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/3 "2025-02-24T11:54:22Z")

</div>

thanks for the reply… but the reason i posted is because that doesn’t work  
This is my solc version:  
0.8.28+commit.7893614a.Emscripten.clang

This is my solc help  
$ npx solc --help  
Usage: solcjs [options]

Options:  
-V, --version output the version number  
–version Show version and exit.  
–optimize Enable bytecode optimizer. (default: false)  
–optimize-runs The number of runs specifies roughly how often each opcode of the deployed code will be executed across the lifetime of the contract. Lower values will optimize more for  
initial deployment cost, higher values will optimize more for high-frequency usage.  
–bin Binary of the contracts in hex.  
–abi ABI of the contracts.  
–standard-json Turn on Standard JSON Input / Output mode.  
–base-path Root of the project source tree. The import callback will attempt to interpret all import paths as relative to this directory.  
–include-path \<path…\> Extra source directories available to the import callback. When using a package manager to install libraries, use this option to specify directories where packages are  
installed. Can be used multiple times to provide multiple locations.  
-o, --output-dir Output directory for the contracts.  
-p, --pretty-json Pretty-print all JSON output. (default: false)  
-v, --verbose More detailed console output. (default: false)  
-h, --help display help for command

There is no ast option  
error: unknown option ‘–ast-compact-json’

---

<div class="post-metadata">

**Author:** ![r0qs](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/r0qs/32/709_2.png) [@r0qs](https://forum.soliditylang.org/u/r0qs)\
**Post date:** [February 24, 2025, 12:03pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/4 "2025-02-24T12:03:08Z")

</div>

Hi @eldanba, unlike the native `solc` binary, `solc-js` requires using the standard JSON input interface to specify AST outputs. Unfortunately, not all flags available in the native command-line binary are supported in `solc-js` via command-line.

This means you can only generate the AST by providing a JSON input that includes the desired output selection when using `solc-js`. For example:

```bash
npx solc --standard-json - <<EOF
{
  "language": "Solidity",
  "sources": {
    "test.sol": {
      "content": "contract C { function foo(uint x) external pure returns(uint) { return x + 2; }}"
    }
  },
  "settings": {
    "outputSelection": {
      "*": {
        "": ["ast"]
      }
    }
  }
}
EOF

```

or

```javascript
var solc = require("solc");

var input = {
  language: "Solidity",
  sources: {
    "test.sol": {
      content: "contract C { function foo(uint x) external pure returns(uint) { return x + 2; }}"
    }
  },
  settings: {
    outputSelection: {
      "*": {
        "": ["ast"]
      }
    }
  }
};

var output = JSON.parse(solc.compile(JSON.stringify(input)));
console.log(output.sources["test.sol"]);

```

Please check out our documentation for more details about the [Compiler Input and Output JSON Interface](https://docs.soliditylang.org/en/latest/using-the-compiler.html#compiler-input-and-output-json-description)

---

<div class="post-metadata">

**Author:** ![eldanba](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/eldanba/32/1111_2.png) [@eldanba](https://forum.soliditylang.org/u/eldanba)\
**Post date:** [February 24, 2025, 12:46pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/5 "2025-02-24T12:46:46Z")

</div>

> [@r0qs](#):
>
> `contract C { function foo(uint x) external pure returns(uint) { return x + 2; }}`

thanks a lot for your input @r0qs  
that did work with that small content.

i’m trying with a much bigger contract having some imports… it gives me:  
“message”: “Source "@openzeppelin/contracts/math/SafeMath.sol" not found: File import callback not supported”,

I understand the error because safeMath is not there… but i just want to generate the ast from the contract… dont care about dependencies  
Is there a way to bypass those kind of errors ?

---

<div class="post-metadata">

**Author:** ![r0qs](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/r0qs/32/709_2.png) [@r0qs](https://forum.soliditylang.org/u/r0qs)\
**Post date:** [February 24, 2025, 2:03pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/6 "2025-02-24T14:03:44Z")

</div>

I see, sadly, as far as I know, using `solc-js` the AST output is only file-level and not contract-level. So for your case I believe you would need to provide the missing import callback. You can see an example in javascript here: [Example usage with import callback](https://github.com/ethereum/solc-js?tab=readme-ov-file#example-usage-with-import-callback)

You can also use the flag `--base-path` so the compiler will be able to find the sources (see: [GitHub - ethereum/solc-js: Javascript bindings for the Solidity compiler](https://github.com/ethereum/solc-js?tab=readme-ov-file#usage-on-the-command-line)), for example, assuming that you have a `lib.sol` at the root directory of your project, you could do:

```auto
echo "library L{}" > lib.sol

npx solc --standard-json --base-path . - <<EOF
{
  "language": "Solidity",
  "sources": {
    "test.sol": {
      "content": "import \"lib.sol\"; contract C { function foo(uint x) external pure returns(uint) { return x + 2; }}"
    }
  },
  "settings": {
    "outputSelection": {
      "*": {
        "": ["ast"]
      }
    }
  }
}
EOF

```

---

<div class="post-metadata">

**Author:** ![r0qs](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/r0qs/32/709_2.png) [@r0qs](https://forum.soliditylang.org/u/r0qs)\
**Post date:** [February 24, 2025, 2:50pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/7 "2025-02-24T14:50:10Z")

</div>

Oh, actually, just a correction, you can have the AST output by “contract-level” in `solc-js` as well, the following should work (note the change in the `outputSelection` from `"*"` to `"test.sol"`). But it will also return an empty `sources` entry for all other sources as well.

```auto
echo "library L{}" > lib.sol

npx solc --standard-json --base-path . - <<EOF
{
  "language": "Solidity",
  "sources": {
    "test.sol": {
      "content": "import \"lib.sol\"; contract C { function foo(uint x) external pure returns(uint) { return x + 2; }}"
    }
  },
  "settings": {
    "outputSelection": {
      "test.sol": {
        "": ["ast"]
      }
    }
  }
}
EOF

```

But you are required to specify the import callback or use the `--base-path` which has a default import callback in any case.

---

<div class="post-metadata">

**Author:** ![eldanba](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/eldanba/32/1111_2.png) [@eldanba](https://forum.soliditylang.org/u/eldanba)\
**Post date:** [March 1, 2025, 8:06pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/8 "2025-03-01T20:06:27Z")

</div>

Thanks a lot for your answers, with examples and all… I really appreciate. I will try this, thanks again for taking the time!

---

<div class="post-metadata">

**Author:** ![eldanba](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/eldanba/32/1111_2.png) [@eldanba](https://forum.soliditylang.org/u/eldanba)\
**Post date:** [March 3, 2025, 6:57pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/9 "2025-03-03T18:57:44Z")

</div>

Im trying to execute this in node js as astGenerator.js  
This file is located in the same folder as ContractsFactory.sol which is the file I’m trying to get the AST and all import of that file are there (except the @openzeppelin ones that are in node\_modules)

```auto
const solc = require("solc");
const fs = require("fs");
const shell = require("shelljs");

const solcVersion = "0.8.28";
console.log("solc version:", solc.version());

const filename = "ContractsFactory.sol";

const sourceCode = fs.readFileSync(filename, "utf8");

const input = {
  language: "Solidity",
  sources: {
    // [filename]: {
    "ContractsFactory.sol": {
      content: sourceCode,
    },
  },
  settings: {
    outputSelection: {
      filename: {
        "": ["ast"],
      },
    },
  },
};

// Convert to json
const jsonInput = JSON.stringify(input);

const { code, stdout } = shell.exec(
  `npx solc --standard-json --base-path . - <<EOF
    ${input}
    EOF`
);

```

This is falling  
I tried different ways to do that, but I cannot make it work  
It will be a nice addition to solhint project to avoid depending on parsers and getting the AST directly

---

<div class="post-metadata">

**Author:** ![eldanba](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/eldanba/32/1111_2.png) [@eldanba](https://forum.soliditylang.org/u/eldanba)\
**Post date:** [March 3, 2025, 6:57pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/10 "2025-03-03T18:57:57Z")

</div>

i can also used `--include-path`

but when i executed i get:

node astGenerator.js  
solc version: 0.8.28+commit.7893614a.Emscripten.clang

> > > Cannot retry compilation with SMT because there are no SMT solvers available.  
> > > {“errors”:[{“component”:“general”,“formattedMessage”:“parse error at line 2, column 5: syntax error while parsing value - invalid literal; last read: ‘"ast"]}}}}\<U+000A\> E’; expected end of input”,“message”:“parse error at line 2, column 5: syntax error while parsing value - invalid literal; last read: ‘"ast"]}}}}\<U+000A\> E’; expected end of input”,“severity”:“error”,“type”:“JSONError”}]}  
> > > stdout: \>\>\> Cannot retry compilation with SMT because there are no SMT solvers available.  
> > > {“errors”:[{“component”:“general”,“formattedMessage”:“parse error at line 2, column 5: syntax error while parsing value - invalid literal; last read: ‘"ast"]}}}}\<U+000A\> E’; expected end of input”,“message”:“parse error at line 2, column 5: syntax error while parsing value - invalid literal; last read: ‘"ast"]}}}}\<U+000A\> E’; expected end of input”,“severity”:“error”,“type”:“JSONError”}]}

---

<div class="post-metadata">

**Author:** ![r0qs](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/r0qs/32/709_2.png) [@r0qs](https://forum.soliditylang.org/u/r0qs)\
**Post date:** [March 3, 2025, 11:07pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/11 "2025-03-03T23:07:21Z")

</div>

I see. Since you want to use `solc-js` as a library, the recommended approach is to define an import callback function that loads all contracts from disk and includes them in the JSON input. As shown in this example: [GitHub - ethereum/solc-js: Javascript bindings for the Solidity compiler](https://github.com/ethereum/solc-js?tab=readme-ov-file#example-usage-with-import-callback). Pay special attention to the `findImports` function and how it is used.

However, implementing this can be tricky, depending on your setup. If you’re using **Foundry** , it typically installs dependencies under `./lib` and applies remappings, while **Hardhat** relies on `node_modules`.

I created a small example that works with both Foundry and Hardhat. I haven’t exhaustively tested it, but I believe it should serve as a helpful guide to achieving what you’re trying to do.

```auto
forge init test --no-commit
cd test
forge install OpenZeppelin/openzeppelin-contracts --no-commit
echo "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/" > remappings.txt

```

astGenerator.js:

```javascript
const solc = require("solc");
const fs = require("fs");
const path = require("path");

console.log("solc version:", solc.version());

const projectRoot = path.resolve(__dirname);
const remappingsPath = path.join(projectRoot, "remappings.txt");
// Read remappings and store them in an object
const remappings = fs.existsSync(remappingsPath)
	? Object.fromEntries(
		fs.readFileSync(remappingsPath, "utf8")
			.split("\n")
			.map(line => line.trim())
			.filter(Boolean)
			.map(line => line.split("="))
	)
	: {};

// Remmapings lookups
function resolveWithRemappings(importPath) {
	for (const prefix in remappings) {
		if (importPath.startsWith(prefix)) {
			const resolvedPath = path.resolve(projectRoot, remappings[prefix], importPath.slice(prefix.length));
			return { contents: fs.readFileSync(resolvedPath, "utf8") };
		}
	}
	return null;
}

function findImports(importPath) {
	console.log(`Resolving import: ${importPath}`);

	// Remappings.txt
	const remappedImport = resolveWithRemappings(importPath);
	if (remappedImport) return remappedImport;

	// Node modules
	const nodeModulesPath = path.resolve(projectRoot, "node_modules", importPath);
	if (fs.existsSync(nodeModulesPath))
		return { contents: fs.readFileSync(nodeModulesPath, "utf8") };

	// Fallback to relative path
	const resolvedPath = path.resolve(projectRoot, importPath);
	if (fs.existsSync(resolvedPath))
		return { contents: fs.readFileSync(resolvedPath, "utf8") };

	return { error: `File not found: ${importPath}` };
}

const filename = "C.sol";
const sourceCode = fs.readFileSync("src/C.sol", "utf8");

// If you want to extract the AST of a single file:
var input = {
	language: "Solidity",
	sources: {
		[filename]: {
			content: sourceCode,
		},
	},
	settings: {
		outputSelection: {
			[filename]: {
				"": ["ast"],
			},
		},
	},
};

const output = JSON.parse(solc.compile(JSON.stringify(input), { import: findImports }));
if (output.sources && output.sources[filename]) {
	console.log(JSON.stringify(output.sources[filename].ast, null, 2));
} else {
	console.log("No AST found for", filename);
}

// If you want to extract the AST of all contracts:
// NOTE: remember to change the AST output selection to "*" in the settings
//Object.keys(output.sources || {}).forEach(contractName => {
//	console.log(`AST for ${contractName}:`);
//	console.log(JSON.stringify(output.sources[contractName].ast, null, 2));
//});

```

src/C.sol:

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

contract C is Ownable {
    constructor(address _owner) Ownable(_owner) {}
}

```

---

<div class="post-metadata">

**Author:** ![eldanba](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.soliditylang.org/eldanba/32/1111_2.png) [@eldanba](https://forum.soliditylang.org/u/eldanba)\
**Post date:** [March 6, 2025, 7:37pm UTC](https://forum.soliditylang.org/t/solc-ast-generator/3258/12 "2025-03-06T19:37:12Z")

</div>

Wow, thanks a lot for taking the time to this  
I will look into that … again I really appreciate

I guess the only blocker will be the fact that if we have different pragmas, solc versions need to be detected and downloaded beforehand for each contract to generate ast

Thanks!
