Skip to content

Commit

Permalink
remove version() function and pattern match the AST instead to determ…
Browse files Browse the repository at this point in the history
…ine version
  • Loading branch information
bchamagne committed Mar 7, 2023
1 parent 1d6433a commit ee5cee8
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 84 deletions.
50 changes: 12 additions & 38 deletions lib/archethic/contracts/interpreter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ 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, code_without_version} ->
Version0.parse(code_without_version)

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

_ ->
{:error, "@version not supported"}
case sanitize_code(code) do
{:ok, block} ->
case block do
{:__block__, [], [{:@, _, [{{:atom, "version"}, _, [version]}]} | rest]} ->
Version1.parse({:__block__, [], rest}, version)

_ ->
Version0.parse(block)
end

{:error, reason} ->
{:error, reason}
end
end

Expand All @@ -42,35 +45,6 @@ defmodule Archethic.Contracts.Interpreter do
|> Code.string_to_quoted(static_atoms_encoder: &atom_encoder/2)
end

@doc """
Determine from the code, the version to use.
Return the version & the code where the version has been removed.
(should be private, but there are unit tests)
"""
@spec version(String.t()) :: {version(), String.t()} | :error
def version(code) do
regex_opts = [capture: :all_but_first]

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 not an integer)
:error

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

@doc """
Return true if the given conditions are valid on the given constants
"""
Expand Down
25 changes: 11 additions & 14 deletions lib/archethic/contracts/interpreter/version0.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ defmodule Archethic.Contracts.Interpreter.Version0 do
## Examples
iex> Version0.parse("
iex> {:ok, ast} = Interpreter.sanitize_code("
...> condition transaction: [
...> content: regex_match?(\"^Mr.Y|Mr.X{1}$\"),
...> origin_family: biometric
Expand All @@ -44,6 +44,7 @@ defmodule Archethic.Contracts.Interpreter.Version0 do
...> set_content \"uco price changed\"
...> end
...> ")
...> Version0.parse(ast)
{:ok,
%Contract{
conditions: %{
Expand Down Expand Up @@ -151,32 +152,28 @@ defmodule Archethic.Contracts.Interpreter.Version0 do
Returns an error when there are invalid trigger options
iex> Version0.parse("
iex> {:ok, ast} = Interpreter.sanitize_code("
...> actions triggered_by: datetime, at: 0000000 do
...> end
...> ")
...> Version0.parse(ast)
{:error, "invalid datetime's trigger"}
Returns an error when a invalid term is provided
iex> Version0.parse("
iex> {:ok, ast} = Interpreter.sanitize_code("
...> actions triggered_by: transaction do
...> System.user_home
...> end
...> ")
...> Version0.parse(ast)
{:error, "unexpected term - System - L2"}
"""
@spec parse(code :: binary()) :: {:ok, Contract.t()} | {:error, reason :: binary()}
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}}
else
{:error, {meta, {_, info}, token}} ->
{:error, Interpreter.format_error_reason({token, meta, []}, info)}

{:error, {meta, info, token}} ->
{:error, Interpreter.format_error_reason({token, meta, []}, info)}
@spec parse(ast :: Macro.t()) :: {:ok, Contract.t()} | {:error, reason :: binary()}
def parse(ast) do
case parse_contract(ast, %Contract{}) do
{:ok, contract} ->
{:ok, %{contract | version: 0}}

{:error, {:unexpected_term, ast}} ->
{:error, Interpreter.format_error_reason(ast, "unexpected term")}
Expand Down
4 changes: 2 additions & 2 deletions lib/archethic/contracts/interpreter/version1.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ defmodule Archethic.Contracts.Interpreter.Version1 do
@doc """
Parse the code and return the parsed contract.
"""
@spec parse(binary(), integer()) ::
@spec parse(Macro.t(), integer()) ::
{:ok, Contract.t()} | {:error, String.t()}
def parse(code, version = 1) when is_binary(code) do
def parse(_ast, version = 1) do
{:ok, %Contract{version: version}}
end

Expand Down
18 changes: 13 additions & 5 deletions test/archethic/contracts/interpreter/version0_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule Archethic.Contracts.Interpreter.Version0Test do

alias Archethic.Contracts.Contract

alias Archethic.Contracts.Interpreter
alias Archethic.Contracts.Interpreter.Version0

alias Archethic.TransactionChain.Transaction
Expand All @@ -17,17 +18,17 @@ defmodule Archethic.Contracts.Interpreter.Version0Test do
"""
abc
"""
|> Version0.parse()
|> sanitize_and_parse()

assert {:error, _} =
"""
condition
"""
|> Version0.parse()
|> sanitize_and_parse()
end

test "should return an error for unexpected term" do
assert {:error, "unexpected term - @1 - L1"} = "@1" |> Version0.parse()
assert {:error, "unexpected term - @1 - L1"} = "@1" |> sanitize_and_parse()
end
end

Expand Down Expand Up @@ -55,7 +56,7 @@ defmodule Archethic.Contracts.Interpreter.Version0Test do
end
end
"""
|> Version0.parse()
|> sanitize_and_parse()
end

test "schedule transfers parsing" do
Expand All @@ -72,6 +73,13 @@ defmodule Archethic.Contracts.Interpreter.Version0Test do
add_uco_transfer to: "0000D574D171A484F8DEAC2D61FC3F7CC984BEB52465D69B3B5F670090742CBF5CC", amount: 100000000
end
"""
|> Version0.parse()
|> sanitize_and_parse()
end

defp sanitize_and_parse(code) do
code
|> Interpreter.sanitize_code()
|> elem(1)
|> Version0.parse()
end
end
25 changes: 0 additions & 25 deletions test/archethic/contracts/interpreter_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,4 @@ defmodule Archethic.Contracts.InterpreterTest do
assert {:error, "@version not supported"} = Interpreter.parse(code_v0)
end
end

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

test "should return the correct version if specified" do
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, _} = 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 1.1))
assert :error = Interpreter.version(~s(@version "1.1"))
assert :error = Interpreter.version(~s(@version "1.1.1"))
end
end
end

0 comments on commit ee5cee8

Please sign in to comment.