Skip to content

Commit

Permalink
Support for imports with ABIs
Browse files Browse the repository at this point in the history
  • Loading branch information
Relfos committed Sep 21, 2023
1 parent 61243e7 commit 1b6d26f
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 1 deletion.
7 changes: 7 additions & 0 deletions Compiler/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ static void Main(string[] args)
break;
}

case "libpath":
{
Module.AddLibraryPath(value);
break;
}

case "debug":
{
Compiler.DebugMode = true;
Expand Down Expand Up @@ -221,6 +227,7 @@ static void Main(string[] args)
Directory.CreateDirectory(outputPath);
}

Module.AddLibraryPath(outputPath);
Console.WriteLine("Output path: " + outputPath);

var sourceCode = File.ReadAllText(sourceFileName);
Expand Down
36 changes: 36 additions & 0 deletions Library/src/AST/MethodInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,5 +218,41 @@ public static VMType ConvertType(VarKind kind)
}
}

public static VarKind ConvertType(VMType type)
{
switch (type)
{
case VMType.Object:
return VarKind.Address; // WARNING this is not valid in some situations...

case VMType.Bytes:
return VarKind.Bytes;

case VMType.Bool:
return VarKind.Bool;

case VMType.Enum:
return VarKind.Enum;

case VMType.Number:
return VarKind.Number;

case VMType.String:
return VarKind.String;

case VMType.Timestamp:
return VarKind.Timestamp;

case VMType.None:
return VarKind.None;

case VMType.Struct:
return VarKind.Struct;

default:
throw new System.Exception("Not a valid vm type: " + type);
}
}

}
}
74 changes: 73 additions & 1 deletion Library/src/CodeGen/Libraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ namespace Phantasma.Tomb.CodeGen
{
public partial class Module
{
private static List<string> _abiPaths = new List<string>();

public static void AddLibraryPath(string path)
{
if (!path.EndsWith(Path.DirectorySeparatorChar))
{
path += Path.DirectorySeparatorChar;
}

_abiPaths.Add(path);
}

public void ImportLibrary(string name)
{
var lib = LoadLibrary(name, this.Scope, this.Kind);
Expand Down Expand Up @@ -750,10 +762,70 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin
break;
}
default:
throw new CompilerException("unknown library: " + name);
return FindExternalLibrary(name, scope, moduleKind);
}

return libDecl;
}

private static Dictionary<string, LibraryDeclaration> _externalLibs = new Dictionary<string, LibraryDeclaration>(StringComparer.OrdinalIgnoreCase);

private static LibraryDeclaration FindExternalLibrary(string name, Scope scope, ModuleKind moduleKind)
{
if (_externalLibs.ContainsKey(name))
{
return _externalLibs[name];
}

string libraryFileName = null;

foreach (var path in _abiPaths)
{
var possibleName = $"{path}{name}.abi";
if (File.Exists(possibleName))
{
libraryFileName = possibleName;
break;
}
}

if (!string.IsNullOrEmpty(libraryFileName))
{
try
{
var bytes = File.ReadAllBytes(libraryFileName);
var abi = ContractInterface.FromBytes(bytes);

var libDecl = new LibraryDeclaration(scope, name);

foreach (var method in abi.Methods)
{
var returnType = MethodInterface.ConvertType(method.returnType);

var parameters = new List<MethodParameter>();

foreach (var param in method.parameters)
{
var paramType = MethodInterface.ConvertType(param.type);
parameters.Add(new MethodParameter(param.name, paramType));
}

libDecl.AddMethod(method.name, MethodImplementationType.ContractCall, returnType, parameters.ToArray()).SetContract(name);
}

Builtins.FillLibrary(libDecl);

_externalLibs[name] = libDecl;

return libDecl;
}
catch (Exception e)
{
throw new CompilerException("unable to load library: " + libraryFileName);
}
}

throw new CompilerException("unknown library: " + name);
}
}
}
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,30 @@ throw "something happened";
}
```

## Importing libraries

Previously you could always use the Call.xxx methods to interact with any deployed contract, but the Call.xxx methods don't have full type and argument validation.
In latest version of TOMB, it is also possible to import any valid Phantasma ABI file.
Using this feature of ABIfiles adds more compile time safety and is also easier to use.

For example, if we have a CustomContract that was previously compiled by TOMB, we should have at least a .pvm and a .abi file for it.
That .abi file contains a list of public interface of the contract, and we can import that so that other contracts can call their methods.

```c#
...
import CustomContract; // by doing this, we can now call any public method of CustomContract
// the sintax is the same as other contract method calls, eg: CustomContract.doSomething(1234);
...
}
```

### ABI import paths
If you do a import CustomContract, the compiler will need to find a customcontract.abi file somewhere.
By default, it will look in the output folder that you specified, but you can also pass extra library paths:

tomb.exe libpath:c:\something\compiled_abis target.tomb

# Examples

## Simple Sum
Expand Down

0 comments on commit 1b6d26f

Please sign in to comment.