mirror of
https://github.com/embarklabs/embark-nim-compiler.git
synced 2025-02-28 05:10:34 +00:00
use docker image to get the ABI
This commit is contained in:
parent
cc307b74d5
commit
bb52ce8de8
@ -18,6 +18,7 @@ then add embark-nim-compiler to the plugins section in `embark.json`:
|
||||
"plugins": {
|
||||
"embark-nim-compiler": {
|
||||
"setupBlockchainOptions": true,
|
||||
"useTestnet": false,
|
||||
"libHeraPath": "path/to/libHera.so"
|
||||
}
|
||||
}
|
||||
@ -31,4 +32,10 @@ then add embark-nim-compiler to the plugins section in `embark.json`:
|
||||
|
||||
- [Embark](https://www.npmjs.com/package/embark) 5.0.0 or higher
|
||||
- A valid eWasm ready node. See https://github.com/ewasm/testnet for more details
|
||||
- Docker
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
If you get an error related to docker or the image `jacqueswww/nimclang`, you might need to pull it first manually using:
|
||||
|
||||
```docker pull jacqueswww/nimclang```
|
||||
|
10
index.js
10
index.js
@ -11,6 +11,7 @@ class NimCompiler {
|
||||
constructor(embark) {
|
||||
this.events = embark.events;
|
||||
this.logger = embark.logger;
|
||||
this.dappPath = embark.dappPath;
|
||||
|
||||
embark.registerCompiler(".nim", this.compile.bind(this));
|
||||
|
||||
@ -30,7 +31,7 @@ class NimCompiler {
|
||||
genesisBlock: path.join(__dirname, './ewasm-testnet-geth-config.json'),
|
||||
bootnodes: "enode://53458e6bf0353f3378e115034cf6c6039b9faed52548da9030b37b4672de4a8fd09f869c48d16f9f10937e7398ae0dbe8b9d271408da7a0cf47f42a09e662827@23.101.78.254:30303"
|
||||
});
|
||||
cb(null, newConfig)
|
||||
cb(null, newConfig);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -54,15 +55,14 @@ class NimCompiler {
|
||||
compiledObject[className].code = codeHex;
|
||||
|
||||
// Get ABI from nim file
|
||||
exec(`${path.join(__dirname, './tools/abi_gen')} ${file.path}`, (err, stdout, stderr) => {
|
||||
exec(`docker run --entrypoint="abi_gen" -v "${this.dappPath('contracts')}":/code/ -w /code/ jacqueswww/nimclang ${path.basename(file.path)}`, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
this.logger.error('Error while getting ABI');
|
||||
this.logger.error(stderr);
|
||||
return eachCb(err);
|
||||
}
|
||||
try {
|
||||
const abi = JSON.parse(stdout);
|
||||
compiledObject[className].abiDefinition = abi;
|
||||
compiledObject[className].abiDefinition = JSON.parse(stdout);
|
||||
return eachCb();
|
||||
} catch (e) {
|
||||
return eachCb(e);
|
||||
@ -74,5 +74,5 @@ class NimCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = NimCompiler
|
||||
module.exports = NimCompiler;
|
||||
|
||||
|
BIN
tools/abi_gen
BIN
tools/abi_gen
Binary file not shown.
@ -1,245 +0,0 @@
|
||||
import compiler / [ast, vmdef, vm, nimeval, options, parser, idents, condsyms,
|
||||
nimconf, extccomp, astalgo, llstream, pathutils]
|
||||
import json
|
||||
import os
|
||||
|
||||
|
||||
import
|
||||
../nimplay/types
|
||||
|
||||
|
||||
type
|
||||
VariableType* = object
|
||||
name: string
|
||||
var_type: string
|
||||
|
||||
type
|
||||
EventType* = object
|
||||
name: string
|
||||
var_type: string
|
||||
indexed: bool
|
||||
|
||||
type
|
||||
FunctionSignature* = object
|
||||
name: string
|
||||
inputs: seq[VariableType]
|
||||
outputs: seq[VariableType]
|
||||
constant: bool
|
||||
payable: bool
|
||||
|
||||
type
|
||||
EventSignature* = object
|
||||
name: string
|
||||
inputs: seq[EventType]
|
||||
indexed: bool
|
||||
|
||||
|
||||
proc get_abi_type(nimplay_type_str: string): string =
|
||||
if nimplay_type_str in @["uint256", "bytes32", "int128", "uint128", "address"]:
|
||||
nimplay_type_str
|
||||
elif nimplay_type_str == "wei_value":
|
||||
"uint128"
|
||||
else:
|
||||
raise newException(Exception, "Unknown type: " & nimplay_type_str)
|
||||
|
||||
|
||||
proc string_to_ast*(s: string): PNode {.raises: [Exception] .} =
|
||||
var conf = newConfigRef()
|
||||
var cache = newIdentCache()
|
||||
condsyms.initDefines(conf.symbols)
|
||||
conf.projectName = "stdinfile"
|
||||
conf.projectFull = "stdinfile".AbsoluteFile
|
||||
conf.projectPath = canonicalizePath(conf, getCurrentDir().AbsoluteFile).AbsoluteDir
|
||||
conf.projectIsStdin = true
|
||||
loadConfigs(DefaultConfig, cache, conf)
|
||||
extccomp.initVars(conf)
|
||||
var node = parseString(s, cache, conf)
|
||||
if len(node.sons) > 1:
|
||||
result = node
|
||||
else:
|
||||
result = node.sons[0]
|
||||
|
||||
|
||||
proc generate_function_signature(proc_def: PNode): FunctionSignature =
|
||||
doAssert(proc_def.kind == nkFuncDef or proc_def.kind == nkProcDef)
|
||||
var
|
||||
func_sig = FunctionSignature()
|
||||
|
||||
for child in proc_def.sons:
|
||||
case child.kind:
|
||||
of nkPostfix:
|
||||
func_sig.name = child[1].ident.s
|
||||
of nkFormalParams:
|
||||
for param in child:
|
||||
case param.kind
|
||||
of nkIdent:
|
||||
func_sig.outputs.add(
|
||||
VariableType(
|
||||
name: "out1",
|
||||
var_type: get_abi_type(param.ident.s)
|
||||
)
|
||||
)
|
||||
of nkIdentDefs:
|
||||
func_sig.inputs.add(
|
||||
VariableType(
|
||||
name: param.sons[0].ident.s,
|
||||
var_type: get_abi_type(param.sons[1].ident.s)
|
||||
)
|
||||
)
|
||||
of nkEmpty:
|
||||
discard
|
||||
else:
|
||||
raise newException(Exception, "unknown param type")
|
||||
of nkPragma:
|
||||
for pragma_child in child:
|
||||
if pragma_child.kind == nkIdent and pragma_child.ident.s == "payable":
|
||||
func_sig.payable = true
|
||||
else:
|
||||
discard
|
||||
return func_sig
|
||||
|
||||
|
||||
proc generate_event_signature(proc_def: PNode): EventSignature =
|
||||
doAssert(proc_def.kind == nkProcDef)
|
||||
var
|
||||
event_sig = EventSignature()
|
||||
for child in proc_def.sons:
|
||||
case child.kind:
|
||||
of nkIdent:
|
||||
event_sig.name = child.ident.s
|
||||
of nkFormalParams:
|
||||
for param in child:
|
||||
if param.kind == nkIdentDefs:
|
||||
var
|
||||
ev: EventType
|
||||
if param[0].kind == nkPragmaExpr and param[0][1].kind == nkPragma:
|
||||
ev = EventType(
|
||||
name: param.sons[0].sons[0].ident.s,
|
||||
var_type: param.sons[1].ident.s,
|
||||
indexed: true
|
||||
)
|
||||
else:
|
||||
ev = EventType(
|
||||
name: param.sons[0].ident.s,
|
||||
var_type: param.sons[1].ident.s,
|
||||
indexed: false
|
||||
)
|
||||
event_sig.inputs.add(ev)
|
||||
else:
|
||||
discard
|
||||
|
||||
event_sig # return
|
||||
|
||||
|
||||
proc generateSignatures(stmts: PNode): (seq[FunctionSignature], seq[EventSignature]) =
|
||||
var
|
||||
public_functions: seq[FunctionSignature]
|
||||
events: seq[EventSignature]
|
||||
for child in stmts:
|
||||
if child.kind == nkCall and len(child.sons) > 2:
|
||||
var first_son = child.sons[0]
|
||||
if first_son.kind == nkIdent and first_son.ident.s == "contract":
|
||||
var main_block = child
|
||||
for b in main_block.sons:
|
||||
if b.kind == nkStmtList:
|
||||
for s in b.sons:
|
||||
if s.kind == nkVarSection: # handle getters.
|
||||
for var_def in s.sons:
|
||||
if var_def.kind == nkIdentDefs:
|
||||
var
|
||||
potential_postfix = var_def.sons[0]
|
||||
if potential_postfix.kind == nkPostfix and potential_postfix.sons[0].ident.s == "*":
|
||||
var
|
||||
func_name = potential_postfix.sons[1].ident.s
|
||||
type_name = var_def.sons[1].ident.s
|
||||
sig = FunctionSignature(name: func_name)
|
||||
sig.outputs.add(
|
||||
VariableType(name: "out1", var_type: get_abi_type(type_name))
|
||||
)
|
||||
public_functions.add(
|
||||
sig
|
||||
)
|
||||
elif s.kind == nkFuncDef or s.kind == nkProcDef:
|
||||
# only get public functions.
|
||||
if s[0].kind == nkPostfix and s[0][0].ident.s == "*":
|
||||
public_functions.add(
|
||||
generate_function_signature(s)
|
||||
)
|
||||
# handle event signature
|
||||
elif s[6].kind == nkEmpty:
|
||||
events.add(
|
||||
generate_event_signature(s)
|
||||
)
|
||||
return (public_functions, events)
|
||||
|
||||
|
||||
proc generateJSONABI(funcs: seq[FunctionSignature], events: seq[EventSignature]): string =
|
||||
var jsonObject = %* []
|
||||
|
||||
proc getVarTypes(var_types: seq[VariableType]): JsonNode =
|
||||
var types = %* []
|
||||
for t in var_types:
|
||||
types.add(%* {
|
||||
"name": t.name,
|
||||
"type": t.var_type,
|
||||
})
|
||||
types # return
|
||||
|
||||
|
||||
func getFunc(f: FunctionSignature): JsonNode =
|
||||
%* {
|
||||
"name": f.name,
|
||||
"inputs": getVarTypes(f.inputs),
|
||||
"outputs": getVarTypes(f.outputs),
|
||||
"constant": f.constant,
|
||||
"payable": f.payable,
|
||||
"type": "function"
|
||||
}
|
||||
|
||||
proc getEventTypes(var_types: seq[EventType]): JsonNode =
|
||||
var types = %* []
|
||||
for t in var_types:
|
||||
types.add(%* {
|
||||
"name": t.name,
|
||||
"type": t.var_type,
|
||||
"indexed": t.indexed
|
||||
})
|
||||
types
|
||||
|
||||
func getEvent(e: EventSignature): JsonNode =
|
||||
%* {
|
||||
"inputs": getEventTypes(e.inputs),
|
||||
"name": e.name,
|
||||
"type": "event",
|
||||
"anonymous": false
|
||||
}
|
||||
|
||||
for fn in funcs:
|
||||
jsonObject.add(getFunc(fn))
|
||||
|
||||
for event in events:
|
||||
jsonObject.add(getEvent(event))
|
||||
|
||||
$jsonObject # return
|
||||
|
||||
|
||||
proc main() =
|
||||
if paramCount() != 1:
|
||||
echo("Requires .nim file with contract() block macro")
|
||||
quit()
|
||||
if not existsFile(commandLineParams()[0]):
|
||||
echo("Requires .nim file with contract() block macro")
|
||||
quit()
|
||||
|
||||
var nimFile = commandLineParams()[0]
|
||||
let node = string_to_ast(readFile(nimFile))
|
||||
|
||||
if node.kind == nkStmtList:
|
||||
let (functions, events) = generateSignatures(node)
|
||||
echo(generateJSONABI(functions, events))
|
||||
else:
|
||||
raise newException(Exception, "Expected nkStmtList")
|
||||
|
||||
|
||||
when is_main_module:
|
||||
main()
|
Loading…
x
Reference in New Issue
Block a user