├── Library
├── tests
│ ├── Usings.cs
│ ├── AST
│ │ ├── EnumsTests.cs
│ │ ├── NodeTests.cs
│ │ ├── ScopeTests.cs
│ │ ├── ExpressionTests.cs
│ │ ├── StatementTests.cs
│ │ ├── DeclarationTests.cs
│ │ ├── MethodInterfaceTests.cs
│ │ ├── Statements
│ │ │ ├── IfStatementTests.cs
│ │ │ ├── BreakStatementTests.cs
│ │ │ ├── CaseStatementTests.cs
│ │ │ ├── EmitStatementTests.cs
│ │ │ ├── ForStatementTests.cs
│ │ │ ├── ThrowStatementTests.cs
│ │ │ ├── WhileStatementTests.cs
│ │ │ ├── AssingStatementTests.cs
│ │ │ ├── DoWhileStatementTests.cs
│ │ │ ├── ReturnStatementTests.cs
│ │ │ ├── SwitchStatementTests.cs
│ │ │ ├── AsmBlockStatementTests.cs
│ │ │ ├── ContinueStatementTests.cs
│ │ │ └── MethodCallStatementTests.cs
│ │ ├── Expressions
│ │ │ ├── VarExpressionTests.cs
│ │ │ ├── ArrayExpressionTests.cs
│ │ │ ├── CastExpressionTests.cs
│ │ │ ├── ConstExpressionTests.cs
│ │ │ ├── MacroExpressionTests.cs
│ │ │ ├── BinaryExpressionTests.cs
│ │ │ ├── LiteralExpressionTests.cs
│ │ │ ├── NegationExpressionTests.cs
│ │ │ ├── MethodCallExpressionTests.cs
│ │ │ ├── ArrayElementExpressionTests.cs
│ │ │ └── StructFieldExpressionTests.cs
│ │ └── Declaration
│ │ │ ├── SetDeclarationTests.cs
│ │ │ ├── MapDeclarationTests.cs
│ │ │ ├── ListDeclarationTests.cs
│ │ │ ├── MethodDeclarationTests.cs
│ │ │ ├── DecimalDeclarationTests.cs
│ │ │ ├── EventDeclarationTests.cs
│ │ │ ├── StructDeclarationTests.cs
│ │ │ ├── EnumDeclarationTests.cs
│ │ │ ├── VarDeclarationTests.cs
│ │ │ └── ConstDeclarationTest.cs
│ ├── CodeGen
│ │ ├── NFTTests.cs
│ │ ├── ModuleTests.cs
│ │ ├── ScriptTests.cs
│ │ ├── BuiltinsTests.cs
│ │ ├── ContractTests.cs
│ │ ├── RegisterTests.cs
│ │ └── CodeGeneratorTests.cs
│ ├── Contracts
│ │ ├── StructTests.cs
│ │ ├── ForTests.cs
│ │ ├── ConstantsTests.cs
│ │ ├── BooleanTests.cs
│ │ ├── SwitchTest.cs
│ │ ├── ReturnTests.cs
│ │ ├── PropertiesTests.cs
│ │ ├── AddressTests.cs
│ │ ├── EnumsTests.cs
│ │ ├── VariableTests.cs
│ │ ├── IfTests.cs
│ │ ├── ArrayTests.cs
│ │ ├── MethodTests.cs
│ │ └── DecimalTests.cs
│ ├── Lexers
│ │ ├── SolidityLexerTests.cs
│ │ └── TombLangLexerTests.cs
│ ├── Compilers
│ │ ├── SolidityCompilerTests.cs
│ │ └── TombLangCompilerTests.cs
│ └── TOMBLib.Tests.csproj
└── src
│ ├── AST
│ ├── Declarations
│ │ ├── SetDeclaration.cs
│ │ ├── ListDeclaration.cs
│ │ ├── DecimalDeclaration.cs
│ │ ├── MapDeclaration.cs
│ │ ├── VarDeclaration.cs
│ │ ├── ConstDeclaration.cs
│ │ ├── StructDeclaration.cs
│ │ └── EnumDeclaration.cs
│ ├── Declaration.cs
│ ├── Statements
│ │ ├── AsmBlockStatement.cs
│ │ ├── ThrowStatement.cs
│ │ ├── MethodCallStatement.cs
│ │ ├── BreakStatement.cs
│ │ ├── ContinueStatement.cs
│ │ ├── CaseStatement.cs
│ │ ├── DoWhileStatement.cs
│ │ ├── WhileStatement.cs
│ │ ├── EmitStatement.cs
│ │ ├── AssignStatement.cs
│ │ ├── IfStatement.cs
│ │ ├── ForStatement.cs
│ │ ├── SwitchStatement.cs
│ │ └── ReturnStatement.cs
│ ├── Node.cs
│ ├── Expressions
│ │ ├── VarExpression.cs
│ │ ├── ConstExpression.cs
│ │ ├── NegationExpression.cs
│ │ ├── ArrayExpression.cs
│ │ ├── StructFieldExpression.cs
│ │ ├── ArrayElementExpression.cs
│ │ ├── CastExpression.cs
│ │ ├── MacroExpression.cs
│ │ └── BinaryExpression.cs
│ ├── Statement.cs
│ └── Expression.cs
│ ├── Exceptions.cs
│ ├── CodeGen
│ ├── Register.cs
│ ├── CodeGenerator.cs
│ ├── NFT.cs
│ └── Script.cs
│ ├── TOMBLib.csproj
│ └── Extensions.cs
├── logo.png
├── Tests
├── AST
│ ├── EnumsTests.cs
│ ├── NodeTests.cs
│ ├── ScopeTests.cs
│ ├── ExpressionTests.cs
│ ├── StatementTests.cs
│ ├── DeclarationTests.cs
│ ├── MethodInterfaceTests.cs
│ ├── Statements
│ │ ├── ForStatementTests.cs
│ │ ├── IfStatementTests.cs
│ │ ├── BreakStatementTests.cs
│ │ ├── CaseStatementTests.cs
│ │ ├── EmitStatementTests.cs
│ │ ├── ThrowStatementTests.cs
│ │ ├── WhileStatementTests.cs
│ │ ├── AsmBlockStatementTests.cs
│ │ ├── AssingStatementTests.cs
│ │ ├── ContinueStatementTests.cs
│ │ ├── DoWhileStatementTests.cs
│ │ ├── ReturnStatementTests.cs
│ │ ├── SwitchStatementTests.cs
│ │ └── MethodCallStatementTests.cs
│ ├── Expressions
│ │ ├── VarExpressionTests.cs
│ │ ├── ArrayExpressionTests.cs
│ │ ├── BinaryExpressionTests.cs
│ │ ├── CastExpressionTests.cs
│ │ ├── ConstExpressionTests.cs
│ │ ├── MacroExpressionTests.cs
│ │ ├── LiteralExpressionTests.cs
│ │ ├── NegationExpressionTests.cs
│ │ ├── MethodCallExpressionTests.cs
│ │ ├── StructFieldExpressionTests.cs
│ │ └── ArrayElementExpressionTests.cs
│ └── Declaration
│ │ ├── MapDeclarationTests.cs
│ │ ├── SetDeclarationTests.cs
│ │ ├── ListDeclarationTests.cs
│ │ ├── MethodDeclarationTests.cs
│ │ ├── DecimalDeclarationTests.cs
│ │ ├── EventDeclarationTests.cs
│ │ ├── StructDeclarationTests.cs
│ │ ├── EnumDeclarationTests.cs
│ │ ├── VarDeclarationTests.cs
│ │ └── ConstDeclarationTest.cs
├── CodeGen
│ ├── NFTTests.cs
│ ├── ModuleTests.cs
│ ├── ScriptTests.cs
│ ├── BuiltinsTests.cs
│ ├── ContractTests.cs
│ ├── RegisterTests.cs
│ └── CodeGeneratorTests.cs
├── Contracts
│ ├── StructTests.cs
│ ├── ForTests.cs
│ ├── BooleanTests.cs
│ ├── ConstantsTests.cs
│ ├── SwitchTest.cs
│ ├── ReturnTests.cs
│ ├── PropertiesTests.cs
│ ├── AddressTests.cs
│ ├── EnumsTests.cs
│ ├── VariableTests.cs
│ ├── IfTests.cs
│ ├── ArrayTests.cs
│ ├── MethodTests.cs
│ └── DecimalTests.cs
├── Lexers
│ ├── SolidityLexerTests.cs
│ └── TombLangLexerTests.cs
├── Compilers
│ ├── SolidityCompilerTests.cs
│ └── TombLangCompilerTests.cs
└── Tests.csproj
├── .gitignore
├── Compiler
├── TombCompiler.csproj
├── Properties
│ └── PublishProfiles
│ │ └── FolderProfile.pubxml
└── builtins.tomb
├── Samples
├── example1.sol
├── example6.sol
├── example2.sol
├── example7.sol
├── example4.sol
├── example5.sol
├── example3.sol
├── basic_token.sol
└── example8.sol
├── .github
└── workflows
│ ├── comment-on-pr.yml
│ ├── dotnet-publish.yml
│ └── dotnet-core.yml
├── LICENSE
└── TombCompiler.sln
/Library/tests/Usings.cs:
--------------------------------------------------------------------------------
1 | global using NUnit.Framework;
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phantasma-io-archive/TOMB/HEAD/logo.png
--------------------------------------------------------------------------------
/Tests/AST/EnumsTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST;
2 |
3 | public class EnumsTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/NodeTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST;
2 |
3 | public class NodeTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/ScopeTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST;
2 |
3 | public class ScopeTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/CodeGen/NFTTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.CodeGen;
2 |
3 | public class NFTTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/ExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST;
2 |
3 | public class ExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/StatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST;
2 |
3 | public class StatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/CodeGen/ModuleTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.CodeGen;
2 |
3 | public class ModuleTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/CodeGen/ScriptTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.CodeGen;
2 |
3 | public class ScriptTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/EnumsTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST;
2 |
3 | public class EnumsTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/NodeTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST;
2 |
3 | public class NodeTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/ScopeTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST;
2 |
3 | public class ScopeTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/DeclarationTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST;
2 |
3 | public class DeclarationTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/CodeGen/BuiltinsTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.CodeGen;
2 |
3 | public class BuiltinsTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/CodeGen/ContractTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.CodeGen;
2 |
3 | public class ContractTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/CodeGen/RegisterTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.CodeGen;
2 |
3 | public class RegisterTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/Contracts/StructTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Contracts;
2 |
3 | public class StructTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/CodeGen/NFTTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.CodeGen;
2 |
3 | public class NFTTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/MethodInterfaceTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST;
2 |
3 | public class MethodInterfaceTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/ExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST;
2 |
3 | public class ExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/StatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST;
2 |
3 | public class StatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/CodeGen/ModuleTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.CodeGen;
2 |
3 | public class ModuleTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/CodeGen/ScriptTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.CodeGen;
2 |
3 | public class ScriptTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/CodeGen/CodeGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.CodeGen;
2 |
3 | public class CodeGeneratorTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/Lexers/SolidityLexerTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Lexers;
2 |
3 | public class SolidityLexerTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/Lexers/TombLangLexerTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Lexers;
2 |
3 | public class TombLangLexerTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/DeclarationTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST;
2 |
3 | public class DeclarationTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/CodeGen/BuiltinsTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.CodeGen;
2 |
3 | public class BuiltinsTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/CodeGen/ContractTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.CodeGen;
2 |
3 | public class ContractTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/CodeGen/RegisterTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.CodeGen;
2 |
3 | public class RegisterTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/Contracts/StructTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.Contracts;
2 |
3 | public class StructTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/MethodInterfaceTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST;
2 |
3 | public class MethodInterfaceTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/ForStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class ForStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/IfStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class IfStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/Compilers/SolidityCompilerTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Compilers;
2 |
3 | public class SolidityCompilerTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/Compilers/TombLangCompilerTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.Compilers;
2 |
3 | public class TombLangCompilerTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/Lexers/SolidityLexerTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.Lexers;
2 |
3 | public class SolidityLexerTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/Lexers/TombLangLexerTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.Lexers;
2 |
3 | public class TombLangLexerTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/VarExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class VarExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/BreakStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class BreakStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/CaseStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class CaseStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/EmitStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class EmitStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/ThrowStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class ThrowStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/WhileStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class WhileStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/ArrayExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class ArrayExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/BinaryExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class BinaryExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/CastExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class CastExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/ConstExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class ConstExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/MacroExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class MacroExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/AsmBlockStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class AsmBlockStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/AssingStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class AssingStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/ContinueStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class ContinueStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/DoWhileStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class DoWhileStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/ReturnStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class ReturnStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/SwitchStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class SwitchStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/IfStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class IfStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/Compilers/SolidityCompilerTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.Compilers;
2 |
3 | public class SolidityCompilerTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/Compilers/TombLangCompilerTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.Compilers;
2 |
3 | public class TombLangCompilerTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/LiteralExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class LiteralExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/NegationExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class NegationExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Statements/MethodCallStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Statements;
2 |
3 | public class MethodCallStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/VarExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class VarExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/BreakStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class BreakStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/CaseStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class CaseStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/EmitStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class EmitStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/ForStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class ForStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/ThrowStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class ThrowStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/WhileStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class WhileStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/MethodCallExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class MethodCallExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/StructFieldExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class StructFieldExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/ArrayExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class ArrayExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/CastExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class CastExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/ConstExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class ConstExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/MacroExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class MacroExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/AssingStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class AssingStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/DoWhileStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class DoWhileStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/ReturnStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class ReturnStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/SwitchStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class SwitchStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Tests/AST/Expressions/ArrayElementExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace Tests.AST.Expressions;
2 |
3 | public class ArrayElementExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/BinaryExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class BinaryExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/LiteralExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class LiteralExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/NegationExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class NegationExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/AsmBlockStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class AsmBlockStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/ContinueStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class ContinueStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Statements/MethodCallStatementTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Statements;
2 |
3 | public class MethodCallStatementTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/MethodCallExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class MethodCallExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/ArrayElementExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class ArrayElementExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Expressions/StructFieldExpressionTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.AST.Expressions;
2 |
3 | public class StructFieldExpressionTests
4 | {
5 |
6 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .vs/
3 | obj/
4 | bin/
5 | Publish/
6 | *.user
7 |
8 | Compiler/Properties/launchSettings.json
9 | .idea/
10 | coverage/
11 |
12 | Releases/
13 |
--------------------------------------------------------------------------------
/Library/tests/AST/Declaration/SetDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.Lexers;
2 |
3 | namespace TOMBLib.Tests.AST.Declaration;
4 |
5 | public class SetDeclarationTests
6 | {
7 | [SetUp]
8 | public void Setup()
9 | {
10 | TombLangLexer lexer = new TombLangLexer();
11 | }
12 | }
--------------------------------------------------------------------------------
/Tests/AST/Declaration/MapDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.Lexers;
3 |
4 | namespace Tests.AST.Declaration;
5 |
6 | public class MapDeclarationTests
7 | {
8 | [SetUp]
9 | public void Setup()
10 | {
11 | TombLangLexer lexer = new TombLangLexer();
12 | }
13 | }
--------------------------------------------------------------------------------
/Tests/AST/Declaration/SetDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.Lexers;
3 |
4 | namespace Tests.AST.Declaration;
5 |
6 | public class SetDeclarationTests
7 | {
8 | [SetUp]
9 | public void Setup()
10 | {
11 | TombLangLexer lexer = new TombLangLexer();
12 | }
13 | }
--------------------------------------------------------------------------------
/Tests/AST/Declaration/ListDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.Lexers;
3 |
4 | namespace Tests.AST.Declaration;
5 |
6 | public class ListDeclarationTests
7 | {
8 | [SetUp]
9 | public void Setup()
10 | {
11 | TombLangLexer lexer = new TombLangLexer();
12 | }
13 | }
--------------------------------------------------------------------------------
/Tests/AST/Declaration/MethodDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.Lexers;
3 |
4 | namespace Tests.AST.Declaration;
5 |
6 | public class MethodDeclarationTests
7 | {
8 | [SetUp]
9 | public void Setup()
10 | {
11 | TombLangLexer lexer = new TombLangLexer();
12 | }
13 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Declaration/MapDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.Lexers;
3 |
4 | namespace TOMBLib.Tests.AST.Declaration;
5 |
6 | public class MapDeclarationTests
7 | {
8 | [SetUp]
9 | public void Setup()
10 | {
11 | TombLangLexer lexer = new TombLangLexer();
12 | }
13 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Declaration/ListDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.Lexers;
3 |
4 | namespace TOMBLib.Tests.AST.Declaration;
5 |
6 | public class ListDeclarationTests
7 | {
8 | [SetUp]
9 | public void Setup()
10 | {
11 | TombLangLexer lexer = new TombLangLexer();
12 | }
13 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Declaration/MethodDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.Lexers;
3 |
4 | namespace TOMBLib.Tests.AST.Declaration;
5 |
6 | public class MethodDeclarationTests
7 | {
8 | [SetUp]
9 | public void Setup()
10 | {
11 | TombLangLexer lexer = new TombLangLexer();
12 | }
13 | }
--------------------------------------------------------------------------------
/Compiler/TombCompiler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 | Phantasma.Tomb
7 | disable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Library/src/AST/Declarations/SetDeclaration.cs:
--------------------------------------------------------------------------------
1 | namespace Phantasma.Tomb.AST.Declarations
2 | {
3 | public class SetDeclaration : VarDeclaration
4 | {
5 | public VarType ValueKind;
6 |
7 | public SetDeclaration(Scope parentScope, string name, VarType valKind) : base(parentScope, name, VarType.Find(VarKind.Storage_Set), VarStorage.Global)
8 | {
9 | this.ValueKind = valKind;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Library/src/AST/Declarations/ListDeclaration.cs:
--------------------------------------------------------------------------------
1 | namespace Phantasma.Tomb.AST.Declarations
2 | {
3 | public class ListDeclaration : VarDeclaration
4 | {
5 | public VarType ValueKind;
6 |
7 | public ListDeclaration(Scope parentScope, string name, VarType valKind) : base(parentScope, name, VarType.Find(VarKind.Storage_List), VarStorage.Global)
8 | {
9 | this.ValueKind = valKind;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Library/src/AST/Declarations/DecimalDeclaration.cs:
--------------------------------------------------------------------------------
1 | namespace Phantasma.Tomb.AST.Declarations
2 | {
3 | public class DecimalDeclaration : VarDeclaration
4 | {
5 | public readonly int Decimals;
6 |
7 | public DecimalDeclaration(Scope parentScope, string name, int decimals, VarStorage storage) : base(parentScope, name, VarType.Find(VarKind.Decimal, decimals), storage)
8 | {
9 | this.Decimals = decimals;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Samples/example1.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.4.10;
2 |
3 | import "Phantasma/Runtime.tomb";
4 | import "Phantasma/Random.tomb";
5 |
6 | //the very first example
7 | contract example1 {
8 | uint counter;
9 |
10 | function getCounter(uint n) public view returns (uint) {
11 | Runtime.log("Returning the current value of counter");
12 | return counter;
13 | }
14 |
15 | function getRandom() public view returns (uint) {
16 | Runtime.log("Generating a random number");
17 | return Random.generate();
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/Library/src/AST/Declarations/MapDeclaration.cs:
--------------------------------------------------------------------------------
1 | namespace Phantasma.Tomb.AST.Declarations
2 | {
3 | public class MapDeclaration: VarDeclaration
4 | {
5 | public VarType KeyKind;
6 | public VarType ValueKind;
7 |
8 | public MapDeclaration(Scope parentScope, string name, VarType keyKind, VarType valKind) : base(parentScope, name, VarType.Find(VarKind.Storage_Map), VarStorage.Global)
9 | {
10 | this.KeyKind = keyKind;
11 | this.ValueKind = valKind;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Compiler/Properties/PublishProfiles/FolderProfile.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Debug
8 | Any CPU
9 | C:\Code\TOMB\Publish\
10 | FileSystem
11 | net7.0
12 | false
13 |
14 |
--------------------------------------------------------------------------------
/Samples/example6.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >0.5.00;
2 |
3 | //the very sixth example
4 | contract Example6 {
5 |
6 | mapping (address => mapping (bytes32 => uint)) public stamps;
7 |
8 | function store(bytes32 hash) public {
9 | stamps[msg.sender][hash] = block.timestamp;
10 | }
11 |
12 | function hashIt(string memory data) public pure returns (bytes32) {
13 | return keccak256(abi.encodePacked(data));
14 | }
15 |
16 | function verify(address recipient, string memory data) public view returns (uint) {
17 | return stamps[recipient][keccak256(abi.encodePacked(data))];
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Library/src/Exceptions.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST;
2 | using System;
3 |
4 | namespace Phantasma.Tomb
5 | {
6 | public class CompilerException : Exception
7 | {
8 | private static string FetchCurrentLine()
9 | {
10 | return Compiler.Instance != null ? Compiler.Instance.CurrentLine.ToString() : "???";
11 | }
12 |
13 | public CompilerException(string msg) : base($"line {FetchCurrentLine()}: {msg}")
14 | {
15 |
16 | }
17 |
18 | public CompilerException(Node node, string msg) : base($"line {node.LineNumber}: {msg}")
19 | {
20 |
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Library/src/CodeGen/Register.cs:
--------------------------------------------------------------------------------
1 | namespace Phantasma.Tomb.CodeGen
2 | {
3 | public class Register
4 | {
5 | public readonly int Index;
6 | public readonly string Alias;
7 |
8 | public readonly static Register Temporary = new Register(0, null);
9 |
10 | public Register(int index, string alias = null)
11 | {
12 | Index = index;
13 | Alias = alias;
14 | }
15 |
16 | public override string ToString()
17 | {
18 | if (Alias != null)
19 | {
20 | return "$" + Alias;
21 |
22 | }
23 | return "r"+Index;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Library/src/AST/Declaration.cs:
--------------------------------------------------------------------------------
1 | namespace Phantasma.Tomb.AST
2 | {
3 | public abstract class Declaration: Node
4 | {
5 | public readonly string Name;
6 | public Scope ParentScope { get; internal set; }
7 |
8 | protected Declaration(Scope parentScope, string name)
9 | {
10 | Name = name;
11 | ParentScope = parentScope;
12 | ValidateName();
13 | }
14 |
15 | protected virtual void ValidateName()
16 | {
17 | if (!Lexer.Instance.IsValidIdentifier(Name))
18 | {
19 | throw new CompilerException("Invalid identifier: " + Name);
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Samples/example2.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >0.4.10;
2 |
3 | //the very second example
4 | contract Example2 {
5 |
6 | uint counter=0;
7 | mapping (uint => string) stringList; //maps an integer to a string (creates an array)
8 |
9 | function push(string memory info) public {
10 | stringList[counter] = info; //saves the input string (info) into the list using the index "counter"
11 | counter++; //increment the counter
12 | }
13 |
14 | function get(uint nr) public view returns (string memory) {
15 | return stringList[nr]; //returns the string that is mapped to the index nr
16 | }
17 | function getCounter() public view returns (uint) {
18 | return counter; //return the number of strings
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Tests/Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Samples/example7.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >0.4.10;
2 |
3 | //the very seventh example
4 | contract Example7 {
5 |
6 | address owner;
7 | mapping (address => uint) accounts;
8 |
9 | constructor() public {
10 | owner = msg.sender;
11 | }
12 |
13 | function mint(address recipient, uint value) public {
14 | if(msg.sender == owner) {
15 | accounts[recipient] += value;
16 | }
17 | }
18 |
19 | function transfer(address to, uint value) public{
20 | if(accounts[msg.sender] >= value) {
21 | accounts[msg.sender] -= value;
22 | accounts[to] += value;
23 | }
24 | }
25 |
26 | function balance(address addr) public view returns (uint) {
27 | return accounts[addr];
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Library/src/AST/Statements/AsmBlockStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 | using System;
3 |
4 | namespace Phantasma.Tomb.AST.Statements
5 | {
6 | public class AsmBlockStatement : Statement
7 | {
8 | public string[] lines;
9 |
10 | public AsmBlockStatement(string[] lines) : base()
11 | {
12 | this.lines = lines;
13 | }
14 |
15 | public override void Visit(Action callback)
16 | {
17 | callback(this);
18 | }
19 |
20 | public override bool IsNodeUsed(Node node)
21 | {
22 | return (node == this);
23 | }
24 |
25 | public override void GenerateCode(CodeGenerator output)
26 | {
27 | foreach (var line in lines)
28 | {
29 | output.AppendLine(this, line);
30 | }
31 | }
32 | }
33 |
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/Library/src/AST/Statements/ThrowStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 | using System;
3 |
4 | namespace Phantasma.Tomb.AST.Statements
5 | {
6 | public class ThrowStatement : Statement
7 | {
8 | public readonly Expression expr;
9 |
10 | public ThrowStatement(Expression expr) : base()
11 | {
12 | this.expr = expr;
13 | }
14 |
15 | public override void Visit(Action callback)
16 | {
17 | callback(this);
18 | }
19 |
20 | public override bool IsNodeUsed(Node node)
21 | {
22 | return (node == this);
23 | }
24 |
25 | public override void GenerateCode(CodeGenerator output)
26 | {
27 | var reg = expr.GenerateCode(output);
28 | output.AppendLine(this, $"THROW {reg}");
29 | Compiler.Instance.DeallocRegister(ref reg);
30 | }
31 | }
32 |
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/Library/src/TOMBLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 | Phantasma.TOMB
8 | Provides runtime compilation of TOMB smart contracts and tokens.
9 | logo.png
10 | 1.5.3
11 | True
12 | Phantasma.TOMB
13 | https://github.com/phantasma-io/TOMB
14 |
15 |
16 |
17 |
18 | True
19 | \
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Library/src/AST/Node.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Phantasma.Tomb.AST
4 | {
5 | public abstract class Node
6 | {
7 | public int LineNumber;
8 | public int Column;
9 | public string NodeID;
10 |
11 | public Node()
12 | {
13 | if (Compiler.Instance != null)
14 | {
15 | this.LineNumber = Compiler.Instance.CurrentLine;
16 | this.Column = Compiler.Instance.CurrentColumn;
17 | this.NodeID = this.GetType().Name.ToLower() + Compiler.Instance.AllocateLabel();
18 | }
19 | else
20 | {
21 | this.LineNumber = -1;
22 | this.Column = -1;
23 | this.NodeID = this.GetType().Name.ToLower();
24 | }
25 | }
26 |
27 | public abstract bool IsNodeUsed(Node node);
28 |
29 | public abstract void Visit(Action callback);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Library/src/AST/Declarations/VarDeclaration.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 |
3 | using System;
4 |
5 | namespace Phantasma.Tomb.AST.Declarations
6 | {
7 | public class VarDeclaration : Declaration
8 | {
9 | public VarType Type;
10 | public VarStorage Storage;
11 | public Register Register = null;
12 |
13 | public VarDeclaration(Scope parentScope, string name, VarType type, VarStorage storage) : base(parentScope, name)
14 | {
15 | this.Type = type;
16 | this.Storage = storage;
17 | }
18 |
19 | public override string ToString()
20 | {
21 | return $"var {Name}:{Type}";
22 | }
23 |
24 | public override void Visit(Action callback)
25 | {
26 | callback(this);
27 | }
28 |
29 | public override bool IsNodeUsed(Node node)
30 | {
31 | return node == this;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Library/src/AST/Statements/MethodCallStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Expressions;
2 | using Phantasma.Tomb.CodeGen;
3 | using System;
4 |
5 | namespace Phantasma.Tomb.AST.Statements
6 | {
7 | public class MethodCallStatement : Statement
8 | {
9 | public MethodCallExpression expression;
10 |
11 | public MethodCallStatement() : base()
12 | {
13 |
14 | }
15 |
16 | public override void Visit(Action callback)
17 | {
18 | callback(this);
19 | expression.Visit(callback);
20 | }
21 |
22 | public override bool IsNodeUsed(Node node)
23 | {
24 | return (node == this) || expression.IsNodeUsed(node);
25 | }
26 |
27 | public override void GenerateCode(CodeGenerator output)
28 | {
29 | var reg = expression.GenerateCode(output);
30 | Compiler.Instance.DeallocRegister(ref reg);
31 | }
32 | }
33 |
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/Library/tests/TOMBLib.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Library/src/AST/Declarations/ConstDeclaration.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 |
3 | using System;
4 |
5 | namespace Phantasma.Tomb.AST.Declarations
6 | {
7 | public class ConstDeclaration : Declaration
8 | {
9 | public VarType Type;
10 | public string Value;
11 |
12 | public ConstDeclaration(Scope parentScope, string name, VarType kind, string value) : base(parentScope, name)
13 | {
14 | this.Type = kind;
15 | this.Value = value;
16 | }
17 |
18 | public void GenerateCode(CodeGenerator output)
19 | {
20 | // DO NOTHING
21 | }
22 |
23 | public override string ToString()
24 | {
25 | return $"const {Name}:{Type}";
26 | }
27 |
28 | public override void Visit(Action callback)
29 | {
30 | callback(this);
31 | }
32 |
33 | public override bool IsNodeUsed(Node node)
34 | {
35 | return node == this;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/.github/workflows/comment-on-pr.yml:
--------------------------------------------------------------------------------
1 | name: Comment on the pull request
2 |
3 | # read-write repo token
4 | # access to secrets
5 | on:
6 | workflow_run:
7 | workflows: [".NET Core"]
8 | types:
9 | - completed
10 | permissions:
11 | pull-requests: write
12 | actions: write
13 | issues: write
14 | contents: write
15 |
16 | env:
17 | GITHUB_TOKEN: ${{ secrets.PR_KEY }}
18 |
19 | jobs:
20 | build:
21 | name: Comment on PR
22 | runs-on: ubuntu-latest
23 | if: >
24 | github.event.workflow_run.event == 'pull_request' &&
25 | github.event.workflow_run.conclusion == 'success'
26 | permissions: write-all
27 | steps:
28 | - uses: actions/checkout@v3
29 |
30 | - uses: actions/download-artifact@v3
31 | with:
32 | name: my-artifact
33 |
34 | - name: Add Coverage PR Comment
35 | uses: marocchino/sticky-pull-request-comment@v2
36 | with:
37 | recreate: true
38 | path: code-coverage-results.md
39 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Sérgio Flores
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Library/src/AST/Declarations/StructDeclaration.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace Phantasma.Tomb.AST.Declarations
7 | {
8 | public struct StructField
9 | {
10 | public readonly string name;
11 | public readonly VarType type;
12 |
13 | public StructField(string name, VarType type)
14 | {
15 | this.name = name;
16 | this.type = type;
17 | }
18 |
19 | public StructField(string name, VarKind kind) : this(name, VarType.Find(kind))
20 | {
21 | }
22 | }
23 |
24 | public class StructDeclaration: Declaration
25 | {
26 | public StructField[] fields;
27 |
28 | public StructDeclaration(string name, IEnumerable fields) : base(null, name)
29 | {
30 | this.fields = fields.ToArray();
31 | }
32 |
33 | public override bool IsNodeUsed(Node node)
34 | {
35 | return (node == this);
36 | }
37 |
38 | public override void Visit(Action callback)
39 | {
40 | callback(this);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Samples/example4.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >0.4.10;
2 |
3 | //the very fourth example
4 | contract Example4 {
5 |
6 | event Message(
7 | string msg
8 | );
9 |
10 | struct Account {
11 | string addr;
12 | uint amount; //default is 256bits
13 | }
14 |
15 | uint counter=1;
16 | mapping (uint => Account) accounts;
17 | address public owner;
18 |
19 | constructor() public {
20 | owner = msg.sender;
21 | }
22 | function create(string memory addr) public {
23 | accounts[counter++] = Account(addr, 42);
24 | owner = msg.sender;
25 | }
26 |
27 | function get(uint nr) public view returns (string memory) {
28 | return accounts[nr].addr;
29 | }
30 | function getAmount(uint nr) public view returns (uint) {
31 | return accounts[nr].amount;
32 | }
33 |
34 | function set(uint nr, string memory addr) public returns (bool) {
35 | if(owner == msg.sender) {
36 | accounts[counter++] = Account(addr, nr);
37 | emit Message("all set!"); //raises the event "Message"
38 | return true;
39 | } else {
40 | return false;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Tests/Contracts/ForTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Utils;
6 | using Phantasma.Tomb.Compilers;
7 |
8 | namespace Tests.Contracts;
9 |
10 | public class ForTests
11 | {
12 | [Test]
13 | public void ForLoop()
14 | {
15 | var sourceCode =
16 | @"
17 | contract test {
18 | public countStuff():number {
19 | local x:number = 0;
20 | for (local i=0; i<9; i+=1)
21 | {
22 | x+=2;
23 | }
24 | return x;
25 | }
26 | }";
27 |
28 | var parser = new TombLangCompiler();
29 | var contract = parser.Process(sourceCode).First();
30 |
31 | var storage = new Dictionary(new ByteArrayComparer());
32 |
33 | var countStuff = contract.abi.FindMethod("countStuff");
34 | Assert.IsNotNull(countStuff);
35 |
36 | var vm = new TestVM(contract, storage, countStuff);
37 | var result = vm.Execute();
38 | Assert.IsTrue(result == ExecutionState.Halt);
39 |
40 | Assert.IsTrue(vm.Stack.Count == 1);
41 | var val = vm.Stack.Pop().AsNumber();
42 | Assert.IsTrue(val == 18);
43 | }
44 | }
--------------------------------------------------------------------------------
/Library/src/AST/Statements/BreakStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 | using System;
3 |
4 | namespace Phantasma.Tomb.AST.Statements
5 | {
6 | public class BreakStatement : Statement
7 | {
8 | public readonly Scope scope;
9 |
10 | public BreakStatement(Scope scope) : base()
11 | {
12 | this.scope = scope;
13 | }
14 |
15 | public override bool IsNodeUsed(Node node)
16 | {
17 | return (node == this);
18 | }
19 |
20 | public override void Visit(Action callback)
21 | {
22 | callback(this);
23 | }
24 |
25 | public override void GenerateCode(CodeGenerator output)
26 | {
27 | if (Compiler.Instance.CurrentLoop == null)
28 | {
29 | if (this.scope.Method != null && this.scope.Method.@interface.Kind == MethodKind.Trigger)
30 | {
31 | throw new CompilerException("trigger break not implemented");
32 | }
33 |
34 | throw new CompilerException("not inside a loop");
35 | }
36 |
37 | output.AppendLine(this, $"JMP @loop_end_{ Compiler.Instance.CurrentLoop.NodeID}");
38 | }
39 | }
40 |
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/Samples/example5.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >0.4.10;
2 |
3 | //the very fifth example
4 | contract Example5 {
5 |
6 | event Message(
7 | string msg
8 | );
9 |
10 | mapping (address => uint) accounts; //maps an address to an integer
11 |
12 | function getContractBalance() public view returns (uint256){
13 | return address(this).balance;
14 | }
15 |
16 | function deposit() public payable { //payable means that you can send ether to the contract (depositing in the accounts array mantained by the smart contract)
17 | accounts[msg.sender] += msg.value;
18 | emit Message("deposit!");
19 | }
20 | function balance() public view returns (uint) { //return the balance of your account
21 | return accounts[msg.sender];
22 | }
23 | function withdraw(uint amount) public returns (bool){ //withdraw funds from your account
24 | if(accounts[msg.sender] >= amount) {
25 | accounts[msg.sender]-= amount;
26 | msg.sender.transfer(amount); //transfer the amount from the smart contract to the sender of the msg
27 | emit Message("withdraw!");
28 | return true;
29 | }
30 | emit Message("no withdraw!");
31 | return false;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Tests/AST/Declaration/DecimalDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.AST;
3 | using Phantasma.Tomb.AST.Declarations;
4 | using Phantasma.Tomb.CodeGen;
5 | using Phantasma.Tomb.Lexers;
6 |
7 | namespace Tests.AST.Declaration;
8 |
9 | public class DecimalDeclarationTests
10 | {
11 | [SetUp]
12 | public void Setup()
13 | {
14 | TombLangLexer lexer = new TombLangLexer();
15 | }
16 |
17 | [Test]
18 | public void DecimalDeclaration_Constructor_SetsProperties()
19 | {
20 | // Arrange
21 | var module = new Contract("myself", ModuleKind.Contract);
22 | var parentScope = new Scope(module);
23 | var name = "myDecimal";
24 | var type = VarType.Find(VarKind.Decimal, 2);
25 | var storage = VarStorage.Local;
26 | var value = "3.12";
27 | var decimals = 2;
28 |
29 | // Act
30 | var constDeclaration = new DecimalDeclaration(parentScope, name, decimals, storage);
31 |
32 | // Assert
33 | Assert.AreEqual(parentScope, constDeclaration.ParentScope);
34 | Assert.AreEqual(name, constDeclaration.Name);
35 | Assert.AreEqual(type, constDeclaration.Type);
36 | Assert.AreEqual(decimals, constDeclaration.Decimals);
37 | }
38 | }
--------------------------------------------------------------------------------
/Library/src/AST/Statements/ContinueStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 | using System;
3 |
4 | namespace Phantasma.Tomb.AST.Statements
5 | {
6 | public class ContinueStatement : Statement
7 | {
8 | public readonly Scope scope;
9 |
10 | public ContinueStatement(Scope scope) : base()
11 | {
12 | this.scope = scope;
13 | }
14 |
15 | public override bool IsNodeUsed(Node node)
16 | {
17 | return (node == this);
18 | }
19 |
20 | public override void Visit(Action callback)
21 | {
22 | callback(this);
23 | }
24 |
25 | public override void GenerateCode(CodeGenerator output)
26 | {
27 | if (Compiler.Instance.CurrentLoop == null)
28 | {
29 | if (this.scope.Method != null && this.scope.Method.@interface.Kind == MethodKind.Trigger)
30 | {
31 | throw new CompilerException("trigger continuenot implemented");
32 | }
33 |
34 | throw new CompilerException("not inside a loop");
35 | }
36 |
37 | output.AppendLine(this, $"JMP @loop_start_{ Compiler.Instance.CurrentLoop.NodeID}");
38 | }
39 | }
40 |
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/Library/tests/AST/Declaration/DecimalDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.AST;
3 | using Phantasma.Tomb.AST.Declarations;
4 | using Phantasma.Tomb.CodeGen;
5 | using Phantasma.Tomb.Lexers;
6 |
7 | namespace TOMBLib.Tests.AST.Declaration;
8 |
9 | public class DecimalDeclarationTests
10 | {
11 | [SetUp]
12 | public void Setup()
13 | {
14 | TombLangLexer lexer = new TombLangLexer();
15 | }
16 |
17 | [Test]
18 | public void DecimalDeclaration_Constructor_SetsProperties()
19 | {
20 | // Arrange
21 | var module = new Contract("myself", ModuleKind.Contract);
22 | var parentScope = new Scope(module);
23 | var name = "myDecimal";
24 | var type = VarType.Find(VarKind.Decimal, 2);
25 | var storage = VarStorage.Local;
26 | var value = "3.12";
27 | var decimals = 2;
28 |
29 | // Act
30 | var constDeclaration = new DecimalDeclaration(parentScope, name, decimals, storage);
31 |
32 | // Assert
33 | Assert.AreEqual(parentScope, constDeclaration.ParentScope);
34 | Assert.AreEqual(name, constDeclaration.Name);
35 | Assert.AreEqual(type, constDeclaration.Type);
36 | Assert.AreEqual(decimals, constDeclaration.Decimals);
37 | }
38 | }
--------------------------------------------------------------------------------
/Library/tests/Contracts/ForTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Domain.Execution.Enums;
6 | using Phantasma.Core.Utils;
7 | using Phantasma.Tomb.Compilers;
8 |
9 | namespace TOMBLib.Tests.Contracts;
10 |
11 | public class ForTests
12 | {
13 | [Test]
14 | public void ForLoop()
15 | {
16 | var sourceCode =
17 | @"
18 | contract test {
19 | public countStuff():number {
20 | local x:number = 0;
21 | for (local i=0; i<9; i+=1)
22 | {
23 | x+=2;
24 | }
25 | return x;
26 | }
27 | }";
28 |
29 | var parser = new TombLangCompiler();
30 | var contract = parser.Process(sourceCode).First();
31 |
32 | var storage = new Dictionary(new ByteArrayComparer());
33 |
34 | var countStuff = contract.abi.FindMethod("countStuff");
35 | Assert.IsNotNull(countStuff);
36 |
37 | var vm = new TestVM(contract, storage, countStuff);
38 | var result = vm.Execute();
39 | Assert.IsTrue(result == ExecutionState.Halt);
40 |
41 | Assert.IsTrue(vm.Stack.Count == 1);
42 | var val = vm.Stack.Pop().AsNumber();
43 | Assert.IsTrue(val == 18);
44 | }
45 | }
--------------------------------------------------------------------------------
/Samples/example3.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >0.4.10;
2 |
3 | //the very third example
4 | contract Example3 {
5 | struct Account {
6 | string addr;
7 | uint amount; //default is 256bits
8 | } //creates a structure
9 |
10 | uint counter=1;
11 | mapping (uint => Account) accounts;
12 | address public owner;
13 |
14 | constructor() public {
15 | owner = msg.sender;
16 | }
17 |
18 | function create(string memory addr) public { //creates the first object in the array and set your address as the owner
19 | accounts[counter++] = Account(addr, 42);
20 | owner = msg.sender;
21 | }
22 |
23 | function get(uint nr) public view returns (string memory) { //returns the address of the position "nr"
24 | return accounts[nr].addr;
25 | }
26 |
27 | function getAmount(uint nr) public view returns (uint) { //returns the amount saved for the position "nr"
28 | return accounts[nr].amount;
29 | }
30 |
31 | function set(uint nr, string memory addr) public returns (bool) { //sets an amount for an address (only possible if the sender of the msg is the owner)
32 | if(owner == msg.sender) {
33 | accounts[counter++] = Account(addr, nr);
34 | return true;
35 | } else {
36 | return false;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Library/src/AST/Declarations/EnumDeclaration.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace Phantasma.Tomb.AST.Declarations
6 | {
7 | public struct EnumEntry
8 | {
9 | public readonly string name;
10 | public readonly uint value;
11 |
12 | public EnumEntry(string name, uint value)
13 | {
14 | this.name = name;
15 | this.value = value;
16 | }
17 | }
18 |
19 | public class EnumDeclaration : Declaration
20 | {
21 | public Dictionary entryNames;
22 |
23 | public EnumDeclaration(string name, IEnumerable entries) : base(null, name)
24 | {
25 | entryNames = new Dictionary();
26 |
27 | foreach (var entry in entries)
28 | {
29 | if (entryNames.ContainsKey(entry.name))
30 | {
31 | throw new CompilerException($"Duplicated entry {entry.value} in enum {name}");
32 | }
33 |
34 | entryNames[entry.name] = entry.value;
35 | }
36 | }
37 |
38 | public override bool IsNodeUsed(Node node)
39 | {
40 | return (node == this);
41 | }
42 |
43 | public override void Visit(Action callback)
44 | {
45 | callback(this);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Library/src/AST/Expressions/VarExpression.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Declarations;
2 | using Phantasma.Tomb.CodeGen;
3 |
4 | using System;
5 |
6 | namespace Phantasma.Tomb.AST.Expressions
7 | {
8 | public class VarExpression : Expression
9 | {
10 | public VarDeclaration decl;
11 |
12 | public VarExpression(Scope parentScope, VarDeclaration declaration) : base(parentScope)
13 | {
14 | this.decl = declaration;
15 | }
16 |
17 | public override string ToString()
18 | {
19 | return decl.Name;
20 | }
21 |
22 | public override Register GenerateCode(CodeGenerator output)
23 | {
24 | if (decl.Register == null)
25 | {
26 | throw new CompilerException(this, $"var not initialized:" + decl.Name);
27 | }
28 |
29 | var reg = Compiler.Instance.AllocRegister(output, this);
30 | output.AppendLine(this, $"COPY {decl.Register} {reg}");
31 | return reg;
32 | }
33 |
34 | public override void Visit(Action callback)
35 | {
36 | callback(this);
37 | decl.Visit(callback);
38 | }
39 |
40 | public override bool IsNodeUsed(Node node)
41 | {
42 | return (node == this) || node == decl;
43 | }
44 |
45 | public override VarType ResultType => decl.Type;
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/Tests/Contracts/BooleanTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Utils;
7 | using Phantasma.Tomb.Compilers;
8 |
9 | namespace Tests.Contracts;
10 |
11 | public class BooleanTests
12 | {
13 | [Test]
14 | public void Bools()
15 | {
16 | string[] sourceCode = new string[]
17 | {
18 | "token TEST {",
19 | "global _contractPaused:bool;",
20 | "property name: string = \"Ghost\"; ",
21 | " constructor(owner:address) {",
22 | " _contractPaused= false;",
23 | "}}"
24 | };
25 |
26 | var parser = new TombLangCompiler();
27 | var contract = parser.Process(sourceCode).First();
28 |
29 | var storage = new Dictionary(new ByteArrayComparer());
30 |
31 | TestVM vm;
32 |
33 | var constructor = contract.abi.FindMethod(SmartContract.ConstructorName);
34 | Assert.IsNotNull(constructor);
35 |
36 | var keys = PhantasmaKeys.Generate();
37 |
38 | vm = new TestVM(contract, storage, constructor);
39 | vm.Stack.Push(VMObject.FromObject(keys.Address));
40 | var result = vm.Execute();
41 | Assert.IsTrue(result == ExecutionState.Halt);
42 |
43 | Assert.IsTrue(storage.Count == 1);
44 | }
45 |
46 | }
--------------------------------------------------------------------------------
/Tests/AST/Declaration/EventDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.AST;
3 | using Phantasma.Tomb.AST.Declarations;
4 | using Phantasma.Tomb.Lexers;
5 |
6 | namespace Tests.AST.Declaration;
7 |
8 | public class EventDeclarationTests
9 | {
10 | private Scope _scope;
11 | private VarType _returnType;
12 | private byte[] _descriptionScript;
13 |
14 | [SetUp]
15 | public void Setup()
16 | {
17 | TombLangLexer lexer = new TombLangLexer();
18 | _scope = null;
19 | _returnType = VarType.Find(VarKind.String);
20 | _descriptionScript = EventDeclaration.GenerateScriptFromString(_returnType, "\"{address}: {data}\"");
21 | }
22 |
23 | /*[Test]
24 | public void TestEventDeclarationConstructor()
25 | {
26 | var eventDeclaration = new EventDeclaration(_scope, "TestEvent", 1, _returnType, _descriptionScript);
27 |
28 | Assert.AreEqual(_scope, eventDeclaration.scope);
29 | Assert.AreEqual(1, eventDeclaration.value);
30 | Assert.AreEqual(_returnType, eventDeclaration.returnType);
31 | Assert.AreEqual(_descriptionScript, eventDeclaration.descriptionScript);
32 | }
33 |
34 | [Test]
35 | public void TestValidate()
36 | {
37 | var eventDeclaration = new EventDeclaration(_scope, "TestEvent", 1, _returnType, _descriptionScript);
38 | Assert.DoesNotThrow(() => eventDeclaration.Validate());
39 | }*/
40 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Declaration/EventDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.AST;
3 | using Phantasma.Tomb.AST.Declarations;
4 | using Phantasma.Tomb.Lexers;
5 |
6 | namespace TOMBLib.Tests.AST.Declaration;
7 |
8 | public class EventDeclarationTests
9 | {
10 | private Scope _scope;
11 | private VarType _returnType;
12 | private byte[] _descriptionScript;
13 |
14 | [SetUp]
15 | public void Setup()
16 | {
17 | TombLangLexer lexer = new TombLangLexer();
18 | _scope = null;
19 | _returnType = VarType.Find(VarKind.String);
20 | _descriptionScript = EventDeclaration.GenerateScriptFromString(_returnType, "\"{address}: {data}\"");
21 | }
22 |
23 | /*[Test]
24 | public void TestEventDeclarationConstructor()
25 | {
26 | var eventDeclaration = new EventDeclaration(_scope, "TestEvent", 1, _returnType, _descriptionScript);
27 |
28 | Assert.AreEqual(_scope, eventDeclaration.scope);
29 | Assert.AreEqual(1, eventDeclaration.value);
30 | Assert.AreEqual(_returnType, eventDeclaration.returnType);
31 | Assert.AreEqual(_descriptionScript, eventDeclaration.descriptionScript);
32 | }
33 |
34 | [Test]
35 | public void TestValidate()
36 | {
37 | var eventDeclaration = new EventDeclaration(_scope, "TestEvent", 1, _returnType, _descriptionScript);
38 | Assert.DoesNotThrow(() => eventDeclaration.Validate());
39 | }*/
40 | }
--------------------------------------------------------------------------------
/Tests/Contracts/ConstantsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Utils;
6 | using Phantasma.Tomb.Compilers;
7 |
8 | namespace Tests.Contracts;
9 |
10 | public class ConstantsTests
11 | {
12 | [Test]
13 | public void Constants()
14 | {
15 | var VAL_A = 30;
16 | var VAL_B = 4;
17 |
18 | string[] sourceCode = new string[]
19 | {
20 | $"const VAL_A : number = {VAL_A};",
21 | "contract test{",
22 | $"const VAL_B : number = {VAL_B};",
23 | "public getValue() : number {",
24 | "return VAL_A + VAL_B;}",
25 | "}"
26 | };
27 |
28 | var expectedVal = VAL_A + VAL_B;
29 |
30 | var parser = new TombLangCompiler();
31 | var contract = parser.Process(sourceCode).First();
32 |
33 | var storage = new Dictionary(new ByteArrayComparer());
34 |
35 | TestVM vm;
36 |
37 | var getValue = contract.abi.FindMethod("getValue");
38 | Assert.IsNotNull(getValue);
39 |
40 | vm = new TestVM(contract, storage, getValue);
41 | var result = vm.Execute();
42 | Assert.IsTrue(result == ExecutionState.Halt);
43 |
44 | Assert.IsTrue(vm.Stack.Count == 1);
45 |
46 | var obj = vm.Stack.Pop();
47 | var newVal = obj.AsNumber();
48 |
49 | Assert.IsTrue(newVal == expectedVal);
50 | }
51 | }
--------------------------------------------------------------------------------
/Library/src/AST/Statements/CaseStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Expressions;
2 | using Phantasma.Tomb.CodeGen;
3 | using System;
4 |
5 | namespace Phantasma.Tomb.AST.Statements
6 | {
7 | public class CaseStatement: Statement
8 | {
9 | public LiteralExpression value;
10 | public StatementBlock body;
11 |
12 | internal Register variable;
13 | internal string endLabel;
14 |
15 | public CaseStatement(LiteralExpression value, StatementBlock body) : base()
16 | {
17 | this.value = value;
18 | this.body = body;
19 | }
20 |
21 | public override void GenerateCode(CodeGenerator output)
22 | {
23 | var reg = value.GenerateCode(output);
24 |
25 | output.AppendLine(this, $"EQUAL {variable} {reg} {reg}");
26 |
27 | output.AppendLine(this, $"JMPNOT {reg} @skip_{this.NodeID}");
28 | body.GenerateCode(output);
29 | output.AppendLine(this, $"JMP {endLabel}");
30 | output.AppendLine(this, $"@skip_{this.NodeID}: NOP");
31 |
32 | Compiler.Instance.DeallocRegister(ref reg);
33 | }
34 |
35 | public override bool IsNodeUsed(Node node)
36 | {
37 | return value.IsNodeUsed(node) || body.IsNodeUsed(node);
38 | }
39 |
40 | public override void Visit(Action callback)
41 | {
42 | value.Visit(callback);
43 | body.Visit(callback);
44 | }
45 | }
46 |
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/Library/tests/Contracts/ConstantsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Domain.Execution.Enums;
6 | using Phantasma.Core.Utils;
7 | using Phantasma.Tomb.Compilers;
8 |
9 | namespace TOMBLib.Tests.Contracts;
10 |
11 | public class ConstantsTests
12 | {
13 | [Test]
14 | public void Constants()
15 | {
16 | var VAL_A = 30;
17 | var VAL_B = 4;
18 |
19 | string[] sourceCode = new string[]
20 | {
21 | $"const VAL_A : number = {VAL_A};",
22 | "contract test{",
23 | $"const VAL_B : number = {VAL_B};",
24 | "public getValue() : number {",
25 | "return VAL_A + VAL_B;}",
26 | "}"
27 | };
28 |
29 | var expectedVal = VAL_A + VAL_B;
30 |
31 | var parser = new TombLangCompiler();
32 | var contract = parser.Process(sourceCode).First();
33 |
34 | var storage = new Dictionary(new ByteArrayComparer());
35 |
36 | TestVM vm;
37 |
38 | var getValue = contract.abi.FindMethod("getValue");
39 | Assert.IsNotNull(getValue);
40 |
41 | vm = new TestVM(contract, storage, getValue);
42 | var result = vm.Execute();
43 | Assert.IsTrue(result == ExecutionState.Halt);
44 |
45 | Assert.IsTrue(vm.Stack.Count == 1);
46 |
47 | var obj = vm.Stack.Pop();
48 | var newVal = obj.AsNumber();
49 |
50 | Assert.IsTrue(newVal == expectedVal);
51 | }
52 | }
--------------------------------------------------------------------------------
/Library/tests/Contracts/BooleanTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Domain.Contract;
7 | using Phantasma.Core.Domain.Execution.Enums;
8 | using Phantasma.Core.Domain.VM;
9 | using Phantasma.Core.Utils;
10 | using Phantasma.Tomb.Compilers;
11 |
12 | namespace TOMBLib.Tests.Contracts;
13 |
14 | public class BooleanTests
15 | {
16 | [Test]
17 | public void Bools()
18 | {
19 | string[] sourceCode = new string[]
20 | {
21 | "token TEST {",
22 | "global _contractPaused:bool;",
23 | "property name: string = \"Ghost\"; ",
24 | " constructor(owner:address) {",
25 | " _contractPaused= false;",
26 | "}}"
27 | };
28 |
29 | var parser = new TombLangCompiler();
30 | var contract = parser.Process(sourceCode).First();
31 |
32 | var storage = new Dictionary(new ByteArrayComparer());
33 |
34 | TestVM vm;
35 |
36 | var constructor = contract.abi.FindMethod(SmartContract.ConstructorName);
37 | Assert.IsNotNull(constructor);
38 |
39 | var keys = PhantasmaKeys.Generate();
40 |
41 | vm = new TestVM(contract, storage, constructor);
42 | vm.Stack.Push(VMObject.FromObject(keys.Address));
43 | var result = vm.Execute();
44 | Assert.IsTrue(result == ExecutionState.Halt);
45 |
46 | Assert.IsTrue(storage.Count == 1);
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/Library/src/AST/Statement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace Phantasma.Tomb.AST
6 | {
7 | public abstract class Statement: Node
8 | {
9 | public abstract void GenerateCode(CodeGenerator output);
10 |
11 | }
12 |
13 | public class StatementBlock : Node
14 | {
15 | public readonly List Commands = new List();
16 |
17 | public Scope ParentScope { get; }
18 |
19 | public StatementBlock(Scope scope) : base()
20 | {
21 | this.ParentScope = scope;
22 | }
23 |
24 | public void GenerateCode(CodeGenerator output)
25 | {
26 | foreach (var cmd in Commands)
27 | {
28 | cmd.GenerateCode(output);
29 | }
30 | }
31 |
32 | public override void Visit(Action callback)
33 | {
34 | callback(this);
35 | foreach (var cmd in Commands)
36 | {
37 | cmd.Visit(callback);
38 | }
39 | }
40 |
41 | public override bool IsNodeUsed(Node node)
42 | {
43 | if (node == this)
44 | {
45 | return true;
46 | }
47 |
48 | foreach (var cmd in Commands)
49 | {
50 | if (cmd.IsNodeUsed(node))
51 | {
52 | return true;
53 | }
54 | }
55 |
56 | return false;
57 | }
58 | }
59 |
60 | public abstract class LoopStatement: Statement
61 | {
62 | }
63 |
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/Library/src/AST/Expressions/ConstExpression.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Declarations;
2 | using Phantasma.Tomb.CodeGen;
3 |
4 | using System;
5 |
6 | namespace Phantasma.Tomb.AST.Expressions
7 | {
8 | public class ConstExpression : Expression
9 | {
10 | public ConstDeclaration decl;
11 |
12 | public ConstExpression(Scope parentScope, ConstDeclaration declaration) : base(parentScope)
13 | {
14 | this.decl = declaration;
15 | }
16 |
17 | public override string ToString()
18 | {
19 | return decl.Name;
20 | //return decl.ToString();
21 | }
22 |
23 | public override T AsLiteral()
24 | {
25 | if (decl.Type.Kind == VarKind.String && typeof(T) == typeof(string))
26 | {
27 | return (T)(object)decl.Value;
28 | }
29 |
30 | return base.AsLiteral();
31 | }
32 |
33 | public override Register GenerateCode(CodeGenerator output)
34 | {
35 | var reg = Compiler.Instance.AllocRegister(output, this, decl.Name);
36 | output.AppendLine(this, $"LOAD {reg} {decl.Value}");
37 | this.CallNecessaryConstructors(output, decl.Type, reg);
38 | return reg;
39 | }
40 |
41 | public override void Visit(Action callback)
42 | {
43 | callback(this);
44 | decl.Visit(callback);
45 | }
46 |
47 | public override bool IsNodeUsed(Node node)
48 | {
49 | return (node == this) || node == decl;
50 | }
51 |
52 | public override VarType ResultType => decl.Type;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/Library/src/AST/Expressions/NegationExpression.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 |
3 | using System;
4 |
5 | namespace Phantasma.Tomb.AST.Expressions
6 | {
7 | public class NegationExpression : Expression
8 | {
9 | public Expression expr;
10 | public override VarType ResultType => expr.ResultType;
11 |
12 | public NegationExpression(Scope parentScope, Expression expr) : base(parentScope)
13 | {
14 | this.expr = expr;
15 | }
16 |
17 | public override Register GenerateCode(CodeGenerator output)
18 | {
19 | var type = expr.ResultType;
20 |
21 | var reg = expr.GenerateCode(output);
22 |
23 | switch (type.Kind)
24 | {
25 | case VarKind.Bool:
26 | output.AppendLine(this, $"NOT {reg} {reg}");
27 | break;
28 |
29 | case VarKind.Number:
30 | output.AppendLine(this, $"NEGATE {reg} {reg}");
31 | break;
32 |
33 | default:
34 | throw new CompilerException("Cannot negate expression of type: " + type);
35 | }
36 |
37 | return reg;
38 | }
39 |
40 |
41 | public override void Visit(Action callback)
42 | {
43 | callback(this);
44 | expr.Visit(callback);
45 | }
46 |
47 | public override bool IsNodeUsed(Node node)
48 | {
49 | return (node == this) || expr.IsNodeUsed(node);
50 | }
51 |
52 | public override string ToString()
53 | {
54 | return "!" + expr.ToString();
55 | }
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet-publish.yml:
--------------------------------------------------------------------------------
1 | name: .NET Nuget Publish
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches: [ "master" ]
7 | pull_request:
8 | branches: [ "master" ]
9 |
10 | permissions:
11 | pull-requests: write
12 | actions: write
13 | issues: write
14 | contents: write
15 |
16 | env:
17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18 |
19 | jobs:
20 | build:
21 | name: Build and Publish Nuget
22 | runs-on: ubuntu-latest
23 | permissions: write-all
24 |
25 | steps:
26 | - uses: actions/checkout@v3
27 | with:
28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29 |
30 | - name: Setup .NET
31 | uses: actions/setup-dotnet@v2
32 | with:
33 | dotnet-version: 6.0.x
34 |
35 | - name: Install dependencies
36 | run: |
37 | dotnet restore
38 |
39 | - name: Build
40 | run: dotnet build --configuration Release --no-restore
41 |
42 | - name: Pack Nuget
43 | run: dotnet pack --configuration Release --no-restore
44 |
45 | - name: Publish Nuget
46 | run: |
47 | dotnet nuget push ./Library/src/bin/Release/TOMBLib.*.nupkg --skip-duplicate -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json
48 |
49 | - name: Publish Nuget Github
50 | run: |
51 | dotnet nuget add ./Library/src/bin/Release/TOMBLib.*.nupkg --skip-duplicate --username USERNAME --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/phantasma-io/index.json"
52 | dotnet nuget push ./Library/src/bin/Release/TOMBLib.*.nupkg --skip-duplicate --api-key ${{secrets.PR_KEY}} --source "github"
--------------------------------------------------------------------------------
/Library/src/AST/Expression.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Expressions;
2 | using Phantasma.Tomb.CodeGen;
3 |
4 | namespace Phantasma.Tomb.AST
5 | {
6 | public abstract class Expression : Node
7 | {
8 | public abstract VarType ResultType { get; }
9 | public Scope ParentScope { get; }
10 |
11 | public Expression(Scope parentScope) : base()
12 | {
13 | this.ParentScope = parentScope;
14 | }
15 |
16 | public virtual T AsLiteral()
17 | {
18 | throw new CompilerException(this, $"{this.GetType()} can't be converted to {typeof(T).Name} literal");
19 | }
20 |
21 | public abstract Register GenerateCode(CodeGenerator output);
22 |
23 | public static Expression AutoCast(Expression expr, VarType expectedType)
24 | {
25 | if (expr.ResultType == expectedType || expectedType.Kind == VarKind.Any)
26 | {
27 | return expr;
28 | }
29 |
30 | switch (expr.ResultType.Kind)
31 | {
32 | case VarKind.Decimal:
33 | switch (expectedType.Kind)
34 | {
35 | case VarKind.Decimal:
36 | case VarKind.Number:
37 | return new CastExpression(expr.ParentScope, expectedType, expr);
38 | }
39 | break;
40 |
41 | case VarKind.Any:
42 | return new CastExpression(expr.ParentScope, expectedType, expr);
43 | }
44 |
45 | throw new CompilerException($"expected {expectedType} expression, got {expr.ResultType} instead");
46 | }
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/Library/src/AST/Statements/DoWhileStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 | using System;
3 |
4 | namespace Phantasma.Tomb.AST.Statements
5 | {
6 | public class DoWhileStatement : LoopStatement
7 | {
8 | public Expression condition;
9 | public StatementBlock body;
10 | public Scope Scope { get; }
11 |
12 | //private int label;
13 |
14 | public DoWhileStatement(Scope parentScope) : base()
15 | {
16 | this.Scope = new Scope(parentScope, this.NodeID);
17 | //this.label = Parser.Instance.AllocateLabel();
18 | }
19 |
20 | public override void Visit(Action callback)
21 | {
22 | callback(this);
23 |
24 | condition.Visit(callback);
25 | body.Visit(callback);
26 | }
27 |
28 | public override bool IsNodeUsed(Node node)
29 | {
30 | return (node == this) || condition.IsNodeUsed(node) || body.IsNodeUsed(node);
31 | }
32 |
33 | public override void GenerateCode(CodeGenerator output)
34 | {
35 | Compiler.Instance.PushLoop(this);
36 |
37 | output.AppendLine(this, $"@loop_start_{this.NodeID}: NOP");
38 |
39 | this.Scope.Enter(output);
40 |
41 | body.GenerateCode(output);
42 |
43 | var reg = condition.GenerateCode(output);
44 | output.AppendLine(this, $"JMPIF {reg} @loop_start_{this.NodeID}");
45 |
46 | output.AppendLine(this, $"@loop_end_{this.NodeID}: NOP");
47 |
48 | this.Scope.Leave(output);
49 |
50 | Compiler.Instance.DeallocRegister(ref reg);
51 | Compiler.Instance.PopLoop(this);
52 | }
53 | }
54 |
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/Tests/Contracts/SwitchTest.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Utils;
6 | using Phantasma.Tomb.Compilers;
7 |
8 | namespace Tests.Contracts;
9 |
10 | public class SwitchTest
11 | {
12 | [Test]
13 | public void Switch()
14 | {
15 | var sourceCode =
16 | @"
17 | contract test {
18 | public check(x:number): string {
19 | switch (x) {
20 | case 0: return ""zero"";
21 | case 1: return ""one"";
22 | case 2: return ""two"";
23 | default: return ""other"";
24 | }
25 | }}";
26 |
27 | var parser = new TombLangCompiler();
28 | var contract = parser.Process(sourceCode).First();
29 |
30 | var storage = new Dictionary(new ByteArrayComparer());
31 |
32 | var check = contract.abi.FindMethod("check");
33 | Assert.IsNotNull(check);
34 |
35 | // test different cases
36 | for (int i = -1; i <= 4; i++)
37 | {
38 | var vm = new TestVM(contract, storage, check);
39 | vm.Stack.Push(VMObject.FromObject(i));
40 | var state = vm.Execute();
41 | Assert.IsTrue(state == ExecutionState.Halt);
42 | var result = vm.Stack.Pop().AsString();
43 |
44 | string expected;
45 | switch (i)
46 | {
47 | case 0: expected = "zero"; break;
48 | case 1: expected = "one"; break;
49 | case 2: expected = "two"; break;
50 | default: expected = "other"; break;
51 | }
52 |
53 | Assert.IsTrue(result == expected);
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/Library/src/AST/Statements/WhileStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 | using System;
3 |
4 | namespace Phantasma.Tomb.AST.Statements
5 | {
6 | public class WhileStatement : LoopStatement
7 | {
8 | public Expression condition;
9 | public StatementBlock body;
10 | public Scope Scope { get; }
11 |
12 | //private int label;
13 |
14 | public WhileStatement(Scope parentScope) : base()
15 | {
16 | this.Scope = new Scope(parentScope, this.NodeID);
17 | //this.label = Parser.Instance.AllocateLabel();
18 | }
19 |
20 | public override void Visit(Action callback)
21 | {
22 | callback(this);
23 |
24 | condition.Visit(callback);
25 | body.Visit(callback);
26 | }
27 |
28 | public override bool IsNodeUsed(Node node)
29 | {
30 | return (node == this) || condition.IsNodeUsed(node) || body.IsNodeUsed(node);
31 | }
32 |
33 | public override void GenerateCode(CodeGenerator output)
34 | {
35 | Compiler.Instance.PushLoop(this);
36 |
37 | output.AppendLine(this, $"@loop_start_{this.NodeID}: NOP");
38 |
39 | var reg = condition.GenerateCode(output);
40 |
41 | this.Scope.Enter(output);
42 |
43 | output.AppendLine(this, $"JMPNOT {reg} @loop_end_{this.NodeID}");
44 | body.GenerateCode(output);
45 |
46 | output.AppendLine(this, $"JMP @loop_start_{this.NodeID}");
47 | output.AppendLine(this, $"@loop_end_{this.NodeID}: NOP");
48 |
49 | this.Scope.Leave(output);
50 |
51 | Compiler.Instance.DeallocRegister(ref reg);
52 | Compiler.Instance.PopLoop(this);
53 | }
54 | }
55 |
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/Library/tests/Contracts/SwitchTest.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Domain.Execution.Enums;
6 | using Phantasma.Core.Domain.VM;
7 | using Phantasma.Core.Utils;
8 | using Phantasma.Tomb.Compilers;
9 |
10 | namespace TOMBLib.Tests.Contracts;
11 |
12 | public class SwitchTest
13 | {
14 | [Test]
15 | public void Switch()
16 | {
17 | var sourceCode =
18 | @"
19 | contract test {
20 | public check(x:number): string {
21 | switch (x) {
22 | case 0: return ""zero"";
23 | case 1: return ""one"";
24 | case 2: return ""two"";
25 | default: return ""other"";
26 | }
27 | }}";
28 |
29 | var parser = new TombLangCompiler();
30 | var contract = parser.Process(sourceCode).First();
31 |
32 | var storage = new Dictionary(new ByteArrayComparer());
33 |
34 | var check = contract.abi.FindMethod("check");
35 | Assert.IsNotNull(check);
36 |
37 | // test different cases
38 | for (int i = -1; i <= 4; i++)
39 | {
40 | var vm = new TestVM(contract, storage, check);
41 | vm.Stack.Push(VMObject.FromObject(i));
42 | var state = vm.Execute();
43 | Assert.IsTrue(state == ExecutionState.Halt);
44 | var result = vm.Stack.Pop().AsString();
45 |
46 | string expected;
47 | switch (i)
48 | {
49 | case 0: expected = "zero"; break;
50 | case 1: expected = "one"; break;
51 | case 2: expected = "two"; break;
52 | default: expected = "other"; break;
53 | }
54 |
55 | Assert.IsTrue(result == expected);
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/Library/src/Extensions.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 | using Phantasma.Tomb.AST;
3 |
4 | namespace Phantasma.Tomb
5 | {
6 | public static class Extensions
7 | {
8 | public static string UppercaseFirst(this string s)
9 | {
10 | if (string.IsNullOrEmpty(s))
11 | {
12 | return string.Empty;
13 | }
14 | char[] a = s.ToCharArray();
15 | a[0] = char.ToUpper(a[0]);
16 | return new string(a);
17 | }
18 | public static bool IsLogicalOperator(this OperatorKind op)
19 | {
20 | return op != OperatorKind.Unknown && op < OperatorKind.Addition;
21 | }
22 |
23 | public static void CallNecessaryConstructors(this Node node, CodeGenerator output, VarType type, Register reg)
24 | {
25 | CallNecessaryConstructors(node, output, type.Kind, reg);
26 | }
27 |
28 | public static void CallNecessaryConstructors(this Node node, CodeGenerator output, VarKind kind, Register reg)
29 | {
30 | switch (kind)
31 | {
32 | case VarKind.Hash:
33 | case VarKind.Address:
34 | case VarKind.Timestamp:
35 | {
36 | var constructorName = kind.ToString();
37 | output.AppendLine(node, $"PUSH {reg}");
38 | output.AppendLine(node, $"EXTCALL \"{constructorName}()\"");
39 | output.AppendLine(node, $"POP {reg}");
40 | break;
41 | }
42 |
43 | case VarKind.Struct:
44 | {
45 | output.AppendLine(node, $"UNPACK {reg} {reg}");
46 | break;
47 | }
48 | }
49 | }
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Library/src/AST/Statements/EmitStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Declarations;
2 | using Phantasma.Tomb.CodeGen;
3 | using System;
4 |
5 | namespace Phantasma.Tomb.AST.Statements
6 | {
7 | public class EmitStatement : Statement
8 | {
9 | public EventDeclaration eventDecl;
10 |
11 | public Expression valueExpr;
12 | public Expression addressExpr;
13 |
14 | public EmitStatement(EventDeclaration evt, Expression addrExpr, Expression valueExpr) : base()
15 | {
16 | this.addressExpr = addrExpr;
17 | this.valueExpr = valueExpr;
18 | this.eventDecl = evt;
19 | }
20 |
21 | public override void Visit(Action callback)
22 | {
23 | callback(this);
24 | eventDecl.Visit(callback);
25 | addressExpr.Visit(callback);
26 | valueExpr.Visit(callback);
27 | }
28 |
29 | public override bool IsNodeUsed(Node node)
30 | {
31 | return (node == this) || eventDecl.IsNodeUsed(node) || addressExpr.IsNodeUsed(node) || valueExpr.IsNodeUsed(node);
32 | }
33 |
34 | public override void GenerateCode(CodeGenerator output)
35 | {
36 | var reg = valueExpr.GenerateCode(output);
37 | output.AppendLine(this, $"PUSH {reg}");
38 | Compiler.Instance.DeallocRegister(ref reg);
39 |
40 | reg = addressExpr.GenerateCode(output);
41 | output.AppendLine(this, $"PUSH {reg}");
42 |
43 | output.AppendLine(this, $"LOAD {reg} {eventDecl.value}");
44 | output.AppendLine(this, $"PUSH {reg}");
45 |
46 | output.AppendLine(this, $"LOAD {reg} \"Runtime.Notify\"");
47 | output.AppendLine(this, $"EXTCALL {reg}");
48 |
49 | Compiler.Instance.DeallocRegister(ref reg);
50 | }
51 | }
52 |
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/Tests/Contracts/ReturnTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Utils;
6 | using Phantasma.Tomb;
7 | using Phantasma.Tomb.Compilers;
8 |
9 | namespace Tests.Contracts;
10 |
11 | public class ReturnTests
12 | {
13 | [Test]
14 | public void MultiResultsSimple()
15 | {
16 | var sourceCode =
17 | @"
18 | contract test{
19 | public getStrings(): string* {
20 | return ""hello"";
21 | return ""world"";
22 | }
23 | }";
24 |
25 | var parser = new TombLangCompiler();
26 | var contract = parser.Process(sourceCode).First();
27 |
28 | var storage = new Dictionary(new ByteArrayComparer());
29 |
30 | TestVM vm;
31 |
32 | var getStrings = contract.abi.FindMethod("getStrings");
33 | Assert.IsNotNull(getStrings);
34 |
35 | vm = new TestVM(contract, storage, getStrings);
36 | var result = vm.Execute();
37 | Assert.IsTrue(result == ExecutionState.Halt);
38 |
39 | Assert.IsTrue(vm.Stack.Count == 2);
40 |
41 | var obj = vm.Stack.Pop();
42 | var x = obj.AsString();
43 | Assert.IsTrue(x == "world");
44 |
45 | obj = vm.Stack.Pop();
46 | x = obj.AsString();
47 | Assert.IsTrue(x == "hello");
48 | }
49 |
50 | [Test]
51 | public void MultiResultsEarlyReturn()
52 | {
53 | var sourceCode =
54 | @"
55 | contract test{
56 | public getStrings(): string* {
57 | return ""ok"";
58 | return;
59 | return ""bug""; // this line should not compile
60 | }
61 | }";
62 |
63 | var parser = new TombLangCompiler();
64 |
65 | Assert.Catch(() =>
66 | {
67 | var contract = parser.Process(sourceCode).First();
68 | });
69 | }
70 |
71 | }
--------------------------------------------------------------------------------
/Library/src/AST/Expressions/ArrayExpression.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace Phantasma.Tomb.AST.Expressions
6 | {
7 | public class ArrayExpression : Expression
8 | {
9 | public List elements;
10 |
11 | public ArrayExpression(Scope parentScope) : base(parentScope)
12 | {
13 | this.elements = new List();
14 | }
15 |
16 | public override string ToString()
17 | {
18 | return $"array[{ResultType}: {elements.Count}]";
19 | }
20 |
21 | public override Register GenerateCode(CodeGenerator output)
22 | {
23 | var reg = Compiler.Instance.AllocRegister(output, this, this.NodeID);
24 |
25 | output.AppendLine(this, $"CLEAR {reg}");
26 |
27 | var idxReg = Compiler.Instance.AllocRegister(output, this, "_array_init_idx");
28 |
29 | for (int i=0; i callback)
42 | {
43 | callback(this);
44 | }
45 |
46 | public override bool IsNodeUsed(Node node)
47 | {
48 | return (node == this);
49 | }
50 |
51 | public override VarType ResultType
52 | {
53 | get
54 | {
55 | var elementType = elements.Count > 0 ? elements[0].ResultType : VarType.Find(VarKind.Unknown);
56 | return VarType.Find(VarKind.Array, elementType);
57 | }
58 | }
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/Library/tests/Contracts/ReturnTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Domain.Execution.Enums;
6 | using Phantasma.Core.Utils;
7 | using Phantasma.Tomb;
8 | using Phantasma.Tomb.Compilers;
9 |
10 | namespace TOMBLib.Tests.Contracts;
11 |
12 | public class ReturnTests
13 | {
14 | [Test]
15 | public void MultiResultsSimple()
16 | {
17 | var sourceCode =
18 | @"
19 | contract test{
20 | public getStrings(): string* {
21 | return ""hello"";
22 | return ""world"";
23 | }
24 | }";
25 |
26 | var parser = new TombLangCompiler();
27 | var contract = parser.Process(sourceCode).First();
28 |
29 | var storage = new Dictionary(new ByteArrayComparer());
30 |
31 | TestVM vm;
32 |
33 | var getStrings = contract.abi.FindMethod("getStrings");
34 | Assert.IsNotNull(getStrings);
35 |
36 | vm = new TestVM(contract, storage, getStrings);
37 | var result = vm.Execute();
38 | Assert.IsTrue(result == ExecutionState.Halt);
39 |
40 | Assert.IsTrue(vm.Stack.Count == 2);
41 |
42 | var obj = vm.Stack.Pop();
43 | var x = obj.AsString();
44 | Assert.IsTrue(x == "world");
45 |
46 | obj = vm.Stack.Pop();
47 | x = obj.AsString();
48 | Assert.IsTrue(x == "hello");
49 | }
50 |
51 | [Test]
52 | public void MultiResultsEarlyReturn()
53 | {
54 | var sourceCode =
55 | @"
56 | contract test{
57 | public getStrings(): string* {
58 | return ""ok"";
59 | return;
60 | return ""bug""; // this line should not compile
61 | }
62 | }";
63 |
64 | var parser = new TombLangCompiler();
65 |
66 | Assert.Catch(() =>
67 | {
68 | var contract = parser.Process(sourceCode).First();
69 | });
70 | }
71 |
72 | }
--------------------------------------------------------------------------------
/Library/src/AST/Statements/AssignStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Declarations;
2 | using Phantasma.Tomb.CodeGen;
3 | using System;
4 |
5 | namespace Phantasma.Tomb.AST.Statements
6 | {
7 | public class AssignStatement : Statement
8 | {
9 | public VarDeclaration variable;
10 | public Expression valueExpression;
11 | public Expression keyExpression; // can be null, if not null it should be an expression that resolves into a key (struct field name or array index)
12 |
13 | public AssignStatement() : base()
14 | {
15 |
16 | }
17 |
18 | public override void Visit(Action callback)
19 | {
20 | callback(this);
21 | variable.Visit(callback);
22 | valueExpression.Visit(callback);
23 | keyExpression?.Visit(callback);
24 | }
25 |
26 | public override bool IsNodeUsed(Node node)
27 | {
28 | return (node == this) || variable.IsNodeUsed(node) || valueExpression.IsNodeUsed(node) || (keyExpression != null && keyExpression.IsNodeUsed(node));
29 | }
30 |
31 | public override void GenerateCode(CodeGenerator output)
32 | {
33 | if (variable.Register == null)
34 | {
35 | variable.Register = Compiler.Instance.AllocRegister(output, variable, variable.Name);
36 | }
37 |
38 | var srcReg = valueExpression.GenerateCode(output);
39 |
40 | if (keyExpression != null)
41 | {
42 | var idxReg = keyExpression.GenerateCode(output);
43 |
44 | output.AppendLine(this, $"PUT {srcReg} {variable.Register} {idxReg}");
45 |
46 | Compiler.Instance.DeallocRegister(ref idxReg);
47 | }
48 | else
49 | {
50 | output.AppendLine(this, $"COPY {srcReg} {variable.Register}");
51 | }
52 |
53 | Compiler.Instance.DeallocRegister(ref srcReg);
54 | }
55 | }
56 |
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/Tests/Contracts/PropertiesTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Utils;
7 | using Phantasma.Tomb.Compilers;
8 |
9 | namespace Tests.Contracts;
10 |
11 | public class PropertiesTests
12 | {
13 | [Test]
14 | public void Properties()
15 | {
16 | string[] sourceCode = new string[]
17 | {
18 | "token TEST {",
19 | "property name:string = \"Unit test\";",
20 | " global _feesSymbol:string;",
21 | $" property feesSymbol:string = _feesSymbol;",
22 | " constructor(owner:address) {",
23 | " _feesSymbol = \"KCAL\";",
24 | "}}"
25 | };
26 |
27 | var parser = new TombLangCompiler();
28 | var contract = parser.Process(sourceCode).First();
29 |
30 | var storage = new Dictionary(new ByteArrayComparer());
31 |
32 | TestVM vm;
33 |
34 | var constructor = contract.abi.FindMethod(SmartContract.ConstructorName);
35 | Assert.IsNotNull(constructor);
36 |
37 | var keys = PhantasmaKeys.Generate();
38 |
39 | vm = new TestVM(contract, storage, constructor);
40 | vm.Stack.Push(VMObject.FromObject(keys.Address));
41 | var result = vm.Execute();
42 | Assert.IsTrue(result == ExecutionState.Halt);
43 |
44 | Assert.IsTrue(storage.Count == 1);
45 |
46 | // call getFeesSymbol
47 | var getValue = contract.abi.FindMethod("getFeesSymbol");
48 | Assert.IsNotNull(getValue);
49 |
50 | vm = new TestVM(contract, storage, getValue);
51 | result = vm.Execute();
52 | Assert.IsTrue(result == ExecutionState.Halt);
53 |
54 | Assert.IsTrue(vm.Stack.Count == 1);
55 |
56 | var obj = vm.Stack.Pop();
57 | var newVal = obj.AsString();
58 | var expectedVal = "KCAL";
59 |
60 | Assert.IsTrue(newVal == expectedVal);
61 | }
62 | }
--------------------------------------------------------------------------------
/.github/workflows/dotnet-core.yml:
--------------------------------------------------------------------------------
1 | name: .NET Core
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master, dev]
8 |
9 | permissions:
10 | pull-requests: write
11 | issues: write
12 | contents: write
13 | actions: write
14 | id-token: write
15 | packages: write
16 | deployments: write
17 | discussions: write
18 |
19 | env:
20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
21 |
22 | jobs:
23 | build:
24 | name: Build TOMB
25 | runs-on: ubuntu-latest
26 | permissions: write-all
27 |
28 | steps:
29 | - uses: actions/checkout@v3
30 | - name: Setup .NET
31 | uses: actions/setup-dotnet@v2
32 | with:
33 | dotnet-version: 6.0.x
34 |
35 | - name: Install dependencies
36 | run: |
37 | sudo apt-get install libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev libzstd-dev
38 | sudo apt-get install libc6-dev libicu-dev libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev libzstd-dev librocksdb-dev
39 | sudo apt-get install librocksdb-dev
40 | dotnet tool install --global dotnet-reportgenerator-globaltool
41 | dotnet restore
42 |
43 | - name: Build
44 | run: dotnet build --configuration Release --no-restore
45 |
46 | - name: Test
47 | run: dotnet test --no-build --configuration Release --verbosity normal --collect:"XPlat Code Coverage" --results-directory ./coverage
48 |
49 | - name: Combine Coverage Output
50 | run: reportgenerator "-reports:coverage/**/coverage.cobertura.xml" -targetdir:"coverage" -reporttypes:Cobertura -assemblyfilters:"-TOMBLib.Tests"
51 |
52 | - name: Code Coverage Summary Report
53 | uses: irongut/CodeCoverageSummary@v1.3.0
54 | with:
55 | filename: coverage/Cobertura.xml
56 | badge: true
57 | fail_below_min: false
58 | format: markdown
59 | hide_branch_rate: false
60 | hide_complexity: false
61 | indicators: true
62 | output: both
63 | thresholds: '60 80'
--------------------------------------------------------------------------------
/Tests/Contracts/AddressTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Utils;
7 | using Phantasma.Tomb.Compilers;
8 |
9 | namespace Tests.Contracts;
10 |
11 | public class AddressTests
12 | {
13 | [Test]
14 | public void QueryMethodAddress()
15 | {
16 | string[] sourceCode = new string[]
17 | {
18 | "token TEST {",
19 | "property name:string = \"Unit test\";",
20 | " global _feesAddress:address;",
21 | $" property feesAddress:address = _feesAddress;",
22 | " constructor(owner:address) {",
23 | " _feesAddress = @P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM;",
24 | "}}"
25 | };
26 |
27 | var parser = new TombLangCompiler();
28 | var contract = parser.Process(sourceCode).First();
29 |
30 | var storage = new Dictionary(new ByteArrayComparer());
31 |
32 | TestVM vm;
33 |
34 | var constructor = contract.abi.FindMethod(SmartContract.ConstructorName);
35 | Assert.IsNotNull(constructor);
36 |
37 | var keys = PhantasmaKeys.Generate();
38 |
39 | vm = new TestVM(contract, storage, constructor);
40 | vm.Stack.Push(VMObject.FromObject(keys.Address));
41 | var result = vm.Execute();
42 | Assert.IsTrue(result == ExecutionState.Halt);
43 |
44 | Assert.IsTrue(storage.Count == 1);
45 |
46 | // call getFeesAddress
47 | var getValue = contract.abi.FindMethod("getFeesAddress");
48 | Assert.IsNotNull(getValue);
49 |
50 | vm = new TestVM(contract, storage, getValue);
51 | result = vm.Execute();
52 | Assert.IsTrue(result == ExecutionState.Halt);
53 |
54 | Assert.IsTrue(vm.Stack.Count == 1);
55 |
56 | var obj = vm.Stack.Pop();
57 | var newVal = obj.AsString();
58 | var expectedVal = "P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM";
59 |
60 | Assert.IsTrue(newVal == expectedVal);
61 | }
62 |
63 | }
--------------------------------------------------------------------------------
/Library/tests/Contracts/PropertiesTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Domain.Contract;
7 | using Phantasma.Core.Domain.Execution.Enums;
8 | using Phantasma.Core.Domain.VM;
9 | using Phantasma.Core.Utils;
10 | using Phantasma.Tomb.Compilers;
11 |
12 | namespace TOMBLib.Tests.Contracts;
13 |
14 | public class PropertiesTests
15 | {
16 | [Test]
17 | public void Properties()
18 | {
19 | string[] sourceCode = new string[]
20 | {
21 | "token TEST {",
22 | "property name:string = \"Unit test\";",
23 | " global _feesSymbol:string;",
24 | $" property feesSymbol:string = _feesSymbol;",
25 | " constructor(owner:address) {",
26 | " _feesSymbol = \"KCAL\";",
27 | "}}"
28 | };
29 |
30 | var parser = new TombLangCompiler();
31 | var contract = parser.Process(sourceCode).First();
32 |
33 | var storage = new Dictionary(new ByteArrayComparer());
34 |
35 | TestVM vm;
36 |
37 | var constructor = contract.abi.FindMethod(SmartContract.ConstructorName);
38 | Assert.IsNotNull(constructor);
39 |
40 | var keys = PhantasmaKeys.Generate();
41 |
42 | vm = new TestVM(contract, storage, constructor);
43 | vm.Stack.Push(VMObject.FromObject(keys.Address));
44 | var result = vm.Execute();
45 | Assert.IsTrue(result == ExecutionState.Halt);
46 |
47 | Assert.IsTrue(storage.Count == 1);
48 |
49 | // call getFeesSymbol
50 | var getValue = contract.abi.FindMethod("getFeesSymbol");
51 | Assert.IsNotNull(getValue);
52 |
53 | vm = new TestVM(contract, storage, getValue);
54 | result = vm.Execute();
55 | Assert.IsTrue(result == ExecutionState.Halt);
56 |
57 | Assert.IsTrue(vm.Stack.Count == 1);
58 |
59 | var obj = vm.Stack.Pop();
60 | var newVal = obj.AsString();
61 | var expectedVal = "KCAL";
62 |
63 | Assert.IsTrue(newVal == expectedVal);
64 | }
65 | }
--------------------------------------------------------------------------------
/Library/src/AST/Statements/IfStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 | using System;
3 |
4 | namespace Phantasma.Tomb.AST.Statements
5 | {
6 | public class IfStatement : Statement
7 | {
8 | public Expression condition;
9 | public StatementBlock body;
10 | public StatementBlock @else;
11 | public Scope Scope { get; }
12 |
13 | //private int label;
14 |
15 | public IfStatement(Scope parentScope) : base()
16 | {
17 | this.Scope = new Scope(parentScope, this.NodeID);
18 | //this.label = Parser.Instance.AllocateLabel();
19 | }
20 |
21 | public override void Visit(Action callback)
22 | {
23 | callback(this);
24 |
25 | condition.Visit(callback);
26 | body.Visit(callback);
27 | @else?.Visit(callback);
28 | }
29 |
30 | public override bool IsNodeUsed(Node node)
31 | {
32 | if (@else != null && @else.IsNodeUsed(node))
33 | {
34 | return true;
35 | }
36 |
37 | return (node == this) || condition.IsNodeUsed(node) || body.IsNodeUsed(node);
38 | }
39 |
40 | public override void GenerateCode(CodeGenerator output)
41 | {
42 | var reg = condition.GenerateCode(output);
43 |
44 | this.Scope.Enter(output);
45 | if (@else != null)
46 | {
47 | output.AppendLine(this, $"JMPNOT {reg} @else_{this.NodeID}");
48 | body.GenerateCode(output);
49 | output.AppendLine(this, $"JMP @then_{this.NodeID}");
50 | output.AppendLine(this, $"@else_{this.NodeID}: NOP");
51 | @else.GenerateCode(output);
52 | }
53 | else
54 | {
55 | output.AppendLine(this, $"JMPNOT {reg} @then_{this.NodeID}");
56 | body.GenerateCode(output);
57 | }
58 | output.AppendLine(this, $"@then_{this.NodeID}: NOP");
59 | this.Scope.Leave(output);
60 |
61 | Compiler.Instance.DeallocRegister(ref reg);
62 |
63 | }
64 | }
65 |
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/Library/src/AST/Expressions/StructFieldExpression.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Declarations;
2 | using Phantasma.Tomb.CodeGen;
3 |
4 | using System;
5 |
6 | namespace Phantasma.Tomb.AST.Expressions
7 | {
8 | public class StructFieldExpression : Expression
9 | {
10 | public VarDeclaration varDecl;
11 | public string fieldName;
12 |
13 | public override VarType ResultType { get; }
14 |
15 | public StructFieldExpression(Scope parentScope, VarDeclaration varDecl, string fieldName) : base(parentScope)
16 | {
17 | var structInfo = ((StructVarType)varDecl.Type);
18 |
19 | VarType fieldType = null;
20 |
21 | foreach (var field in structInfo.decl.fields)
22 | {
23 | if (field.name == fieldName)
24 | {
25 | fieldType = field.type;
26 | }
27 | }
28 |
29 | if (fieldType == null)
30 | {
31 | throw new CompilerException($"Struct {varDecl.Type} does not contain field: {fieldName}");
32 | }
33 |
34 | this.varDecl = varDecl;
35 | this.fieldName = fieldName;
36 | this.ResultType = fieldType;
37 | }
38 |
39 | public override void Visit(Action callback)
40 | {
41 | callback(this);
42 | varDecl.Visit(callback);
43 | }
44 |
45 | public override bool IsNodeUsed(Node node)
46 | {
47 | return (node == this || node == varDecl);
48 | }
49 |
50 | public override Register GenerateCode(CodeGenerator output)
51 | {
52 | var reg = Compiler.Instance.AllocRegister(output, this/*, $"{varDecl.Name}.{fieldName}"*/);
53 |
54 | var tempReg = Compiler.Instance.AllocRegister(output, this);
55 |
56 | output.AppendLine(this, $"COPY {varDecl.Register} {reg}");
57 | output.AppendLine(this, $"LOAD {tempReg} \"{fieldName}\"");
58 | output.AppendLine(this, $"GET {reg} {reg} {tempReg}");
59 |
60 | Compiler.Instance.DeallocRegister(ref tempReg);
61 |
62 | return reg;
63 | }
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/TombCompiler.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.3.32811.315
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TombCompiler", "Compiler\TombCompiler.csproj", "{A669C9C4-AA5E-4BBD-9A8A-569B6B50A5D4}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TOMBLib", "Library\src\TOMBLib.csproj", "{86AA09AA-ED89-4097-97A3-E3E3E0EF5A86}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TOMBLib.Tests", "Library\tests\TOMBLib.Tests.csproj", "{EA79025B-F50F-4608-B2BC-77D776AE99EB}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {A669C9C4-AA5E-4BBD-9A8A-569B6B50A5D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {A669C9C4-AA5E-4BBD-9A8A-569B6B50A5D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {A669C9C4-AA5E-4BBD-9A8A-569B6B50A5D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {A669C9C4-AA5E-4BBD-9A8A-569B6B50A5D4}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {86AA09AA-ED89-4097-97A3-E3E3E0EF5A86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {86AA09AA-ED89-4097-97A3-E3E3E0EF5A86}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {86AA09AA-ED89-4097-97A3-E3E3E0EF5A86}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {86AA09AA-ED89-4097-97A3-E3E3E0EF5A86}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {EA79025B-F50F-4608-B2BC-77D776AE99EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {EA79025B-F50F-4608-B2BC-77D776AE99EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {EA79025B-F50F-4608-B2BC-77D776AE99EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {EA79025B-F50F-4608-B2BC-77D776AE99EB}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {BD1476E1-CAAE-4BFB-8E2F-FBA3F82EE3A8}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/Tests/Contracts/EnumsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Utils;
7 | using Phantasma.Tomb.Compilers;
8 |
9 | namespace Tests.Contracts;
10 |
11 | public class EnumsTests
12 | {
13 | public enum MyEnum
14 | {
15 | A,
16 | B,
17 | C,
18 | }
19 |
20 | [Test]
21 | public void Enums()
22 | {
23 | string[] sourceCode = new string[]
24 | {
25 | "enum MyEnum { A, B, C}",
26 | "contract test{",
27 | $"global state: MyEnum;",
28 | "constructor(owner:address) {",
29 | "state = MyEnum.B;}",
30 | "public getValue():MyEnum {",
31 | "return state;}",
32 | "public isSet(val:MyEnum):bool {",
33 | "return state.isSet(val);}",
34 | "}"
35 | };
36 |
37 | var parser = new TombLangCompiler();
38 | var contract = parser.Process(sourceCode).First();
39 |
40 | var storage = new Dictionary(new ByteArrayComparer());
41 |
42 | TestVM vm;
43 |
44 | var constructor = contract.abi.FindMethod(SmartContract.ConstructorName);
45 | Assert.IsNotNull(constructor);
46 |
47 | var keys = PhantasmaKeys.Generate();
48 |
49 | vm = new TestVM(contract, storage, constructor);
50 | vm.Stack.Push(VMObject.FromObject(keys.Address));
51 | var result = vm.Execute();
52 | Assert.IsTrue(result == ExecutionState.Halt);
53 |
54 | Assert.IsTrue(storage.Count == 1);
55 |
56 | // call getVal
57 | var getValue = contract.abi.FindMethod("getValue");
58 | Assert.IsNotNull(getValue);
59 |
60 | vm = new TestVM(contract, storage, getValue);
61 | result = vm.Execute();
62 | Assert.IsTrue(result == ExecutionState.Halt);
63 |
64 | Assert.IsTrue(storage.Count == 1);
65 |
66 | Assert.IsTrue(vm.Stack.Count == 1);
67 |
68 | var obj = vm.Stack.Pop();
69 | var newVal = obj.AsEnum();
70 | var expectedVal = MyEnum.B;
71 |
72 | Assert.IsTrue(newVal == expectedVal);
73 | }
74 | }
--------------------------------------------------------------------------------
/Library/src/AST/Expressions/ArrayElementExpression.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Declarations;
2 | using Phantasma.Tomb.CodeGen;
3 |
4 | using System;
5 |
6 | namespace Phantasma.Tomb.AST.Expressions
7 | {
8 | public class ArrayElementExpression : Expression
9 | {
10 | public VarDeclaration decl;
11 | public Expression indexExpression;
12 |
13 | public ArrayElementExpression(Scope parentScope, VarDeclaration declaration, Expression indexExpression) : base(parentScope)
14 | {
15 | this.decl = declaration;
16 | this.indexExpression = indexExpression;
17 | }
18 |
19 | public override string ToString()
20 | {
21 | return $"{decl}[{indexExpression}]";
22 | }
23 |
24 | public override Register GenerateCode(CodeGenerator output)
25 | {
26 | if (decl.Register == null)
27 | {
28 | throw new CompilerException(this, $"var not initialized:" + decl.Name);
29 | }
30 |
31 | var dstReg = Compiler.Instance.AllocRegister(output, this);
32 | var idxReg = indexExpression.GenerateCode(output);
33 |
34 | var reg = decl.Register;
35 | output.AppendLine(this, $"GET {reg} {dstReg} {idxReg}");
36 |
37 | var arrayType = decl.Type as ArrayVarType;
38 | if (arrayType == null)
39 | {
40 | throw new CompilerException(this, $"expected array type:" + decl.Name);
41 | }
42 | this.CallNecessaryConstructors(output, arrayType.elementType, decl.Register);
43 |
44 | Compiler.Instance.DeallocRegister(ref idxReg);
45 |
46 | return dstReg;
47 | }
48 |
49 | public override void Visit(Action callback)
50 | {
51 | callback(this);
52 | decl.Visit(callback);
53 | indexExpression.Visit(callback);
54 | }
55 |
56 | public override bool IsNodeUsed(Node node)
57 | {
58 | return (node == this) || node == decl;
59 | }
60 |
61 | public override VarType ResultType => decl.Type is ArrayVarType ? ((ArrayVarType)decl.Type).elementType : VarType.Find(VarKind.Unknown);
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/Library/tests/Contracts/AddressTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Domain.Contract;
7 | using Phantasma.Core.Domain.Execution.Enums;
8 | using Phantasma.Core.Domain.VM;
9 | using Phantasma.Core.Utils;
10 | using Phantasma.Tomb.Compilers;
11 |
12 | namespace TOMBLib.Tests.Contracts;
13 |
14 | public class AddressTests
15 | {
16 | [Test]
17 | public void QueryMethodAddress()
18 | {
19 | string[] sourceCode = new string[]
20 | {
21 | "token TEST {",
22 | "property name:string = \"Unit test\";",
23 | " global _feesAddress:address;",
24 | $" property feesAddress:address = _feesAddress;",
25 | " constructor(owner:address) {",
26 | " _feesAddress = @P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM;",
27 | "}}"
28 | };
29 |
30 | var parser = new TombLangCompiler();
31 | var contract = parser.Process(sourceCode).First();
32 |
33 | var storage = new Dictionary(new ByteArrayComparer());
34 |
35 | TestVM vm;
36 |
37 | var constructor = contract.abi.FindMethod(SmartContract.ConstructorName);
38 | Assert.IsNotNull(constructor);
39 |
40 | var keys = PhantasmaKeys.Generate();
41 |
42 | vm = new TestVM(contract, storage, constructor);
43 | vm.Stack.Push(VMObject.FromObject(keys.Address));
44 | var result = vm.Execute();
45 | Assert.IsTrue(result == ExecutionState.Halt);
46 |
47 | Assert.IsTrue(storage.Count == 1);
48 |
49 | // call getFeesAddress
50 | var getValue = contract.abi.FindMethod("getFeesAddress");
51 | Assert.IsNotNull(getValue);
52 |
53 | vm = new TestVM(contract, storage, getValue);
54 | result = vm.Execute();
55 | Assert.IsTrue(result == ExecutionState.Halt);
56 |
57 | Assert.IsTrue(vm.Stack.Count == 1);
58 |
59 | var obj = vm.Stack.Pop();
60 | var newVal = obj.AsString();
61 | var expectedVal = "P2KEYzWsbrMbPNtW1tBzzDKeYxYi4hjzpx4EfiyRyaoLkMM";
62 |
63 | Assert.IsTrue(newVal == expectedVal);
64 | }
65 |
66 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Declaration/StructDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST;
2 | using Phantasma.Tomb.AST.Declarations;
3 | using Phantasma.Tomb.Lexers;
4 |
5 | namespace TOMBLib.Tests.AST.Declaration;
6 |
7 | public class StructDeclarationTests
8 | {
9 | [SetUp]
10 | public void Setup()
11 | {
12 | TombLangLexer lexer = new TombLangLexer();
13 | }
14 |
15 | [Test]
16 | public void Constructor_WithValidArguments_CreatesFieldsArray()
17 | {
18 | // Arrange
19 | var name = "MyStruct";
20 | var fields = new List()
21 | {
22 | new StructField("myInt", VarType.Find(VarKind.Number)),
23 | new StructField("myFloat", VarType.Find(VarKind.Decimal,2)),
24 | new StructField("myString", VarType.Find(VarKind.String)),
25 | };
26 |
27 | // Act
28 | var structDeclaration = new StructDeclaration(name, fields);
29 |
30 | // Assert
31 | Assert.That(structDeclaration.Name, Is.EqualTo(name));
32 | Assert.That(structDeclaration.fields, Is.Not.Null);
33 | Assert.That(structDeclaration.fields.Length, Is.EqualTo(fields.Count));
34 | for (int i = 0; i < fields.Count; i++)
35 | {
36 | Assert.That(structDeclaration.fields[i].name, Is.EqualTo(fields[i].name));
37 | Assert.That(structDeclaration.fields[i].type, Is.EqualTo(fields[i].type));
38 | }
39 | }
40 |
41 | [Test]
42 | public void IsNodeUsed_WithSameNode_ReturnsTrue()
43 | {
44 | // Arrange
45 | var structDeclaration = new StructDeclaration("MyStruct", new List());
46 |
47 | // Act
48 | var isUsed = structDeclaration.IsNodeUsed(structDeclaration);
49 |
50 | // Assert
51 | Assert.That(isUsed, Is.True);
52 | }
53 |
54 | [Test]
55 | public void Visit_WithCallback_CallsCallbackWithThisNode()
56 | {
57 | // Arrange
58 | var structDeclaration = new StructDeclaration("MyStruct", new List());
59 | bool isCallbackCalled = false;
60 |
61 | // Act
62 | structDeclaration.Visit(node => isCallbackCalled = (node == structDeclaration));
63 |
64 | // Assert
65 | Assert.That(isCallbackCalled, Is.True);
66 | }
67 | }
--------------------------------------------------------------------------------
/Library/src/AST/Statements/ForStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Declarations;
2 | using Phantasma.Tomb.CodeGen;
3 | using System;
4 |
5 | namespace Phantasma.Tomb.AST.Statements
6 | {
7 | public class ForStatement : LoopStatement
8 | {
9 | public VarDeclaration loopVar;
10 | public Expression condition;
11 | public Statement initStatement;
12 | public Statement loopStatement;
13 |
14 | public StatementBlock body;
15 | public Scope Scope { get; }
16 |
17 | //private int label;
18 |
19 | public ForStatement(Scope parentScope) : base()
20 | {
21 | this.Scope = new Scope(parentScope, this.NodeID);
22 | //this.label = Parser.Instance.AllocateLabel();
23 | }
24 |
25 | public override void Visit(Action callback)
26 | {
27 | callback(this);
28 |
29 | loopVar.Visit(callback);
30 | initStatement.Visit(callback);
31 | condition.Visit(callback);
32 | loopStatement.Visit(callback);
33 | body.Visit(callback);
34 | }
35 |
36 | public override bool IsNodeUsed(Node node)
37 | {
38 | return (node == this) || condition.IsNodeUsed(node) || body.IsNodeUsed(node) || loopVar.IsNodeUsed(node) || loopStatement.IsNodeUsed(node) || initStatement.IsNodeUsed(node);
39 | }
40 |
41 | public override void GenerateCode(CodeGenerator output)
42 | {
43 | initStatement.GenerateCode(output);
44 |
45 | Compiler.Instance.PushLoop(this);
46 |
47 | output.AppendLine(this, $"@loop_start_{this.NodeID}: NOP");
48 |
49 | var reg = condition.GenerateCode(output);
50 |
51 | this.Scope.Enter(output);
52 |
53 | output.AppendLine(this, $"JMPNOT {reg} @loop_end_{this.NodeID}");
54 | body.GenerateCode(output);
55 | loopStatement.GenerateCode(output);
56 |
57 | output.AppendLine(this, $"JMP @loop_start_{this.NodeID}");
58 | output.AppendLine(this, $"@loop_end_{this.NodeID}: NOP");
59 |
60 | this.Scope.Leave(output);
61 |
62 | Compiler.Instance.DeallocRegister(ref reg);
63 | Compiler.Instance.PopLoop(this);
64 | }
65 | }
66 |
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/Tests/AST/Declaration/StructDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using NUnit.Framework;
3 | using Phantasma.Tomb.AST;
4 | using Phantasma.Tomb.AST.Declarations;
5 | using Phantasma.Tomb.Lexers;
6 |
7 | namespace Tests.AST.Declaration;
8 |
9 | public class StructDeclarationTests
10 | {
11 | [SetUp]
12 | public void Setup()
13 | {
14 | TombLangLexer lexer = new TombLangLexer();
15 | }
16 |
17 | [Test]
18 | public void Constructor_WithValidArguments_CreatesFieldsArray()
19 | {
20 | // Arrange
21 | var name = "MyStruct";
22 | var fields = new List()
23 | {
24 | new StructField("myInt", VarType.Find(VarKind.Number)),
25 | new StructField("myFloat", VarType.Find(VarKind.Decimal,2)),
26 | new StructField("myString", VarType.Find(VarKind.String)),
27 | };
28 |
29 | // Act
30 | var structDeclaration = new StructDeclaration(name, fields);
31 |
32 | // Assert
33 | Assert.That(structDeclaration.Name, Is.EqualTo(name));
34 | Assert.That(structDeclaration.fields, Is.Not.Null);
35 | Assert.That(structDeclaration.fields.Length, Is.EqualTo(fields.Count));
36 | for (int i = 0; i < fields.Count; i++)
37 | {
38 | Assert.That(structDeclaration.fields[i].name, Is.EqualTo(fields[i].name));
39 | Assert.That(structDeclaration.fields[i].type, Is.EqualTo(fields[i].type));
40 | }
41 | }
42 |
43 | [Test]
44 | public void IsNodeUsed_WithSameNode_ReturnsTrue()
45 | {
46 | // Arrange
47 | var structDeclaration = new StructDeclaration("MyStruct", new List());
48 |
49 | // Act
50 | var isUsed = structDeclaration.IsNodeUsed(structDeclaration);
51 |
52 | // Assert
53 | Assert.That(isUsed, Is.True);
54 | }
55 |
56 | [Test]
57 | public void Visit_WithCallback_CallsCallbackWithThisNode()
58 | {
59 | // Arrange
60 | var structDeclaration = new StructDeclaration("MyStruct", new List());
61 | bool isCallbackCalled = false;
62 |
63 | // Act
64 | structDeclaration.Visit(node => isCallbackCalled = (node == structDeclaration));
65 |
66 | // Assert
67 | Assert.That(isCallbackCalled, Is.True);
68 | }
69 | }
--------------------------------------------------------------------------------
/Library/tests/Contracts/EnumsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Domain.Contract;
7 | using Phantasma.Core.Domain.Execution.Enums;
8 | using Phantasma.Core.Domain.VM;
9 | using Phantasma.Core.Utils;
10 | using Phantasma.Tomb.Compilers;
11 |
12 | namespace TOMBLib.Tests.Contracts;
13 |
14 | public class EnumsTests
15 | {
16 | public enum MyEnum
17 | {
18 | A,
19 | B,
20 | C,
21 | }
22 |
23 | [Test]
24 | public void Enums()
25 | {
26 | string[] sourceCode = new string[]
27 | {
28 | "enum MyEnum { A, B, C}",
29 | "contract test{",
30 | $"global state: MyEnum;",
31 | "constructor(owner:address) {",
32 | "state = MyEnum.B;}",
33 | "public getValue():MyEnum {",
34 | "return state;}",
35 | "public isSet(val:MyEnum):bool {",
36 | "return state.isSet(val);}",
37 | "}"
38 | };
39 |
40 | var parser = new TombLangCompiler();
41 | var contract = parser.Process(sourceCode).First();
42 |
43 | var storage = new Dictionary(new ByteArrayComparer());
44 |
45 | TestVM vm;
46 |
47 | var constructor = contract.abi.FindMethod(SmartContract.ConstructorName);
48 | Assert.IsNotNull(constructor);
49 |
50 | var keys = PhantasmaKeys.Generate();
51 |
52 | vm = new TestVM(contract, storage, constructor);
53 | vm.Stack.Push(VMObject.FromObject(keys.Address));
54 | var result = vm.Execute();
55 | Assert.IsTrue(result == ExecutionState.Halt);
56 |
57 | Assert.IsTrue(storage.Count == 1);
58 |
59 | // call getVal
60 | var getValue = contract.abi.FindMethod("getValue");
61 | Assert.IsNotNull(getValue);
62 |
63 | vm = new TestVM(contract, storage, getValue);
64 | result = vm.Execute();
65 | Assert.IsTrue(result == ExecutionState.Halt);
66 |
67 | Assert.IsTrue(storage.Count == 1);
68 |
69 | Assert.IsTrue(vm.Stack.Count == 1);
70 |
71 | var obj = vm.Stack.Pop();
72 | var newVal = obj.AsEnum();
73 | var expectedVal = MyEnum.B;
74 |
75 | Assert.IsTrue(newVal == expectedVal);
76 | }
77 | }
--------------------------------------------------------------------------------
/Library/src/AST/Statements/SwitchStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Expressions;
2 | using Phantasma.Tomb.CodeGen;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace Phantasma.Tomb.AST.Statements
7 | {
8 | public class SwitchStatement : Statement
9 | {
10 | public VarExpression variable;
11 | public StatementBlock @default;
12 | public List cases = new List();
13 | public Scope Scope { get; }
14 |
15 | //private int label;
16 |
17 | public SwitchStatement(Scope parentScope) : base()
18 | {
19 | this.Scope = new Scope(parentScope, this.NodeID);
20 | //this.label = Parser.Instance.AllocateLabel();
21 | }
22 |
23 | public override void Visit(Action callback)
24 | {
25 | callback(this);
26 |
27 | variable.Visit(callback);
28 | foreach (var entry in cases)
29 | {
30 | entry.Visit(callback);
31 | }
32 |
33 | @default?.Visit(callback);
34 | }
35 |
36 | public override bool IsNodeUsed(Node node)
37 | {
38 | foreach (var entry in cases)
39 | {
40 | if (entry.IsNodeUsed(node))
41 | {
42 | return true;
43 | }
44 | }
45 |
46 | if (@default != null && @default.IsNodeUsed(node))
47 | {
48 | return true;
49 | }
50 |
51 | return (node == this);
52 | }
53 |
54 | public override void GenerateCode(CodeGenerator output)
55 | {
56 | var reg = variable.GenerateCode(output);
57 | var endLabel = $"@end_case_{this.NodeID}";
58 |
59 | this.Scope.Enter(output);
60 |
61 | foreach (var entry in cases)
62 | {
63 | entry.variable = reg;
64 | entry.endLabel = endLabel;
65 | entry.GenerateCode(output);
66 | }
67 |
68 | if (@default != null)
69 | {
70 | @default.GenerateCode(output);
71 | }
72 |
73 | output.AppendLine(this, $"{endLabel}: NOP");
74 | this.Scope.Leave(output);
75 |
76 | Compiler.Instance.DeallocRegister(ref reg);
77 |
78 | }
79 | }
80 |
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/Tests/Contracts/VariableTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Utils;
7 | using Phantasma.Tomb.Compilers;
8 |
9 | namespace Tests.Contracts;
10 |
11 | public class VariableTests
12 | {
13 | [Test]
14 | public void TypeOf()
15 | {
16 | var sourceCode = new string[]
17 | {
18 | "contract test{",
19 | "public returnType() : type {",
20 | "return $TYPE_OF(string);",
21 | "}}"
22 | };
23 |
24 | var parser = new TombLangCompiler();
25 | var contract = parser.Process(sourceCode).First();
26 |
27 | var storage = new Dictionary(new ByteArrayComparer());
28 |
29 | TestVM vm;
30 |
31 | var keys = PhantasmaKeys.Generate();
32 |
33 | // call returnType
34 | var returnType = contract.abi.FindMethod("returnType");
35 | Assert.IsNotNull(returnType);
36 |
37 | vm = new TestVM(contract, storage, returnType);
38 | var result = vm.Execute();
39 | Assert.IsTrue(result == ExecutionState.Halt);
40 |
41 | Assert.IsTrue(storage.Count == 0);
42 |
43 | Assert.IsTrue(vm.Stack.Count == 1);
44 |
45 | var obj = vm.Stack.Pop();
46 | var vmType = obj.AsEnum();
47 |
48 | Assert.IsTrue(vmType == VMType.String);
49 | }
50 |
51 | [Test]
52 | public void TypeInferenceInVarDecls()
53 | {
54 | var sourceCode =
55 | @"
56 | contract test{
57 | public calculate():string {
58 | local a = ""hello "";
59 | local b = ""world"";
60 | return a + b;
61 | }
62 | }";
63 |
64 | var parser = new TombLangCompiler();
65 | var contract = parser.Process(sourceCode).First();
66 |
67 | var storage = new Dictionary(new ByteArrayComparer());
68 |
69 | TestVM vm;
70 |
71 | var method = contract.abi.FindMethod("calculate");
72 | Assert.IsNotNull(method);
73 |
74 | vm = new TestVM(contract, storage, method);
75 | var result = vm.Execute();
76 | Assert.IsTrue(result == ExecutionState.Halt);
77 |
78 | Assert.IsTrue(vm.Stack.Count == 1);
79 |
80 | var obj = vm.Stack.Pop();
81 | var str = obj.AsString();
82 |
83 | Assert.IsTrue(str == "hello world");
84 | }
85 | }
--------------------------------------------------------------------------------
/Library/src/AST/Statements/ReturnStatement.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST.Declarations;
2 | using Phantasma.Tomb.CodeGen;
3 | using System;
4 | using System.Linq.Expressions;
5 |
6 | namespace Phantasma.Tomb.AST.Statements
7 | {
8 | public class ReturnStatement : Statement
9 | {
10 | public Expression expression;
11 |
12 | public MethodDeclaration method;
13 |
14 | public ReturnStatement(MethodDeclaration method, Expression expression) : base()
15 | {
16 | this.expression = expression;
17 | this.method = method;
18 | }
19 |
20 | public override void Visit(Action callback)
21 | {
22 | callback(this);
23 | expression?.Visit(callback);
24 | }
25 |
26 | public override bool IsNodeUsed(Node node)
27 | {
28 | return (node == this) || (expression != null && expression.IsNodeUsed(node));
29 | }
30 |
31 | public override void GenerateCode(CodeGenerator output)
32 | {
33 | var returnType = this.method.@interface.ReturnType;
34 |
35 | var simpleReturn = (this.method.ParentScope.Module is Script);
36 | var isMulti = this.method.@interface.IsMulti;
37 |
38 | if (expression != null)
39 | {
40 | if (returnType.Kind == VarKind.None)
41 | {
42 | throw new System.Exception($"unexpect return expression for void method: {method.Name}");
43 | }
44 |
45 | this.expression = Expression.AutoCast(expression, returnType);
46 |
47 | var reg = this.expression.GenerateCode(output);
48 | output.AppendLine(this, $"PUSH {reg}");
49 | Compiler.Instance.DeallocRegister(ref reg);
50 | }
51 | else
52 | if (returnType.Kind != VarKind.None && !isMulti)
53 | {
54 | throw new System.Exception($"expected return expression for non-void method: {method.Name}");
55 | }
56 |
57 | if (isMulti && expression != null)
58 | {
59 | return; // for multi methods a return with expression is basically just a push, nothing more..
60 | }
61 |
62 | if (simpleReturn)
63 | {
64 | output.AppendLine(this, "RET");
65 | }
66 | else
67 | {
68 | output.AppendLine(this, "JMP @" + this.method.GetExitLabel());
69 | }
70 | }
71 | }
72 |
73 | }
74 |
75 |
--------------------------------------------------------------------------------
/Library/src/CodeGen/CodeGenerator.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST;
2 | using System.Text;
3 | using System.Collections.Generic;
4 |
5 | namespace Phantasma.Tomb.CodeGen
6 | {
7 | public class CodeGenerator
8 | {
9 | private StringBuilder _sb = new StringBuilder();
10 | private StringBuilder _includedBuiltinCodeBuffer = new StringBuilder(); // used for builtins
11 |
12 | public static Scope currentScope = null;
13 | public static int currentSourceLine = 0;
14 |
15 | public int LineCount;
16 |
17 | private Dictionary _builtinMethodMap = new Dictionary();
18 |
19 | public CodeGenerator()
20 | {
21 | }
22 |
23 | public static string Tabs(int n)
24 | {
25 | return new string('\t', n);
26 | }
27 |
28 | public void AppendLine(Node node, string line = "")
29 | {
30 | if (node.LineNumber <= 0)
31 | {
32 | throw new CompilerException("line number failed for " + node.GetType().Name);
33 | }
34 |
35 | while (currentSourceLine <= node.LineNumber)
36 | {
37 | if (currentSourceLine > 0)
38 | {
39 | var lineContent = Compiler.Instance.GetLine(currentSourceLine);
40 | _sb.AppendLine($"// Line {currentSourceLine}:" + lineContent);
41 | LineCount++;
42 | }
43 | currentSourceLine++;
44 | }
45 |
46 | line = Tabs(currentScope.Level) + line;
47 | _sb.AppendLine(line);
48 | LineCount++;
49 | }
50 |
51 | public void IncBuiltinReference(string builtinMethodName)
52 | {
53 | if (_builtinMethodMap.ContainsKey(builtinMethodName))
54 | {
55 | return;
56 | }
57 |
58 | var builtin = Builtins.GetMethod(builtinMethodName);
59 | var code = builtin.Code;
60 |
61 | _builtinMethodMap[builtinMethodName] = code;
62 |
63 | if (_includedBuiltinCodeBuffer.Length == 0)
64 | {
65 | _includedBuiltinCodeBuffer.AppendLine();
66 | _includedBuiltinCodeBuffer.AppendLine("// =======> BUILTINS SECTION");
67 | }
68 |
69 | _includedBuiltinCodeBuffer.Append(code);
70 | }
71 |
72 | public override string ToString()
73 | {
74 | return _sb.ToString() + _includedBuiltinCodeBuffer.ToString();
75 | }
76 |
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Library/tests/Contracts/VariableTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Domain.Execution.Enums;
7 | using Phantasma.Core.Domain.VM.Enums;
8 | using Phantasma.Core.Utils;
9 | using Phantasma.Tomb.Compilers;
10 |
11 | namespace TOMBLib.Tests.Contracts;
12 |
13 | public class VariableTests
14 | {
15 | [Test]
16 | public void TypeOf()
17 | {
18 | var sourceCode = new string[]
19 | {
20 | "contract test{",
21 | "public returnType() : type {",
22 | "return $TYPE_OF(string);",
23 | "}}"
24 | };
25 |
26 | var parser = new TombLangCompiler();
27 | var contract = parser.Process(sourceCode).First();
28 |
29 | var storage = new Dictionary(new ByteArrayComparer());
30 |
31 | TestVM vm;
32 |
33 | var keys = PhantasmaKeys.Generate();
34 |
35 | // call returnType
36 | var returnType = contract.abi.FindMethod("returnType");
37 | Assert.IsNotNull(returnType);
38 |
39 | vm = new TestVM(contract, storage, returnType);
40 | var result = vm.Execute();
41 | Assert.IsTrue(result == ExecutionState.Halt);
42 |
43 | Assert.IsTrue(storage.Count == 0);
44 |
45 | Assert.IsTrue(vm.Stack.Count == 1);
46 |
47 | var obj = vm.Stack.Pop();
48 | var vmType = obj.AsEnum();
49 |
50 | Assert.IsTrue(vmType == VMType.String);
51 | }
52 |
53 | [Test]
54 | public void TypeInferenceInVarDecls()
55 | {
56 | var sourceCode =
57 | @"
58 | contract test{
59 | public calculate():string {
60 | local a = ""hello "";
61 | local b = ""world"";
62 | return a + b;
63 | }
64 | }";
65 |
66 | var parser = new TombLangCompiler();
67 | var contract = parser.Process(sourceCode).First();
68 |
69 | var storage = new Dictionary(new ByteArrayComparer());
70 |
71 | TestVM vm;
72 |
73 | var method = contract.abi.FindMethod("calculate");
74 | Assert.IsNotNull(method);
75 |
76 | vm = new TestVM(contract, storage, method);
77 | var result = vm.Execute();
78 | Assert.IsTrue(result == ExecutionState.Halt);
79 |
80 | Assert.IsTrue(vm.Stack.Count == 1);
81 |
82 | var obj = vm.Stack.Pop();
83 | var str = obj.AsString();
84 |
85 | Assert.IsTrue(str == "hello world");
86 | }
87 | }
--------------------------------------------------------------------------------
/Tests/AST/Declaration/EnumDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NUnit.Framework;
4 | using Phantasma.Tomb;
5 | using Phantasma.Tomb.AST.Declarations;
6 | using Phantasma.Tomb.Lexers;
7 |
8 | namespace Tests.AST.Declaration;
9 |
10 | public class EnumDeclarationTests
11 | {
12 | [SetUp]
13 | public void Setup()
14 | {
15 | TombLangLexer lexer = new TombLangLexer();
16 | }
17 |
18 | [Test]
19 | public void Constructor_WithDuplicateEntryName_ThrowsCompilerException()
20 | {
21 | // Arrange
22 | var entries = new List()
23 | {
24 | new EnumEntry("Red", 1),
25 | new EnumEntry("Green", 2),
26 | new EnumEntry("Red", 3)
27 | };
28 |
29 | // Act & Assert
30 | Assert.Throws(() => new EnumDeclaration("Colors", entries));
31 | }
32 |
33 | [Test]
34 | public void Constructor_WithValidEntries_CreatesEntryNamesDictionary()
35 | {
36 | // Arrange
37 | var entries = new List()
38 | {
39 | new EnumEntry("Red", 1),
40 | new EnumEntry("Green", 2),
41 | new EnumEntry("Blue", 3)
42 | };
43 |
44 | // Act
45 | var enumDeclaration = new EnumDeclaration("Colors", entries);
46 |
47 |
48 | // Assert
49 | Assert.That(enumDeclaration.entryNames, Is.Not.Null);
50 | Assert.That(enumDeclaration.entryNames.Count, Is.EqualTo(entries.Count));
51 | foreach (var entry in entries)
52 | {
53 | Assert.That(enumDeclaration.entryNames.ContainsKey(entry.name), Is.True);
54 | Assert.That(enumDeclaration.entryNames[entry.name], Is.EqualTo(entry.value));
55 | }
56 | }
57 |
58 | [Test]
59 | public void IsNodeUsed_WithSameNode_ReturnsTrue()
60 | {
61 | // Arrange
62 | var enumDeclaration = new EnumDeclaration("Colors", new List());
63 |
64 | // Act
65 | var isUsed = enumDeclaration.IsNodeUsed(enumDeclaration);
66 |
67 | // Assert
68 | Assert.That(isUsed, Is.True);
69 | }
70 |
71 | [Test]
72 | public void Visit_WithCallback_CallsCallbackWithThisNode()
73 | {
74 | // Arrange
75 | var enumDeclaration = new EnumDeclaration("Colors", new List());
76 | bool isCallbackCalled = false;
77 |
78 | // Act
79 | enumDeclaration.Visit(node => isCallbackCalled = (node == enumDeclaration));
80 |
81 | // Assert
82 | Assert.That(isCallbackCalled, Is.True);
83 | }
84 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Declaration/EnumDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NUnit.Framework;
4 | using Phantasma.Tomb;
5 | using Phantasma.Tomb.AST.Declarations;
6 | using Phantasma.Tomb.Lexers;
7 |
8 | namespace TOMBLib.Tests.AST.Declaration;
9 |
10 | public class EnumDeclarationTests
11 | {
12 | [SetUp]
13 | public void Setup()
14 | {
15 | TombLangLexer lexer = new TombLangLexer();
16 | }
17 |
18 | [Test]
19 | public void Constructor_WithDuplicateEntryName_ThrowsCompilerException()
20 | {
21 | // Arrange
22 | var entries = new List()
23 | {
24 | new EnumEntry("Red", 1),
25 | new EnumEntry("Green", 2),
26 | new EnumEntry("Red", 3)
27 | };
28 |
29 | // Act & Assert
30 | Assert.Throws(() => new EnumDeclaration("Colors", entries));
31 | }
32 |
33 | [Test]
34 | public void Constructor_WithValidEntries_CreatesEntryNamesDictionary()
35 | {
36 | // Arrange
37 | var entries = new List()
38 | {
39 | new EnumEntry("Red", 1),
40 | new EnumEntry("Green", 2),
41 | new EnumEntry("Blue", 3)
42 | };
43 |
44 | // Act
45 | var enumDeclaration = new EnumDeclaration("Colors", entries);
46 |
47 |
48 | // Assert
49 | Assert.That(enumDeclaration.entryNames, Is.Not.Null);
50 | Assert.That(enumDeclaration.entryNames.Count, Is.EqualTo(entries.Count));
51 | foreach (var entry in entries)
52 | {
53 | Assert.That(enumDeclaration.entryNames.ContainsKey(entry.name), Is.True);
54 | Assert.That(enumDeclaration.entryNames[entry.name], Is.EqualTo(entry.value));
55 | }
56 | }
57 |
58 | [Test]
59 | public void IsNodeUsed_WithSameNode_ReturnsTrue()
60 | {
61 | // Arrange
62 | var enumDeclaration = new EnumDeclaration("Colors", new List());
63 |
64 | // Act
65 | var isUsed = enumDeclaration.IsNodeUsed(enumDeclaration);
66 |
67 | // Assert
68 | Assert.That(isUsed, Is.True);
69 | }
70 |
71 | [Test]
72 | public void Visit_WithCallback_CallsCallbackWithThisNode()
73 | {
74 | // Arrange
75 | var enumDeclaration = new EnumDeclaration("Colors", new List());
76 | bool isCallbackCalled = false;
77 |
78 | // Act
79 | enumDeclaration.Visit(node => isCallbackCalled = (node == enumDeclaration));
80 |
81 | // Assert
82 | Assert.That(isCallbackCalled, Is.True);
83 | }
84 | }
--------------------------------------------------------------------------------
/Samples/basic_token.sol:
--------------------------------------------------------------------------------
1 | /*
2 | Sample implementation of a pseudo-ERC20 token in Phantasma.
3 | Note that this contract is not compatible with normal Phantasma tokens yet (some details missing, TODO)
4 | */
5 |
6 | pragma solidity ^0.4.19;
7 |
8 | import "Phantasma/Runtime.tomb";
9 |
10 | contract ERC20Basic {
11 |
12 | string public constant name = "ERC20Basic";
13 | string public constant symbol = "BSC";
14 | uint8 public constant decimals = 18;
15 |
16 | // NOTE there is no need for a Phantsama token to emit those as they are automatically emmited
17 | //event Transfer(address indexed from, address indexed to, uint tokens);
18 | //event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
19 |
20 |
21 | mapping(address => uint256) balances;
22 |
23 | //mapping(address => mapping (address => uint256)) allowed;
24 |
25 | uint256 totalSupply_;
26 |
27 | constructor(address owner) public {
28 | totalSupply_ = 10000000000;
29 | balances[owner] = totalSupply_;
30 | }
31 |
32 | function totalSupply() public view returns (uint256) {
33 | return totalSupply_;
34 | }
35 |
36 | function balanceOf(address tokenOwner) public view returns (uint) {
37 | return balances[tokenOwner];
38 | }
39 |
40 | function transfer(address sender, address receiver, uint numTokens) public returns (bool) {
41 | require(Runtime.isWitness(sender));
42 | require(numTokens <= balances[sender]);
43 | balances[sender] = balances[sender] - numTokens;
44 | balances[receiver] = balances[receiver] + numTokens;
45 | //emit Transfer(msg.sender, receiver, numTokens);
46 | return true;
47 | }
48 |
49 | /* NOTE the approve/allowance of ERC20 does not apply to Phantasma tokens
50 |
51 | function approve(address delegate, uint numTokens) public returns (bool) {
52 | allowed[msg.sender][delegate] = numTokens;
53 | //emit Approval(msg.sender, delegate, numTokens);
54 | return true;
55 | }
56 |
57 | function allowance(address owner, address delegate) public view returns (uint) {
58 | return allowed[owner][delegate];
59 | }
60 |
61 | function transferFrom(address owner, address buyer, uint numTokens) public returns (bool) {
62 | require(numTokens <= balances[owner]);
63 | require(numTokens <= allowed[owner][msg.sender]);
64 |
65 | balances[owner] = balances[owner].sub(numTokens);
66 | allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);
67 | balances[buyer] = balances[buyer].add(numTokens);
68 | //emit Transfer(owner, buyer, numTokens);
69 | return true;
70 | }*/
71 | }
72 |
--------------------------------------------------------------------------------
/Library/src/CodeGen/NFT.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Phantasma.Business.Blockchain.Tokens;
3 | using Phantasma.Core.Domain;
4 | using Phantasma.Core.Domain.Contract;
5 | using Phantasma.Core.Domain.Contract.Structs;
6 | using Phantasma.Core.Domain.VM.Enums;
7 | using Phantasma.Tomb.AST;
8 | using Phantasma.Tomb.AST.Declarations;
9 |
10 | namespace Phantasma.Tomb.CodeGen
11 | {
12 | public class NFT : Contract
13 | {
14 | public VarType romType;
15 | public VarType ramType;
16 |
17 | public StructVarType nftType;
18 |
19 | public NFT(string name, VarType romType, VarType ramType, Module parent) : base(name, ModuleKind.NFT, parent)
20 | {
21 | this.romType = romType;
22 | this.ramType = ramType;
23 |
24 | this.nftType = (StructVarType)VarType.Find(VarKind.Struct, name);
25 | //this.nftType.decl = new StructDeclaration(name, new[] { new StructField("id", VarKind.Number), new StructField("owner", VarKind.Address), new StructField("chain", VarKind.String), new StructField("rom", romType), new StructField("ram", ramType) });
26 |
27 | this.Scope.AddVariable(new VarDeclaration(this.Scope, "_tokenID", VarType.Find(VarKind.Number), VarStorage.NFT));
28 | this.Scope.AddVariable(new VarDeclaration(this.Scope, "_seriesID", VarType.Find(VarKind.Number), VarStorage.NFT));
29 | this.Scope.AddVariable(new VarDeclaration(this.Scope, "_mintID", VarType.Find(VarKind.Number), VarStorage.NFT));
30 | this.Scope.AddVariable(new VarDeclaration(this.Scope, "_ROM", romType, VarStorage.NFT));
31 | this.Scope.AddVariable(new VarDeclaration(this.Scope, "_RAM", ramType, VarStorage.NFT));
32 | }
33 |
34 | public override ContractInterface GenerateCode(CodeGenerator output)
35 | {
36 | var abi = base.GenerateCode(output);
37 |
38 | var nftStandard = TokenUtils.GetNFTStandard();
39 |
40 | // convert ABI parameters
41 | var methods = new List();
42 | foreach (var method in abi.Methods)
43 | {
44 | if (nftStandard.HasMethod(method.name))
45 | {
46 | var convertedMethod = new ContractMethod(method.name, method.returnType, method.offset, new[] { new ContractParameter("tokenID", VMType.Number) });
47 | methods.Add(convertedMethod);
48 | }
49 | else
50 | {
51 | methods.Add(method);
52 | }
53 | }
54 |
55 | abi = new ContractInterface(methods, abi.Events);
56 | return abi;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Library/tests/AST/Declaration/VarDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.AST;
2 | using Phantasma.Tomb.AST.Declarations;
3 | using Phantasma.Tomb.Lexers;
4 |
5 | namespace TOMBLib.Tests.AST.Declaration;
6 |
7 | public class VarDeclarationTests
8 | {
9 | [SetUp]
10 | public void Setup()
11 | {
12 | TombLangLexer lexer = new TombLangLexer();
13 | }
14 |
15 | [Test]
16 | public void Constructor_WithValidArguments_SetsPropertiesCorrectly()
17 | {
18 | // Arrange
19 | Scope parentScope = null;
20 | var name = "myVar";
21 | var type = VarType.Find(VarKind.Any);
22 | var storage = VarStorage.Global;
23 |
24 | // Act
25 | var varDeclaration = new VarDeclaration(parentScope, name, type, storage);
26 |
27 | // Assert
28 | Assert.That(varDeclaration.ParentScope, Is.EqualTo(parentScope));
29 | Assert.That(varDeclaration.Name, Is.EqualTo(name));
30 | Assert.That(varDeclaration.Type, Is.EqualTo(type));
31 | Assert.That(varDeclaration.Storage, Is.EqualTo(storage));
32 | Assert.That(varDeclaration.Register, Is.Null);
33 | }
34 |
35 | [Test]
36 | public void ToString_WithValidVarDeclaration_ReturnsExpectedString()
37 | {
38 | // Arrange
39 | Scope parentScope = null;
40 | var name = "myVar";
41 | var type = VarType.Find(VarKind.Bool);
42 | var storage = VarStorage.Local;
43 | var varDeclaration = new VarDeclaration(parentScope, name, type, storage);
44 |
45 | // Act
46 | var result = varDeclaration.ToString();
47 |
48 | // Assert
49 | Assert.That(result, Is.EqualTo("var myVar:Bool"));
50 | }
51 |
52 | [Test]
53 | public void Visit_WithCallback_CallsCallbackWithThisNode()
54 | {
55 | // Arrange
56 | Scope parentScope = null;
57 | var name = "myVar";
58 | var type = VarType.Find(VarKind.Decimal, 2);
59 | var storage = VarStorage.Register;
60 | var varDeclaration = new VarDeclaration(parentScope, name, type, storage);
61 | bool isCallbackCalled = false;
62 |
63 | // Act
64 | varDeclaration.Visit(node => isCallbackCalled = (node == varDeclaration));
65 |
66 | // Assert
67 | Assert.That(isCallbackCalled, Is.True);
68 | }
69 |
70 | [Test]
71 | public void IsNodeUsed_WithSameNode_ReturnsTrue()
72 | {
73 | // Arrange
74 | Scope parentScope = null;
75 | var name = "myVar";
76 | var type = VarType.Find(VarKind.String);
77 | var storage = VarStorage.Global;
78 | var varDeclaration = new VarDeclaration(parentScope, name, type, storage);
79 |
80 | // Act
81 | var isUsed = varDeclaration.IsNodeUsed(varDeclaration);
82 |
83 | // Assert
84 | Assert.That(isUsed, Is.True);
85 | }
86 | }
--------------------------------------------------------------------------------
/Tests/AST/Declaration/VarDeclarationTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.AST;
3 | using Phantasma.Tomb.AST.Declarations;
4 | using Phantasma.Tomb.Lexers;
5 |
6 | namespace Tests.AST.Declaration;
7 |
8 | public class VarDeclarationTests
9 | {
10 | [SetUp]
11 | public void Setup()
12 | {
13 | TombLangLexer lexer = new TombLangLexer();
14 | }
15 |
16 | [Test]
17 | public void Constructor_WithValidArguments_SetsPropertiesCorrectly()
18 | {
19 | // Arrange
20 | Scope parentScope = null;
21 | var name = "myVar";
22 | var type = VarType.Find(VarKind.Any);
23 | var storage = VarStorage.Global;
24 |
25 | // Act
26 | var varDeclaration = new VarDeclaration(parentScope, name, type, storage);
27 |
28 | // Assert
29 | Assert.That(varDeclaration.ParentScope, Is.EqualTo(parentScope));
30 | Assert.That(varDeclaration.Name, Is.EqualTo(name));
31 | Assert.That(varDeclaration.Type, Is.EqualTo(type));
32 | Assert.That(varDeclaration.Storage, Is.EqualTo(storage));
33 | Assert.That(varDeclaration.Register, Is.Null);
34 | }
35 |
36 | [Test]
37 | public void ToString_WithValidVarDeclaration_ReturnsExpectedString()
38 | {
39 | // Arrange
40 | Scope parentScope = null;
41 | var name = "myVar";
42 | var type = VarType.Find(VarKind.Bool);
43 | var storage = VarStorage.Local;
44 | var varDeclaration = new VarDeclaration(parentScope, name, type, storage);
45 |
46 | // Act
47 | var result = varDeclaration.ToString();
48 |
49 | // Assert
50 | Assert.That(result, Is.EqualTo("var myVar:Bool"));
51 | }
52 |
53 | [Test]
54 | public void Visit_WithCallback_CallsCallbackWithThisNode()
55 | {
56 | // Arrange
57 | Scope parentScope = null;
58 | var name = "myVar";
59 | var type = VarType.Find(VarKind.Decimal, 2);
60 | var storage = VarStorage.Register;
61 | var varDeclaration = new VarDeclaration(parentScope, name, type, storage);
62 | bool isCallbackCalled = false;
63 |
64 | // Act
65 | varDeclaration.Visit(node => isCallbackCalled = (node == varDeclaration));
66 |
67 | // Assert
68 | Assert.That(isCallbackCalled, Is.True);
69 | }
70 |
71 | [Test]
72 | public void IsNodeUsed_WithSameNode_ReturnsTrue()
73 | {
74 | // Arrange
75 | Scope parentScope = null;
76 | var name = "myVar";
77 | var type = VarType.Find(VarKind.String);
78 | var storage = VarStorage.Global;
79 | var varDeclaration = new VarDeclaration(parentScope, name, type, storage);
80 |
81 | // Act
82 | var isUsed = varDeclaration.IsNodeUsed(varDeclaration);
83 |
84 | // Assert
85 | Assert.That(isUsed, Is.True);
86 | }
87 | }
--------------------------------------------------------------------------------
/Compiler/builtins.tomb:
--------------------------------------------------------------------------------
1 | contract builtins {
2 | import Array;
3 | import Runtime;
4 | import Storage;
5 |
6 | private tomb_math_sqrt(n:number) : number {
7 | local root:number = n / 2;
8 | while (n < root * root) {
9 | root += n / root;
10 | root /= 2;
11 | }
12 |
13 | return root;
14 | }
15 |
16 | private tomb_string_toUpper(s:string):string
17 | {
18 | local my_array: array;
19 |
20 | // extract chars from string into an array
21 | my_array = s.toArray();
22 |
23 | local length :number = Array.length(my_array);
24 | local idx :number = 0;
25 |
26 | while (idx < length) {
27 | local ch : number = my_array[idx];
28 |
29 | if (ch >= 97) {
30 | if (ch <= 122) {
31 | my_array[idx] = ch - 32;
32 | }
33 | }
34 |
35 | idx += 1;
36 | }
37 |
38 | // convert the array back into a unicode string
39 | local result:string = String.fromArray(my_array);
40 | return result;
41 | }
42 |
43 | private tomb_string_toLower(s:string):string
44 | {
45 | local my_array: array;
46 |
47 | // extract chars from string into an array
48 | my_array = s.toArray();
49 |
50 | local length :number = Array.length(my_array);
51 | local idx :number = 0;
52 |
53 | while (idx < length) {
54 | local ch : number = my_array[idx];
55 |
56 | if (ch >= 65) {
57 | if (ch <= 90) {
58 | my_array[idx] = ch + 32;
59 | }
60 | }
61 |
62 | idx += 1;
63 | }
64 |
65 | // convert the array back into a unicode string
66 | local result:string = String.fromArray(my_array);
67 | return result;
68 | }
69 |
70 |
71 | private tomb_string_indexOf(s:string, x:number):number
72 | {
73 | local my_array: array;
74 |
75 | // extract chars from string into an array
76 | my_array = s.toArray();
77 |
78 | local length :number = Array.length(my_array);
79 | local idx :number = 0;
80 |
81 | while (idx < length) {
82 | local ch : number = my_array[idx];
83 |
84 | if (ch == x) {
85 | // found, return index
86 | return idx;
87 | }
88 |
89 | idx += 1;
90 | }
91 |
92 | return -1; // not found
93 | }
94 |
95 | const RND_A:number = 16807;
96 | const RND_M:number = 2147483647;
97 | const RND_SEED_KEY:string = "tomb_rnd_seed";
98 |
99 | private tomb_random_seed(seed:number)
100 | {
101 | Storage.write(RND_SEED_KEY, seed);
102 | }
103 |
104 | private tomb_random_generate(): number
105 | {
106 | local seed: number;
107 | local context:string = Runtime.context();
108 | seed = Storage.read(context, RND_SEED_KEY);
109 | seed = (RND_A * seed) % RND_M;
110 | Storage.write(RND_SEED_KEY, seed);
111 | return seed;
112 | }
113 | }
--------------------------------------------------------------------------------
/Tests/Contracts/IfTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Utils;
6 | using Phantasma.Tomb.Compilers;
7 |
8 | namespace Tests.Contracts;
9 |
10 | public class IfTests
11 | {
12 | [Test]
13 | public void IfChained()
14 | {
15 | var sourceCode =
16 | @"
17 | contract test {
18 | public sign(x:number): number {
19 | if (x > 0)
20 | {
21 | return 1;
22 | }
23 | else
24 | if (x < 0)
25 | {
26 | return -1;
27 | }
28 | else
29 | {
30 | return 0;
31 | }
32 | }
33 | }";
34 |
35 | var parser = new TombLangCompiler();
36 | var contract = parser.Process(sourceCode).First();
37 |
38 | var storage = new Dictionary(new ByteArrayComparer());
39 |
40 | var countStuff = contract.abi.FindMethod("sign");
41 | Assert.IsNotNull(countStuff);
42 |
43 | var vm = new TestVM(contract, storage, countStuff);
44 | vm.Stack.Push(VMObject.FromObject(-3));
45 | var result = vm.Execute();
46 | Assert.IsTrue(result == ExecutionState.Halt);
47 |
48 | Assert.IsTrue(vm.Stack.Count == 1);
49 | var val = vm.Stack.Pop().AsNumber();
50 | Assert.IsTrue(val == -1);
51 | }
52 |
53 | [Test]
54 | public void IfWithOr()
55 | {
56 | var sourceCode =
57 | @"
58 | contract test {
59 | public check(x:number, y:number): bool {
60 | return (x > 0) && (y < 0);
61 | }
62 | }";
63 |
64 | var parser = new TombLangCompiler();
65 | var contract = parser.Process(sourceCode).First();
66 |
67 | var storage = new Dictionary(new ByteArrayComparer());
68 |
69 | var countStuff = contract.abi.FindMethod("check");
70 | Assert.IsNotNull(countStuff);
71 |
72 | var vm = new TestVM(contract, storage, countStuff);
73 | // NOTE - due to using a stack, we're pushing the second argument first (y), then the first argument (y)
74 | vm.Stack.Push(VMObject.FromObject(-3));
75 | vm.Stack.Push(VMObject.FromObject(3));
76 | var result = vm.Execute();
77 | Assert.IsTrue(result == ExecutionState.Halt);
78 |
79 | Assert.IsTrue(vm.Stack.Count == 1);
80 | var val = vm.Stack.Pop().AsBool();
81 | Assert.IsTrue(val);
82 |
83 | vm = new TestVM(contract, storage, countStuff);
84 | // NOTE - here we invert the order, in this case should fail due to the condition in the contract inside check()
85 | vm.Stack.Push(VMObject.FromObject(3));
86 | vm.Stack.Push(VMObject.FromObject(-3));
87 | result = vm.Execute();
88 | Assert.IsTrue(result == ExecutionState.Halt);
89 |
90 | Assert.IsTrue(vm.Stack.Count == 1);
91 | val = vm.Stack.Pop().AsBool();
92 | Assert.IsFalse(val);
93 | }
94 | }
--------------------------------------------------------------------------------
/Library/tests/Contracts/IfTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Domain.Execution.Enums;
6 | using Phantasma.Core.Domain.VM;
7 | using Phantasma.Core.Utils;
8 | using Phantasma.Tomb.Compilers;
9 |
10 | namespace TOMBLib.Tests.Contracts;
11 |
12 | public class IfTests
13 | {
14 | [Test]
15 | public void IfChained()
16 | {
17 | var sourceCode =
18 | @"
19 | contract test {
20 | public sign(x:number): number {
21 | if (x > 0)
22 | {
23 | return 1;
24 | }
25 | else
26 | if (x < 0)
27 | {
28 | return -1;
29 | }
30 | else
31 | {
32 | return 0;
33 | }
34 | }
35 | }";
36 |
37 | var parser = new TombLangCompiler();
38 | var contract = parser.Process(sourceCode).First();
39 |
40 | var storage = new Dictionary(new ByteArrayComparer());
41 |
42 | var countStuff = contract.abi.FindMethod("sign");
43 | Assert.IsNotNull(countStuff);
44 |
45 | var vm = new TestVM(contract, storage, countStuff);
46 | vm.Stack.Push(VMObject.FromObject(-3));
47 | var result = vm.Execute();
48 | Assert.IsTrue(result == ExecutionState.Halt);
49 |
50 | Assert.IsTrue(vm.Stack.Count == 1);
51 | var val = vm.Stack.Pop().AsNumber();
52 | Assert.IsTrue(val == -1);
53 | }
54 |
55 | [Test]
56 | public void IfWithOr()
57 | {
58 | var sourceCode =
59 | @"
60 | contract test {
61 | public check(x:number, y:number): bool {
62 | return (x > 0) && (y < 0);
63 | }
64 | }";
65 |
66 | var parser = new TombLangCompiler();
67 | var contract = parser.Process(sourceCode).First();
68 |
69 | var storage = new Dictionary(new ByteArrayComparer());
70 |
71 | var countStuff = contract.abi.FindMethod("check");
72 | Assert.IsNotNull(countStuff);
73 |
74 | var vm = new TestVM(contract, storage, countStuff);
75 | // NOTE - due to using a stack, we're pushing the second argument first (y), then the first argument (y)
76 | vm.Stack.Push(VMObject.FromObject(-3));
77 | vm.Stack.Push(VMObject.FromObject(3));
78 | var result = vm.Execute();
79 | Assert.IsTrue(result == ExecutionState.Halt);
80 |
81 | Assert.IsTrue(vm.Stack.Count == 1);
82 | var val = vm.Stack.Pop().AsBool();
83 | Assert.IsTrue(val);
84 |
85 | vm = new TestVM(contract, storage, countStuff);
86 | // NOTE - here we invert the order, in this case should fail due to the condition in the contract inside check()
87 | vm.Stack.Push(VMObject.FromObject(3));
88 | vm.Stack.Push(VMObject.FromObject(-3));
89 | result = vm.Execute();
90 | Assert.IsTrue(result == ExecutionState.Halt);
91 |
92 | Assert.IsTrue(vm.Stack.Count == 1);
93 | val = vm.Stack.Pop().AsBool();
94 | Assert.IsFalse(val);
95 | }
96 | }
--------------------------------------------------------------------------------
/Library/tests/CodeGen/CodeGeneratorTests.cs:
--------------------------------------------------------------------------------
1 | namespace TOMBLib.Tests.CodeGen;
2 |
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using NUnit.Framework;
6 | using Phantasma.Core.Cryptography.Structs;
7 | using Phantasma.Core.Domain;
8 | using Phantasma.Core.Domain.Execution.Enums;
9 | using Phantasma.Core.Domain.VM;
10 | using Phantasma.Core.Utils;
11 | using Phantasma.Tomb.Compilers;
12 |
13 | public class CodeGeneratorTests
14 | {
15 | [Test]
16 | public void AutoCasts()
17 | {
18 | var sourceCode =
19 | @"
20 | contract test {
21 | import Address;
22 |
23 | public castTest(x:address): string {
24 | return Address.toString(x);
25 | }
26 | }";
27 |
28 | var parser = new TombLangCompiler();
29 | var contract = parser.Process(sourceCode).First();
30 |
31 | var storage = new Dictionary(new ByteArrayComparer());
32 |
33 | var cast = contract.abi.FindMethod("castTest");
34 | Assert.IsNotNull(cast);
35 |
36 | var expected = "P2K7GyVMC3f9XxKRji5gfg91WvutoHs2RyB6KzQxuaAUUeo";
37 | var addr = Address.FromText(expected);
38 |
39 | var vm = new TestVM(contract, storage, cast);
40 | vm.Stack.Push(VMObject.FromObject(addr));
41 | var result = vm.Execute();
42 | Assert.IsTrue(result == ExecutionState.Halt);
43 |
44 | Assert.IsTrue(vm.Stack.Count == 1);
45 | var val = vm.Stack.Pop().AsString();
46 | Assert.IsTrue(val == expected);
47 | }
48 |
49 | [Test]
50 | public void IfWithOr()
51 | {
52 | var sourceCode =
53 | @"
54 | contract test {
55 | public check(x:number, y:number): bool {
56 | return (x > 0) && (y < 0);
57 | }
58 | }";
59 |
60 | var parser = new TombLangCompiler();
61 | var contract = parser.Process(sourceCode).First();
62 |
63 | var storage = new Dictionary(new ByteArrayComparer());
64 |
65 | var countStuff = contract.abi.FindMethod("check");
66 | Assert.IsNotNull(countStuff);
67 |
68 | var vm = new TestVM(contract, storage, countStuff);
69 | // NOTE - due to using a stack, we're pushing the second argument first (y), then the first argument (y)
70 | vm.Stack.Push(VMObject.FromObject(-3));
71 | vm.Stack.Push(VMObject.FromObject(3));
72 | var result = vm.Execute();
73 | Assert.IsTrue(result == ExecutionState.Halt);
74 |
75 | Assert.IsTrue(vm.Stack.Count == 1);
76 | var val = vm.Stack.Pop().AsBool();
77 | Assert.IsTrue(val);
78 |
79 | vm = new TestVM(contract, storage, countStuff);
80 | // NOTE - here we invert the order, in this case should fail due to the condition in the contract inside check()
81 | vm.Stack.Push(VMObject.FromObject(3));
82 | vm.Stack.Push(VMObject.FromObject(-3));
83 | result = vm.Execute();
84 | Assert.IsTrue(result == ExecutionState.Halt);
85 |
86 | Assert.IsTrue(vm.Stack.Count == 1);
87 | val = vm.Stack.Pop().AsBool();
88 | Assert.IsFalse(val);
89 | }
90 | }
--------------------------------------------------------------------------------
/Library/src/AST/Expressions/CastExpression.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Tomb.CodeGen;
2 |
3 | using System;
4 |
5 | namespace Phantasma.Tomb.AST.Expressions
6 | {
7 | public class CastExpression : Expression
8 | {
9 | public Expression expr;
10 |
11 | public override VarType ResultType { get; }
12 |
13 | public CastExpression(Scope parentScope, VarType resultType, Expression expr) : base(parentScope)
14 | {
15 | this.expr = expr;
16 | this.ResultType = resultType;
17 | }
18 |
19 | public override Register GenerateCode(CodeGenerator output)
20 | {
21 | var reg = expr.GenerateCode(output);
22 |
23 | switch (expr.ResultType.Kind)
24 | {
25 | case VarKind.Decimal:
26 | {
27 | switch (this.ResultType.Kind)
28 | {
29 | case VarKind.Number:
30 | return reg;
31 |
32 | case VarKind.Decimal:
33 | {
34 | var srcDecimals = ((DecimalVarType)expr.ResultType).decimals;
35 | var dstDecimals = ((DecimalVarType)this.ResultType).decimals;
36 |
37 | if (srcDecimals == dstDecimals)
38 | {
39 | return reg;
40 | }
41 | else
42 | if (srcDecimals < dstDecimals)
43 | {
44 | var diff = (dstDecimals - srcDecimals);
45 | var mult = (int)Math.Pow(10, diff);
46 | output.AppendLine(this, $"LOAD r0 {mult}");
47 | output.AppendLine(this, $"MUL {reg} r0 {reg}");
48 | return reg;
49 | }
50 | else
51 | {
52 | throw new CompilerException($"Decimal precision failure: {expr.ResultType} => {this.ResultType}");
53 | }
54 | }
55 |
56 | default:
57 | throw new CompilerException($"Unsupported cast: {expr.ResultType} => {this.ResultType}");
58 | }
59 | }
60 | }
61 |
62 | var vmType = MethodInterface.ConvertType(ResultType);
63 | output.AppendLine(this, $"CAST {reg} {reg} #{vmType}");
64 | return reg;
65 | }
66 |
67 |
68 | public override void Visit(Action callback)
69 | {
70 | callback(this);
71 | expr.Visit(callback);
72 | }
73 |
74 | public override bool IsNodeUsed(Node node)
75 | {
76 | return (node == this) || expr.IsNodeUsed(node);
77 | }
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/Samples/example8.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >0.4.10;
2 |
3 |
4 | //the very 8th example
5 | //this contract implements proof of ownership :) or at least it tries
6 | contract Example8 {
7 |
8 | address owner;
9 |
10 | event Stored(
11 | );
12 |
13 | struct Document {
14 | address ownerAddress;
15 | string name;
16 | uint256 timestamp;
17 | uint256 modified;
18 | }
19 | mapping (bytes32 => Document) public documents; //every file hashed will belong to a address using the data type 32 bytes, size of a sha256 hash.
20 | mapping (uint => bytes32) public hashList; //every file hashed will belong to a address using the data type 32 bytes, size of a sha256 hash.
21 | uint public documentCount = 0;
22 |
23 | constructor() public {
24 | owner = msg.sender;
25 | }
26 |
27 | function amIMaster() public view returns (string memory) {
28 | if (msg.sender == owner) {
29 | return "Yes, master";
30 | }
31 | return "No";
32 | }
33 | function getBalance() public view returns (uint) {
34 | return msg.sender.balance;
35 | }
36 |
37 | function amIOwner(string memory file) public view returns (bool) {
38 | bytes32 fileHash = keccak256(abi.encodePacked(file));
39 |
40 | if (msg.sender == documents[fileHash].ownerAddress) {
41 | return true;
42 | }
43 | return false;
44 | }
45 | function getHash(string memory file) public pure returns (bytes32) {
46 | return keccak256(abi.encodePacked(file));
47 | }
48 |
49 | function changeOwner(string memory file,address newOwner) public returns (bool) {
50 | if (amIOwner(file)) {
51 | bytes32 fileHash = keccak256(abi.encodePacked(file));
52 | documents[fileHash].ownerAddress = newOwner;
53 | documents[fileHash].modified = now;
54 | emit Stored();
55 | return true;
56 | }
57 | return false;
58 | }
59 |
60 | function store(string memory file,string memory name) public returns (bytes32) {
61 | bytes32 fileHash = keccak256(abi.encodePacked(file));
62 | if (documents[fileHash].ownerAddress == 0x0000000000000000000000000000000000000000) {
63 | documents[fileHash].ownerAddress = msg.sender; //can save
64 | documents[fileHash].name = name;
65 | documents[fileHash].timestamp = now;
66 | hashList[documentCount] = fileHash;
67 | documentCount += 1;
68 | emit Stored();
69 | return fileHash;
70 | }
71 | }
72 |
73 | function getDocumentCount() public view returns (uint) {
74 | return documentCount;
75 | }
76 |
77 | function getDocument(uint index) public view returns (bytes32 fileHash, address ownerAddress, string memory name, uint256 timestamp) {
78 | require(index > documentCount);
79 |
80 | fileHash = hashList[index];
81 | ownerAddress = documents[fileHash].ownerAddress;
82 | name = documents[fileHash].name;
83 | timestamp = documents[fileHash].timestamp;
84 |
85 | }
86 |
87 | function hasOwner(string memory file) public view returns (address) {
88 | return documents[keccak256(abi.encodePacked(file))].ownerAddress;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Library/src/CodeGen/Script.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Phantasma.Tomb.AST;
3 | using Phantasma.Tomb.AST.Statements;
4 | using Phantasma.Tomb.AST.Declarations;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Domain.Contract;
7 |
8 | namespace Phantasma.Tomb.CodeGen
9 | {
10 | public class Script: Module
11 | {
12 | public StatementBlock main;
13 |
14 | public MethodParameter[] Parameters { get; internal set; }
15 | public VarType ReturnType;
16 |
17 | public Script(string name, ModuleKind kind) : base(name, kind)
18 | {
19 |
20 | }
21 |
22 | public override MethodDeclaration FindMethod(string name)
23 | {
24 | return null;
25 | }
26 |
27 | public override bool IsNodeUsed(Node node)
28 | {
29 | if (node == this)
30 | {
31 | return true;
32 | }
33 |
34 | foreach (var lib in Libraries.Values)
35 | {
36 | if (lib.IsNodeUsed(node))
37 | {
38 | return true;
39 | }
40 | }
41 |
42 |
43 | return main.IsNodeUsed(node);
44 | }
45 |
46 | public override void Visit(Action callback)
47 | {
48 | foreach (var lib in Libraries.Values)
49 | {
50 | lib.Visit(callback);
51 | }
52 |
53 | callback(this);
54 | main.Visit(callback);
55 | }
56 |
57 |
58 | public override ContractInterface GenerateCode(CodeGenerator output)
59 | {
60 | this.Scope.Enter(output);
61 |
62 | this.main.ParentScope.Enter(output);
63 |
64 | foreach (var parameter in this.Parameters)
65 | {
66 | var reg = Compiler.Instance.AllocRegister(output, this, parameter.Name);
67 | output.AppendLine(this, $"POP {reg}");
68 |
69 | this.CallNecessaryConstructors(output, parameter.Type, reg);
70 |
71 | if (!this.main.ParentScope.Variables.ContainsKey(parameter.Name))
72 | {
73 | throw new CompilerException("script parameter not initialized: " + parameter.Name);
74 | }
75 |
76 | var varDecl = this.main.ParentScope.Variables[parameter.Name];
77 | varDecl.Register = reg;
78 | }
79 |
80 | this.main.GenerateCode(output);
81 | this.main.ParentScope.Leave(output);
82 |
83 | if (ReturnType.Kind == VarKind.None)
84 | {
85 | output.AppendLine(this, "RET");
86 | }
87 | else
88 | {
89 | bool hasReturn = false;
90 | this.main.Visit((node) =>
91 | {
92 | if (node is ReturnStatement)
93 | {
94 | hasReturn = true;
95 | }
96 | });
97 |
98 | if (!hasReturn)
99 | {
100 | throw new Exception("Script is missing return statement");
101 | }
102 | }
103 |
104 | this.Scope.Leave(output);
105 |
106 | return null;
107 | //return new ContractInterface(Enumerable.Empty(), Enumerable.Empty());
108 | }
109 |
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Tests/Contracts/ArrayTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Utils;
6 | using Phantasma.Tomb.Compilers;
7 |
8 | namespace Tests.Contracts;
9 |
10 | public class ArrayTests
11 | {
12 | [Test]
13 | public void StringArray()
14 | {
15 | var str = "hello";
16 |
17 | var sourceCode =
18 | @"contract test{
19 | public getStrings(): array {
20 | local result:array = {""A"", ""B"", ""C""};
21 | return result;
22 | }}";
23 |
24 | var parser = new TombLangCompiler();
25 | var contract = parser.Process(sourceCode).First();
26 |
27 | var storage = new Dictionary(new ByteArrayComparer());
28 |
29 | TestVM vm;
30 |
31 | var getStrings = contract.abi.FindMethod("getStrings");
32 | Assert.IsNotNull(getStrings);
33 |
34 | vm = new TestVM(contract, storage, getStrings);
35 | var result = vm.Execute();
36 | Assert.IsTrue(result == ExecutionState.Halt);
37 |
38 | Assert.IsTrue(vm.Stack.Count == 1);
39 |
40 | var obj = vm.Stack.Pop();
41 |
42 | var array = obj.AsArray(VMType.String);
43 | Assert.IsTrue(array.Length == 3);
44 | }
45 |
46 | [Test]
47 | public void ArraySimple()
48 | {
49 | // TODO make other tests also use multiline strings for source code, much more readable...
50 | var sourceCode = @"
51 | contract arrays {
52 | import Array;
53 |
54 | public test(x:number):number {
55 | local my_array: array;
56 | my_array[1] = x;
57 | return Array.length(my_array);
58 | }
59 | }
60 | ";
61 |
62 | var parser = new TombLangCompiler();
63 | var contract = parser.Process(sourceCode).First();
64 |
65 | var storage = new Dictionary(new ByteArrayComparer());
66 |
67 | TestVM vm;
68 |
69 | var test = contract.abi.FindMethod("test");
70 | Assert.IsNotNull(test);
71 |
72 | vm = new TestVM(contract, storage, test);
73 | vm.Stack.Push(VMObject.FromObject(5));
74 | var state = vm.Execute();
75 | Assert.IsTrue(state == ExecutionState.Halt);
76 |
77 | var result = vm.Stack.Pop().AsNumber();
78 | Assert.IsTrue(result == 1);
79 | }
80 |
81 | [Test]
82 | public void ArrayVariableIndex()
83 | {
84 | // TODO make other tests also use multiline strings for source code, much more readable...
85 | var sourceCode = @"
86 | contract arrays {
87 | public test(x:number, idx:number):number {
88 | local my_array: array;
89 | my_array[idx] = x;
90 | local num:number = my_array[idx];
91 | return num + 1;
92 | }
93 | }
94 | ";
95 |
96 | var parser = new TombLangCompiler();
97 | var contract = parser.Process(sourceCode).First();
98 |
99 | var storage = new Dictionary(new ByteArrayComparer());
100 |
101 | TestVM vm;
102 |
103 | var test = contract.abi.FindMethod("test");
104 | Assert.IsNotNull(test);
105 |
106 | vm = new TestVM(contract, storage, test);
107 | vm.Stack.Push(VMObject.FromObject(2));
108 | vm.Stack.Push(VMObject.FromObject(5));
109 | var state = vm.Execute();
110 | Assert.IsTrue(state == ExecutionState.Halt);
111 |
112 | var result = vm.Stack.Pop().AsNumber();
113 | Assert.IsTrue(result == 6);
114 | }
115 | }
--------------------------------------------------------------------------------
/Library/tests/Contracts/ArrayTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Domain;
5 | using Phantasma.Core.Domain.Execution.Enums;
6 | using Phantasma.Core.Domain.VM;
7 | using Phantasma.Core.Domain.VM.Enums;
8 | using Phantasma.Core.Utils;
9 | using Phantasma.Tomb.Compilers;
10 |
11 | namespace TOMBLib.Tests.Contracts;
12 |
13 | public class ArrayTests
14 | {
15 | [Test]
16 | public void StringArray()
17 | {
18 | var str = "hello";
19 |
20 | var sourceCode =
21 | @"contract test{
22 | public getStrings(): array {
23 | local result:array = {""A"", ""B"", ""C""};
24 | return result;
25 | }}";
26 |
27 | var parser = new TombLangCompiler();
28 | var contract = parser.Process(sourceCode).First();
29 |
30 | var storage = new Dictionary(new ByteArrayComparer());
31 |
32 | TestVM vm;
33 |
34 | var getStrings = contract.abi.FindMethod("getStrings");
35 | Assert.IsNotNull(getStrings);
36 |
37 | vm = new TestVM(contract, storage, getStrings);
38 | var result = vm.Execute();
39 | Assert.IsTrue(result == ExecutionState.Halt);
40 |
41 | Assert.IsTrue(vm.Stack.Count == 1);
42 |
43 | var obj = vm.Stack.Pop();
44 |
45 | var array = obj.AsArray(VMType.String);
46 | Assert.IsTrue(array.Length == 3);
47 | }
48 |
49 | [Test]
50 | public void ArraySimple()
51 | {
52 | // TODO make other tests also use multiline strings for source code, much more readable...
53 | var sourceCode = @"
54 | contract arrays {
55 | import Array;
56 |
57 | public test(x:number):number {
58 | local my_array: array;
59 | my_array[1] = x;
60 | return Array.length(my_array);
61 | }
62 | }
63 | ";
64 |
65 | var parser = new TombLangCompiler();
66 | var contract = parser.Process(sourceCode).First();
67 |
68 | var storage = new Dictionary(new ByteArrayComparer());
69 |
70 | TestVM vm;
71 |
72 | var test = contract.abi.FindMethod("test");
73 | Assert.IsNotNull(test);
74 |
75 | vm = new TestVM(contract, storage, test);
76 | vm.Stack.Push(VMObject.FromObject(5));
77 | var state = vm.Execute();
78 | Assert.IsTrue(state == ExecutionState.Halt);
79 |
80 | var result = vm.Stack.Pop().AsNumber();
81 | Assert.IsTrue(result == 1);
82 | }
83 |
84 | [Test]
85 | public void ArrayVariableIndex()
86 | {
87 | // TODO make other tests also use multiline strings for source code, much more readable...
88 | var sourceCode = @"
89 | contract arrays {
90 | public test(x:number, idx:number):number {
91 | local my_array: array;
92 | my_array[idx] = x;
93 | local num:number = my_array[idx];
94 | return num + 1;
95 | }
96 | }
97 | ";
98 |
99 | var parser = new TombLangCompiler();
100 | var contract = parser.Process(sourceCode).First();
101 |
102 | var storage = new Dictionary(new ByteArrayComparer());
103 |
104 | TestVM vm;
105 |
106 | var test = contract.abi.FindMethod("test");
107 | Assert.IsNotNull(test);
108 |
109 | vm = new TestVM(contract, storage, test);
110 | vm.Stack.Push(VMObject.FromObject(2));
111 | vm.Stack.Push(VMObject.FromObject(5));
112 | var state = vm.Execute();
113 | Assert.IsTrue(state == ExecutionState.Halt);
114 |
115 | var result = vm.Stack.Pop().AsNumber();
116 | Assert.IsTrue(result == 6);
117 | }
118 | }
--------------------------------------------------------------------------------
/Tests/Contracts/MethodTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Utils;
7 | using Phantasma.Tomb;
8 | using Phantasma.Tomb.Compilers;
9 |
10 | namespace Tests.Contracts;
11 |
12 | public class MethodTests
13 | {
14 | [Test]
15 | public void DuplicatedMethodNames()
16 | {
17 | var sourceCode =
18 | @"
19 | contract test {
20 | public testme(x:number): number {
21 | return 5;
22 | }
23 |
24 | public testme(x:number): string {
25 | return ""zero"";
26 | }}";
27 |
28 | var parser = new TombLangCompiler();
29 |
30 | Assert.Catch(() =>
31 | {
32 | var contract = parser.Process(sourceCode).First();
33 | });
34 | }
35 |
36 | [Test]
37 | public void TooManyArgs()
38 | {
39 | var sourceCode = @"
40 | contract arrays {
41 | import Array;
42 |
43 | public mycall(x:number):number {
44 | return x+ 1;
45 | }
46 |
47 | public something():number {
48 | return this.mycall(2, 3); // extra argument here, should not compile
49 | }
50 | }
51 | ";
52 |
53 | var parser = new TombLangCompiler();
54 |
55 | Assert.Catch(() =>
56 | {
57 | var contract = parser.Process(sourceCode).First();
58 | });
59 | }
60 |
61 | [Test]
62 | public void TestLocalCallViaThis()
63 | {
64 | var sourceCode =
65 | @"
66 | contract test {
67 | private sum(x:number, y:number) : number
68 | { return x + y; }
69 |
70 | public fetch(val:number) : number
71 | {
72 | return this.sum(val, 1);
73 | }
74 | }";
75 |
76 | var parser = new TombLangCompiler();
77 | var contract = parser.Process(sourceCode).First();
78 |
79 | var storage = new Dictionary(new ByteArrayComparer());
80 |
81 | TestVM vm;
82 |
83 | var keys = PhantasmaKeys.Generate();
84 |
85 | // call fetch
86 | var fetch = contract.abi.FindMethod("fetch");
87 | Assert.IsNotNull(fetch);
88 |
89 | vm = new TestVM(contract, storage, fetch);
90 | vm.Stack.Push(VMObject.FromObject(10));
91 | var state = vm.Execute();
92 | Assert.IsTrue(state == ExecutionState.Halt);
93 | var result = vm.Stack.Pop().AsNumber();
94 |
95 | Assert.IsTrue(result == 11);
96 | }
97 |
98 | [Test]
99 | public void TestContractCallViaCallMethod()
100 | {
101 | var sourceCode =
102 | @"
103 | contract test {
104 | import Call;
105 |
106 | private sum(x:number, y:number) : number
107 | { return x + y; }
108 |
109 | public fetch(val:number) : number
110 | {
111 | return Call.method(sum, val, 1);
112 | }
113 | }";
114 |
115 | var parser = new TombLangCompiler();
116 | var contract = parser.Process(sourceCode).First();
117 |
118 | var storage = new Dictionary(new ByteArrayComparer());
119 |
120 | TestVM vm;
121 |
122 | var keys = PhantasmaKeys.Generate();
123 |
124 | // call fetch
125 | var fetch = contract.abi.FindMethod("fetch");
126 | Assert.IsNotNull(fetch);
127 |
128 | vm = new TestVM(contract, storage, fetch);
129 | vm.Stack.Push(VMObject.FromObject(10));
130 | var state = vm.Execute();
131 | Assert.IsTrue(state == ExecutionState.Halt);
132 | var result = vm.Stack.Pop().AsNumber();
133 |
134 | Assert.IsTrue(result == 11);
135 | }
136 | }
--------------------------------------------------------------------------------
/Tests/Contracts/DecimalTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Globalization;
3 | using System.Linq;
4 | using NUnit.Framework;
5 | using Phantasma.Core.Cryptography;
6 | using Phantasma.Core.Domain;
7 | using Phantasma.Core.Numerics;
8 | using Phantasma.Core.Utils;
9 | using Phantasma.Tomb;
10 | using Phantasma.Tomb.Compilers;
11 |
12 | namespace Tests.Contracts;
13 |
14 | public class DecimalTests
15 | {
16 | [Test]
17 | public void DecimalsSimple()
18 | {
19 | var valStr = "2.4587";
20 | var val = decimal.Parse(valStr, CultureInfo.InvariantCulture);
21 | var decimals = 8;
22 |
23 | var sourceCode =
24 | "contract test{\n" +
25 | $"global amount: decimal<{decimals}>;\n" +
26 | "constructor(owner:address) {\n" +
27 | "amount = " + valStr + ";\n}" +
28 | "public getValue():number {\n" +
29 | "return amount;\n}" +
30 | "public getLength():number {\n" +
31 | "return amount.decimals();\n}" +
32 | "}\n";
33 |
34 | var parser = new TombLangCompiler();
35 | var contract = parser.Process(sourceCode).First();
36 |
37 | var storage = new Dictionary(new ByteArrayComparer());
38 |
39 | TestVM vm;
40 |
41 | var constructor = contract.abi.FindMethod(SmartContract.ConstructorName);
42 | Assert.IsNotNull(constructor);
43 |
44 | var keys = PhantasmaKeys.Generate();
45 |
46 | vm = new TestVM(contract, storage, constructor);
47 | vm.Stack.Push(VMObject.FromObject(keys.Address));
48 | var result = vm.Execute();
49 | Assert.IsTrue(result == ExecutionState.Halt);
50 |
51 | Assert.IsTrue(storage.Count == 1);
52 |
53 | // call getVal
54 | var getValue = contract.abi.FindMethod("getValue");
55 | Assert.IsNotNull(getValue);
56 |
57 | vm = new TestVM(contract, storage, getValue);
58 | result = vm.Execute();
59 | Assert.IsTrue(result == ExecutionState.Halt);
60 |
61 | Assert.IsTrue(storage.Count == 1);
62 |
63 | Assert.IsTrue(vm.Stack.Count == 1);
64 |
65 | var obj = vm.Stack.Pop();
66 | var newVal = obj.AsNumber();
67 | var expectedVal = UnitConversion.ToBigInteger(val, decimals);
68 |
69 | Assert.IsTrue(newVal == expectedVal);
70 |
71 | // call getLength
72 | var getLength = contract.abi.FindMethod("getLength");
73 | Assert.IsNotNull(getLength);
74 |
75 | vm = new TestVM(contract, storage, getLength);
76 | result = vm.Execute();
77 | Assert.IsTrue(result == ExecutionState.Halt);
78 |
79 | Assert.IsTrue(storage.Count == 1);
80 |
81 | Assert.IsTrue(vm.Stack.Count == 1);
82 |
83 | obj = vm.Stack.Pop();
84 | var len = obj.AsNumber();
85 |
86 | Assert.IsTrue(len == decimals);
87 | }
88 |
89 | [Test]
90 | public void DecimalsPrecision()
91 | {
92 | var valStr = "2.4587";
93 | var val = decimal.Parse(valStr, CultureInfo.InvariantCulture);
94 |
95 | var sourceCode =
96 | "contract test{\n" +
97 | $"global amount: decimal<3>;\n" +
98 | "constructor(owner:address) {\n" +
99 | "amount = " + valStr + ";\n}" +
100 | "}\n";
101 |
102 | var parser = new TombLangCompiler();
103 |
104 | try
105 | {
106 | var contract = parser.Process(sourceCode).First();
107 | Assert.Fail("should have throw compile error");
108 | }
109 | catch (CompilerException e)
110 | {
111 | Assert.IsTrue(e.Message.ToLower().Contains("precision"));
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/Tests/AST/Declaration/ConstDeclarationTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.AST;
3 | using Phantasma.Tomb.AST.Declarations;
4 | using Phantasma.Tomb.CodeGen;
5 | using Phantasma.Tomb.Lexers;
6 |
7 | namespace Tests.AST.Declaration;
8 |
9 | public class ConstDeclarationTest
10 | {
11 | [SetUp]
12 | public void Setup()
13 | {
14 | TombLangLexer lexer = new TombLangLexer();
15 | }
16 |
17 | [Test]
18 | public void ConstDeclaration_Constructor_SetsProperties()
19 | {
20 | // Arrange
21 | var module = new Contract("myself", ModuleKind.Contract);
22 | var parentScope = new Scope(module);
23 | var name = "MyConst";
24 | var type = VarType.Find(VarKind.Number);
25 | var value = "42";
26 |
27 | // Act
28 | var constDeclaration = new ConstDeclaration(parentScope, name, type, value);
29 |
30 | // Assert
31 | Assert.AreEqual(parentScope, constDeclaration.ParentScope);
32 | Assert.AreEqual(name, constDeclaration.Name);
33 | Assert.AreEqual(type, constDeclaration.Type);
34 | Assert.AreEqual(value, constDeclaration.Value);
35 | }
36 |
37 | [Test]
38 | public void ConstDeclaration_ToString_ReturnsCorrectString()
39 | {
40 | // Arrange
41 | var module = new Contract("myself", ModuleKind.Contract);
42 | var parentScope = new Scope(module);
43 | var name = "MyConst";
44 | var type = VarType.Find(VarKind.Number);
45 | var value = "42";
46 | var constDeclaration = new ConstDeclaration(parentScope, name, type, value);
47 |
48 | // Act
49 | var result = constDeclaration.ToString();
50 |
51 | // Assert
52 | Assert.AreEqual("const MyConst:Number", result);
53 | }
54 |
55 | [Test]
56 | public void ConstDeclaration_Visit_ExecutesCallback()
57 | {
58 | // Arrange
59 | var module = new Contract("myself", ModuleKind.Contract);
60 | var parentScope = new Scope(module);
61 | var name = "MyConst";
62 | var type = VarType.Find(VarKind.Number);
63 | var value = "42";
64 | var constDeclaration = new ConstDeclaration(parentScope, name, type, value);
65 | var visited = false;
66 |
67 | // Act
68 | constDeclaration.Visit(node => visited = true);
69 |
70 | // Assert
71 | Assert.True(visited);
72 | }
73 |
74 | [Test]
75 | public void ConstDeclaration_IsNodeUsed_ReturnsTrue()
76 | {
77 | // Arrange
78 | var module = new Contract("myself", ModuleKind.Contract);
79 | var parentScope = new Scope(module);
80 | var name = "MyConst";
81 | var type = VarType.Find(VarKind.Number);
82 | var value = "42";
83 | var constDeclaration = new ConstDeclaration(parentScope, name, type, value);
84 |
85 | // Act
86 | var result = constDeclaration.IsNodeUsed(constDeclaration);
87 |
88 | // Assert
89 | Assert.True(result);
90 | }
91 |
92 | [Test]
93 | public void ConstDeclaration_IsNodeUsed_ReturnsFalse()
94 | {
95 | // Arrange
96 | var module = new Contract("myself", ModuleKind.Contract);
97 | var parentScope = new Scope(module);
98 | var name = "MyConst";
99 | var type = VarType.Find(VarKind.Number);
100 | var value = "42";
101 | var constDeclaration = new ConstDeclaration(parentScope, name, type, value);
102 | var otherNode = new ConstDeclaration(parentScope, "OtherConst", VarType.Find(VarKind.Decimal, 2), "3.12");
103 |
104 | // Act
105 | var result = constDeclaration.IsNodeUsed(otherNode);
106 |
107 | // Assert
108 | Assert.False(result);
109 | }
110 | }
--------------------------------------------------------------------------------
/Library/tests/AST/Declaration/ConstDeclarationTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using Phantasma.Tomb.AST;
3 | using Phantasma.Tomb.AST.Declarations;
4 | using Phantasma.Tomb.CodeGen;
5 | using Phantasma.Tomb.Lexers;
6 |
7 | namespace TOMBLib.Tests.AST.Declaration;
8 |
9 | public class ConstDeclarationTest
10 | {
11 | [SetUp]
12 | public void Setup()
13 | {
14 | TombLangLexer lexer = new TombLangLexer();
15 | }
16 |
17 | [Test]
18 | public void ConstDeclaration_Constructor_SetsProperties()
19 | {
20 | // Arrange
21 | var module = new Contract("myself", ModuleKind.Contract);
22 | var parentScope = new Scope(module);
23 | var name = "MyConst";
24 | var type = VarType.Find(VarKind.Number);
25 | var value = "42";
26 |
27 | // Act
28 | var constDeclaration = new ConstDeclaration(parentScope, name, type, value);
29 |
30 | // Assert
31 | Assert.AreEqual(parentScope, constDeclaration.ParentScope);
32 | Assert.AreEqual(name, constDeclaration.Name);
33 | Assert.AreEqual(type, constDeclaration.Type);
34 | Assert.AreEqual(value, constDeclaration.Value);
35 | }
36 |
37 | [Test]
38 | public void ConstDeclaration_ToString_ReturnsCorrectString()
39 | {
40 | // Arrange
41 | var module = new Contract("myself", ModuleKind.Contract);
42 | var parentScope = new Scope(module);
43 | var name = "MyConst";
44 | var type = VarType.Find(VarKind.Number);
45 | var value = "42";
46 | var constDeclaration = new ConstDeclaration(parentScope, name, type, value);
47 |
48 | // Act
49 | var result = constDeclaration.ToString();
50 |
51 | // Assert
52 | Assert.AreEqual("const MyConst:Number", result);
53 | }
54 |
55 | [Test]
56 | public void ConstDeclaration_Visit_ExecutesCallback()
57 | {
58 | // Arrange
59 | var module = new Contract("myself", ModuleKind.Contract);
60 | var parentScope = new Scope(module);
61 | var name = "MyConst";
62 | var type = VarType.Find(VarKind.Number);
63 | var value = "42";
64 | var constDeclaration = new ConstDeclaration(parentScope, name, type, value);
65 | var visited = false;
66 |
67 | // Act
68 | constDeclaration.Visit(node => visited = true);
69 |
70 | // Assert
71 | Assert.True(visited);
72 | }
73 |
74 | [Test]
75 | public void ConstDeclaration_IsNodeUsed_ReturnsTrue()
76 | {
77 | // Arrange
78 | var module = new Contract("myself", ModuleKind.Contract);
79 | var parentScope = new Scope(module);
80 | var name = "MyConst";
81 | var type = VarType.Find(VarKind.Number);
82 | var value = "42";
83 | var constDeclaration = new ConstDeclaration(parentScope, name, type, value);
84 |
85 | // Act
86 | var result = constDeclaration.IsNodeUsed(constDeclaration);
87 |
88 | // Assert
89 | Assert.True(result);
90 | }
91 |
92 | [Test]
93 | public void ConstDeclaration_IsNodeUsed_ReturnsFalse()
94 | {
95 | // Arrange
96 | var module = new Contract("myself", ModuleKind.Contract);
97 | var parentScope = new Scope(module);
98 | var name = "MyConst";
99 | var type = VarType.Find(VarKind.Number);
100 | var value = "42";
101 | var constDeclaration = new ConstDeclaration(parentScope, name, type, value);
102 | var otherNode = new ConstDeclaration(parentScope, "OtherConst", VarType.Find(VarKind.Decimal, 2), "3.12");
103 |
104 | // Act
105 | var result = constDeclaration.IsNodeUsed(otherNode);
106 |
107 | // Assert
108 | Assert.False(result);
109 | }
110 | }
--------------------------------------------------------------------------------
/Library/tests/Contracts/MethodTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 | using Phantasma.Core.Cryptography;
5 | using Phantasma.Core.Domain;
6 | using Phantasma.Core.Domain.Execution.Enums;
7 | using Phantasma.Core.Domain.VM;
8 | using Phantasma.Core.Utils;
9 | using Phantasma.Tomb;
10 | using Phantasma.Tomb.Compilers;
11 |
12 | namespace TOMBLib.Tests.Contracts;
13 |
14 | public class MethodTests
15 | {
16 | [Test]
17 | public void DuplicatedMethodNames()
18 | {
19 | var sourceCode =
20 | @"
21 | contract test {
22 | public testme(x:number): number {
23 | return 5;
24 | }
25 |
26 | public testme(x:number): string {
27 | return ""zero"";
28 | }}";
29 |
30 | var parser = new TombLangCompiler();
31 |
32 | Assert.Catch(() =>
33 | {
34 | var contract = parser.Process(sourceCode).First();
35 | });
36 | }
37 |
38 | [Test]
39 | public void TooManyArgs()
40 | {
41 | var sourceCode = @"
42 | contract arrays {
43 | import Array;
44 |
45 | public mycall(x:number):number {
46 | return x+ 1;
47 | }
48 |
49 | public something():number {
50 | return this.mycall(2, 3); // extra argument here, should not compile
51 | }
52 | }
53 | ";
54 |
55 | var parser = new TombLangCompiler();
56 |
57 | Assert.Catch(() =>
58 | {
59 | var contract = parser.Process(sourceCode).First();
60 | });
61 | }
62 |
63 | [Test]
64 | public void TestLocalCallViaThis()
65 | {
66 | var sourceCode =
67 | @"
68 | contract test {
69 | private sum(x:number, y:number) : number
70 | { return x + y; }
71 |
72 | public fetch(val:number) : number
73 | {
74 | return this.sum(val, 1);
75 | }
76 | }";
77 |
78 | var parser = new TombLangCompiler();
79 | var contract = parser.Process(sourceCode).First();
80 |
81 | var storage = new Dictionary(new ByteArrayComparer());
82 |
83 | TestVM vm;
84 |
85 | var keys = PhantasmaKeys.Generate();
86 |
87 | // call fetch
88 | var fetch = contract.abi.FindMethod("fetch");
89 | Assert.IsNotNull(fetch);
90 |
91 | vm = new TestVM(contract, storage, fetch);
92 | vm.Stack.Push(VMObject.FromObject(10));
93 | var state = vm.Execute();
94 | Assert.IsTrue(state == ExecutionState.Halt);
95 | var result = vm.Stack.Pop().AsNumber();
96 |
97 | Assert.IsTrue(result == 11);
98 | }
99 |
100 | [Test]
101 | public void TestContractCallViaCallMethod()
102 | {
103 | var sourceCode =
104 | @"
105 | contract test {
106 | import Call;
107 |
108 | private sum(x:number, y:number) : number
109 | { return x + y; }
110 |
111 | public fetch(val:number) : number
112 | {
113 | return Call.method(sum, val, 1);
114 | }
115 | }";
116 |
117 | var parser = new TombLangCompiler();
118 | var contract = parser.Process(sourceCode).First();
119 |
120 | var storage = new Dictionary(new ByteArrayComparer());
121 |
122 | TestVM vm;
123 |
124 | var keys = PhantasmaKeys.Generate();
125 |
126 | // call fetch
127 | var fetch = contract.abi.FindMethod("fetch");
128 | Assert.IsNotNull(fetch);
129 |
130 | vm = new TestVM(contract, storage, fetch);
131 | vm.Stack.Push(VMObject.FromObject(10));
132 | var state = vm.Execute();
133 | Assert.IsTrue(state == ExecutionState.Halt);
134 | var result = vm.Stack.Pop().AsNumber();
135 |
136 | Assert.IsTrue(result == 11);
137 | }
138 | }
--------------------------------------------------------------------------------
/Library/tests/Contracts/DecimalTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Globalization;
3 | using System.Linq;
4 | using NUnit.Framework;
5 | using Phantasma.Core.Cryptography;
6 | using Phantasma.Core.Domain;
7 | using Phantasma.Core.Domain.Contract;
8 | using Phantasma.Core.Domain.Execution.Enums;
9 | using Phantasma.Core.Domain.VM;
10 | using Phantasma.Core.Numerics;
11 | using Phantasma.Core.Utils;
12 | using Phantasma.Tomb;
13 | using Phantasma.Tomb.Compilers;
14 |
15 | namespace TOMBLib.Tests.Contracts;
16 |
17 | public class DecimalTests
18 | {
19 | [Test]
20 | public void DecimalsSimple()
21 | {
22 | var valStr = "2.4587";
23 | var val = decimal.Parse(valStr, CultureInfo.InvariantCulture);
24 | var decimals = 8;
25 |
26 | var sourceCode =
27 | "contract test{\n" +
28 | $"global amount: decimal<{decimals}>;\n" +
29 | "constructor(owner:address) {\n" +
30 | "amount = " + valStr + ";\n}" +
31 | "public getValue():number {\n" +
32 | "return amount;\n}" +
33 | "public getLength():number {\n" +
34 | "return amount.decimals();\n}" +
35 | "}\n";
36 |
37 | var parser = new TombLangCompiler();
38 | var contract = parser.Process(sourceCode).First();
39 |
40 | var storage = new Dictionary(new ByteArrayComparer());
41 |
42 | TestVM vm;
43 |
44 | var constructor = contract.abi.FindMethod(SmartContract.ConstructorName);
45 | Assert.IsNotNull(constructor);
46 |
47 | var keys = PhantasmaKeys.Generate();
48 |
49 | vm = new TestVM(contract, storage, constructor);
50 | vm.Stack.Push(VMObject.FromObject(keys.Address));
51 | var result = vm.Execute();
52 | Assert.IsTrue(result == ExecutionState.Halt);
53 |
54 | Assert.IsTrue(storage.Count == 1);
55 |
56 | // call getVal
57 | var getValue = contract.abi.FindMethod("getValue");
58 | Assert.IsNotNull(getValue);
59 |
60 | vm = new TestVM(contract, storage, getValue);
61 | result = vm.Execute();
62 | Assert.IsTrue(result == ExecutionState.Halt);
63 |
64 | Assert.IsTrue(storage.Count == 1);
65 |
66 | Assert.IsTrue(vm.Stack.Count == 1);
67 |
68 | var obj = vm.Stack.Pop();
69 | var newVal = obj.AsNumber();
70 | var expectedVal = UnitConversion.ToBigInteger(val, decimals);
71 |
72 | Assert.IsTrue(newVal == expectedVal);
73 |
74 | // call getLength
75 | var getLength = contract.abi.FindMethod("getLength");
76 | Assert.IsNotNull(getLength);
77 |
78 | vm = new TestVM(contract, storage, getLength);
79 | result = vm.Execute();
80 | Assert.IsTrue(result == ExecutionState.Halt);
81 |
82 | Assert.IsTrue(storage.Count == 1);
83 |
84 | Assert.IsTrue(vm.Stack.Count == 1);
85 |
86 | obj = vm.Stack.Pop();
87 | var len = obj.AsNumber();
88 |
89 | Assert.IsTrue(len == decimals);
90 | }
91 |
92 | [Test]
93 | public void DecimalsPrecision()
94 | {
95 | var valStr = "2.4587";
96 | var val = decimal.Parse(valStr, CultureInfo.InvariantCulture);
97 |
98 | var sourceCode =
99 | "contract test{\n" +
100 | $"global amount: decimal<3>;\n" +
101 | "constructor(owner:address) {\n" +
102 | "amount = " + valStr + ";\n}" +
103 | "}\n";
104 |
105 | var parser = new TombLangCompiler();
106 |
107 | try
108 | {
109 | var contract = parser.Process(sourceCode).First();
110 | Assert.Fail("should have throw compile error");
111 | }
112 | catch (CompilerException e)
113 | {
114 | Assert.IsTrue(e.Message.ToLower().Contains("precision"));
115 | }
116 | }
117 | }
--------------------------------------------------------------------------------
/Library/src/AST/Expressions/MacroExpression.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Core.Domain;
2 | using Phantasma.Core.Domain.Contract;
3 | using Phantasma.Core.Numerics;
4 | using Phantasma.Tomb.CodeGen;
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 |
10 | namespace Phantasma.Tomb.AST.Expressions
11 | {
12 | public class MacroExpression : Expression
13 | {
14 | public string value;
15 | public string[] args;
16 |
17 | public MacroExpression(Scope parentScope, string value, IEnumerable args) : base(parentScope)
18 | {
19 | this.value = value;
20 | this.args = args.ToArray();
21 | }
22 |
23 | public override string ToString()
24 | {
25 | return "macro: " + value;
26 | }
27 |
28 | public override Register GenerateCode(CodeGenerator output)
29 | {
30 | throw new System.Exception($"macro {value} was not unfolded!");
31 | }
32 |
33 | public override void Visit(Action callback)
34 | {
35 | callback(this);
36 | }
37 |
38 | public override bool IsNodeUsed(Node node)
39 | {
40 | return (node == this);
41 | }
42 |
43 | public LiteralExpression Unfold(Scope scope)
44 | {
45 | switch (value)
46 | {
47 | case "THIS_ADDRESS":
48 | {
49 | var addr = SmartContract.GetAddressFromContractName(scope.Module.Name);
50 | var hex = Base16.Encode(addr.ToByteArray());
51 | return new LiteralExpression(scope, "0x" + hex, VarType.Find(VarKind.Address));
52 | }
53 |
54 | case "THIS_SYMBOL":
55 | {
56 | var module = scope.Module;
57 |
58 | while (module.Kind != ModuleKind.Token && module.Parent != null)
59 | {
60 | module = module.Parent;
61 | }
62 |
63 | if (module.Kind == ModuleKind.Token)
64 | {
65 | return new LiteralExpression(scope, '\"' + module.Name + '\"', VarType.Find(VarKind.String));
66 | }
67 |
68 | throw new CompilerException($"macro {value} is not available here");
69 | }
70 |
71 | case "TYPE_OF":
72 | {
73 | if (args.Length != 1)
74 | {
75 | throw new CompilerException($"macro {value} requires 1 argument");
76 | }
77 |
78 | var target = args[0];
79 |
80 | VarKind kind;
81 | if (!Enum.TryParse(target, true, out kind))
82 | {
83 | var decl = scope.FindVariable(target, false);
84 | if (decl == null)
85 | {
86 | throw new CompilerException($"unknown identifier: {target}");
87 | }
88 |
89 | kind = decl.Type.Kind;
90 | }
91 |
92 | return new LiteralExpression(scope, kind.ToString(), VarType.Find(VarKind.Type));
93 | }
94 |
95 | default:
96 | {
97 | var macro = Compiler.Instance.ResolveMacro(value);
98 |
99 | if (macro != null)
100 | {
101 | return new LiteralExpression(scope, macro.GetValue(), macro.type);
102 | }
103 | else
104 | {
105 | throw new CompilerException($"unknown compile time macro: {value}");
106 | }
107 | }
108 | }
109 | }
110 |
111 | public override VarType ResultType => VarType.Find(VarKind.Unknown);
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/Library/src/AST/Expressions/BinaryExpression.cs:
--------------------------------------------------------------------------------
1 | using Phantasma.Core.Domain;
2 | using Phantasma.Core.Domain.VM.Enums;
3 | using Phantasma.Tomb.CodeGen;
4 |
5 | using System;
6 |
7 | namespace Phantasma.Tomb.AST.Expressions
8 | {
9 | public class BinaryExpression : Expression
10 | {
11 | private OperatorKind op;
12 | private Expression left;
13 | private Expression right;
14 |
15 | public override VarType ResultType => op.IsLogicalOperator() ? VarType.Find(VarKind.Bool) : left.ResultType;
16 |
17 | public BinaryExpression(Scope parentScope, OperatorKind op, Expression leftSide, Expression rightSide) : base(parentScope)
18 | {
19 | if (op == OperatorKind.Unknown)
20 | {
21 | throw new CompilerException("implementation failure");
22 | }
23 |
24 | this.op = op;
25 | this.left = leftSide;
26 | this.right = rightSide;
27 | }
28 |
29 | public override T AsLiteral()
30 | {
31 | if (op == OperatorKind.Addition)
32 | {
33 | if (typeof(T) == typeof(string) && ResultType.Kind == VarKind.String)
34 | return (T)(object)(left.AsLiteral() + right.AsLiteral());
35 |
36 | if (typeof(T) == typeof(int) && ResultType.Kind == VarKind.Number)
37 | return (T)(object)(left.AsLiteral() + right.AsLiteral());
38 | }
39 |
40 |
41 | return base.AsLiteral();
42 | }
43 |
44 | public override bool IsNodeUsed(Node node)
45 | {
46 | return (node == this) || left.IsNodeUsed(node) || right.IsNodeUsed(node);
47 | }
48 |
49 | public override void Visit(Action callback)
50 | {
51 | callback(this);
52 | left.Visit(callback);
53 | right.Visit(callback);
54 | }
55 |
56 | public override Register GenerateCode(CodeGenerator output)
57 | {
58 | if (this.op == OperatorKind.Addition && left.ResultType.Kind == VarKind.String && right.ResultType.Kind != VarKind.String)
59 | {
60 | this.right = new CastExpression(this.ParentScope, VarType.Find(VarKind.String), right);
61 | }
62 |
63 | var regLeft = left.GenerateCode(output);
64 | var regRight = right.GenerateCode(output);
65 | var regResult = Compiler.Instance.AllocRegister(output, this);
66 |
67 | Opcode opcode;
68 | switch (this.op)
69 | {
70 | case OperatorKind.Addition: opcode = Opcode.ADD; break;
71 | case OperatorKind.Subtraction: opcode = Opcode.SUB; break;
72 | case OperatorKind.Multiplication: opcode = Opcode.MUL; break;
73 | case OperatorKind.Division: opcode = Opcode.DIV; break;
74 | case OperatorKind.Modulus: opcode = Opcode.MOD; break;
75 | case OperatorKind.Power: opcode = Opcode.POW; break;
76 |
77 | case OperatorKind.Equal: opcode = Opcode.EQUAL; break;
78 | case OperatorKind.Less: opcode = Opcode.LT; break;
79 | case OperatorKind.LessOrEqual: opcode = Opcode.LTE; break;
80 | case OperatorKind.Greater: opcode = Opcode.GT; break;
81 | case OperatorKind.GreaterOrEqual: opcode = Opcode.GTE; break;
82 |
83 | case OperatorKind.ShiftRight: opcode = Opcode.SHR; break;
84 | case OperatorKind.ShiftLeft: opcode = Opcode.SHL; break;
85 |
86 | case OperatorKind.Or: opcode = Opcode.OR; break;
87 | case OperatorKind.And: opcode = Opcode.AND; break;
88 | case OperatorKind.Xor: opcode = Opcode.XOR; break;
89 |
90 | default:
91 | throw new CompilerException("not implemented vmopcode for " + op);
92 | }
93 |
94 | output.AppendLine(this, $"{opcode} {regLeft} {regRight} {regResult}");
95 |
96 | Compiler.Instance.DeallocRegister(ref regRight);
97 | Compiler.Instance.DeallocRegister(ref regLeft);
98 |
99 | return regResult;
100 | }
101 |
102 | public override string ToString()
103 | {
104 | return $"{left} {op} {right}";
105 | }
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------