Skip to content

Commit

Permalink
SC: remove semantic versionning and use an int instead for @Version
Browse files Browse the repository at this point in the history
  • Loading branch information
bchamagne committed Mar 1, 2023
1 parent a596a00 commit 1d6433a
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 56 deletions.
4 changes: 2 additions & 2 deletions lib/archethic/contracts/contract.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ defmodule Archethic.Contracts.Contract do
alias Archethic.TransactionChain.TransactionData

defstruct triggers: %{},
version: {0, 0, 1},
version: 0,
conditions: %{
transaction: %Conditions{},
inherit: %Conditions{},
Expand All @@ -32,7 +32,7 @@ defmodule Archethic.Contracts.Contract do
triggers: %{
trigger_type() => Macro.t()
},
version: {integer(), integer(), integer()},
version: integer(),
conditions: %{
transaction: Conditions.t(),
inherit: Conditions.t(),
Expand Down
46 changes: 15 additions & 31 deletions lib/archethic/contracts/interpreter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ defmodule Archethic.Contracts.Interpreter do

alias Archethic.TransactionChain.Transaction

@type version() :: {integer(), integer(), integer()}
@type version() :: integer()

@doc """
Dispatch through the correct interpreter.
Expand All @@ -20,10 +20,10 @@ defmodule Archethic.Contracts.Interpreter do
@spec parse(code :: binary()) :: {:ok, Contract.t()} | {:error, String.t()}
def parse(code) when is_binary(code) do
case version(code) do
{{0, 0, 1}, code_without_version} ->
{0, code_without_version} ->
Version0.parse(code_without_version)

{version = {1, _, _}, code_without_version} ->
{version = 1, code_without_version} ->
Version1.parse(code_without_version, version)

_ ->
Expand Down Expand Up @@ -51,46 +51,35 @@ defmodule Archethic.Contracts.Interpreter do
def version(code) do
regex_opts = [capture: :all_but_first]

version_attr_regex = ~r/^\s*@version\s+"(\S+)"/
version_attr_regex = ~r/^\s*@version\s+(\d+)\s/

if Regex.match?(~r/^\s*@version/, code) do
case Regex.run(version_attr_regex, code, regex_opts) do
nil ->
# there is a @version but syntax is invalid (probably the quotes missing)
# there is a @version but syntax is invalid (probably the not an integer)
:error

[capture] ->
case Regex.run(semver_regex(), capture, regex_opts) do
nil ->
# there is a @version but semver syntax is wrong
:error

["0", "0", "0"] ->
# there is a @version but it's 0.0.0
:error

[major, minor, patch] ->
{
{String.to_integer(major), String.to_integer(minor), String.to_integer(patch)},
Regex.replace(version_attr_regex, code, "")
}
end
[version] ->
{
String.to_integer(version),
Regex.replace(version_attr_regex, code, "")
}
end
else
# no @version at all
{{0, 0, 1}, code}
{0, code}
end
end

@doc """
Return true if the given conditions are valid on the given constants
"""
@spec valid_conditions?(version(), Conditions.t(), map()) :: bool()
def valid_conditions?({0, _, _}, conditions, constants) do
def valid_conditions?(0, conditions, constants) do
Version0.valid_conditions?(conditions, constants)
end

def valid_conditions?({1, _, _}, conditions, constants) do
def valid_conditions?(1, conditions, constants) do
Version1.valid_conditions?(conditions, constants)
end

Expand All @@ -99,11 +88,11 @@ defmodule Archethic.Contracts.Interpreter do
May return a new transaction or nil
"""
@spec execute_trigger(version(), Macro.t(), map()) :: Transaction.t() | nil
def execute_trigger({0, _, _}, ast, constants) do
def execute_trigger(0, ast, constants) do
Version0.execute_trigger(ast, constants)
end

def execute_trigger({1, _, _}, ast, constants) do
def execute_trigger(1, ast, constants) do
Version1.execute_trigger(ast, constants)
end

Expand Down Expand Up @@ -165,9 +154,4 @@ defmodule Archethic.Contracts.Interpreter do
{:ok, {:atom, atom}}
end
end

# source: https://semver.org/
defp semver_regex() do
~r/(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?/
end
end
2 changes: 1 addition & 1 deletion lib/archethic/contracts/interpreter/version0.ex
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ defmodule Archethic.Contracts.Interpreter.Version0 do
def parse(code) when is_binary(code) do
with {:ok, ast} <- Interpreter.sanitize_code(code),
{:ok, contract} <- parse_contract(ast, %Contract{}) do
{:ok, %{contract | version: {0, 0, 1}}}
{:ok, %{contract | version: 0}}
else
{:error, {meta, {_, info}, token}} ->
{:error, Interpreter.format_error_reason({token, meta, []}, info)}
Expand Down
6 changes: 3 additions & 3 deletions lib/archethic/contracts/interpreter/version1.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ defmodule Archethic.Contracts.Interpreter.Version1 do
@doc """
Parse the code and return the parsed contract.
"""
@spec parse(binary(), {integer(), integer(), integer()}) ::
@spec parse(binary(), integer()) ::
{:ok, Contract.t()} | {:error, String.t()}
def parse(code, {1, 0, 0}) when is_binary(code) do
{:ok, %Contract{version: {1, 0, 0}}}
def parse(code, version = 1) when is_binary(code) do
{:ok, %Contract{version: version}}
end

def parse(_, _), do: {:error, "@version not supported"}
Expand Down
29 changes: 11 additions & 18 deletions test/archethic/contracts/interpreter_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ defmodule Archethic.Contracts.InterpreterTest do

test "should return an error if version does not exist yet" do
code_v0 = ~s"""
@version "0.144.233"
@version 20
#{ContractFactory.valid_version0_contract()}
"""

code_v1 = ~s"""
@version "1.377.610"
@version 20
#{ContractFactory.valid_version1_contract(version_attribute: false)}
"""

Expand All @@ -30,7 +30,7 @@ defmodule Archethic.Contracts.InterpreterTest do

test "should return an error if version is invalid" do
code_v0 = ~s"""
@version 12
@version 1.5
#{ContractFactory.valid_version0_contract()}
"""

Expand All @@ -39,34 +39,27 @@ defmodule Archethic.Contracts.InterpreterTest do
end

describe "version/1" do
test "should return 0.0.1 if there is no interpreter tag" do
test "should return 0 if there is no interpreter tag" do
code = ~s(some code)
assert {{0, 0, 1}, ^code} = Interpreter.version(code)
assert {0, ^code} = Interpreter.version(code)
end

test "should return the correct version if specified" do
assert {{0, 0, 1}, "\n my_code"} = Interpreter.version(~s(@version "0.0.1"\n my_code))
assert {{0, 1, 0}, " \n my_code"} = Interpreter.version(~s(@version "0.1.0" \n my_code))
assert {{0, 1, 1}, ""} = Interpreter.version(~s(@version "0.1.1"))
assert {{1, 0, 0}, _} = Interpreter.version(~s(@version "1.0.0"))
assert {{1, 0, 1}, _} = Interpreter.version(~s(@version "1.0.1"))
assert {{1, 1, 0}, _} = Interpreter.version(~s(@version "1.1.0"))
assert {{1, 1, 1}, _} = Interpreter.version(~s(@version "1.1.1"))
assert {0, "my_code"} = Interpreter.version(~s(@version 0\nmy_code))
assert {1, "my_code"} = Interpreter.version(~s(@version 1\nmy_code))
end

test "should work even if there are some whitespaces" do
assert {{0, 1, 0}, _} = Interpreter.version(~s(\n \n @version "0.1.0" \n \n))
assert {{1, 1, 2}, _} = Interpreter.version(~s(\n \n @version "1.1.2" \n \n))
assert {{3, 105, 0}, _} = Interpreter.version(~s(\n \n @version "3.105.0" \n \n))
assert {0, _} = Interpreter.version(~s(\n \n @version 0 \n \n))
assert {1, _} = Interpreter.version(~s(\n \n @version 1 \n \n))
end

test "should return error if version is not formatted as expected" do
assert :error = Interpreter.version(~s(@version "0"))
assert :error = Interpreter.version(~s(@version "1"))
assert :error = Interpreter.version(~s(@version "0.0"))
assert :error = Interpreter.version(~s(@version 1.1))
assert :error = Interpreter.version(~s(@version "1.1"))
assert :error = Interpreter.version(~s(@version "0.0.0"))
assert :error = Interpreter.version(~s(@version 1.1.1))
assert :error = Interpreter.version(~s(@version "1.1.1"))
end
end
end
2 changes: 1 addition & 1 deletion test/support/contract_factory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ defmodule Archethic.ContractFactory do

if Keyword.get(opts, :version_attribute, true) do
"""
@version "1.0.0"
@version 1
#{code}
"""
else
Expand Down

0 comments on commit 1d6433a

Please sign in to comment.