Compare commits

...

5 commits

Author SHA1 Message Date
Eric Merritt
0ed11ba68c minor whitespace cleanup for ec_semver 2012-09-16 13:11:49 -05:00
Eric Merritt
50fbda3dc8 provide the ability to format a version into a string as well as parse a version 2012-09-16 13:11:47 -05:00
Eric Merritt
fed8522774 make sure the docs get run as part of a bare make 2012-09-16 13:11:46 -05:00
Eric Merritt
aa8b2088cf fixes for edoc compilation 2012-09-16 13:11:44 -05:00
Eric Merritt
0d0edc4461 compilation utilities for the implementors 2012-09-16 13:11:41 -05:00
3 changed files with 157 additions and 7 deletions

View file

@ -16,7 +16,7 @@ ERLWARE_COMMONS_PLT=$(CURDIR)/.erlware_commons_plt
.PHONY: all compile doc clean test dialyzer typer shell distclean pdf get-deps escript .PHONY: all compile doc clean test dialyzer typer shell distclean pdf get-deps escript
all: compile test dialyzer all: compile test doc dialyzer
get-deps: get-deps:
$(REBAR) get-deps $(REBAR) get-deps

107
src/ec_compile.erl Normal file
View file

@ -0,0 +1,107 @@
%%%-------------------------------------------------------------------
%%% @author Eric Merritt <>
%%% @copyright (C) 2011, Erlware, LLC.
%%% @doc
%%% These are various utility functions to help with compiling and
%%% decompiling erlang source. They are mostly useful to the
%%% language/parse transform implementor.
%%% @end
%%%-------------------------------------------------------------------
-module(ec_compile).
-export([beam_to_erl_source/2,
erl_source_to_core_ast/1,
erl_source_to_erl_ast/1,
erl_source_to_asm/1,
erl_string_to_core_ast/1,
erl_string_to_erl_ast/1,
erl_string_to_asm/1]).
%%%===================================================================
%%% API
%%%===================================================================
%% @doc decompile a beam file that has been compiled with +debug_info
%% into a erlang source file
%%
%% @param BeamFName the name of the beamfile
%% @param ErlFName the name of the erlang file where the generated
%% source file will be output. This should *not* be the same as the
%% source file that created the beamfile unless you want to overwrite
%% it.
-spec beam_to_erl_source(string(), string()) -> ok | term().
beam_to_erl_source(BeamFName, ErlFName) ->
case beam_lib:chunks(BeamFName, [abstract_code]) of
{ok, {_, [{abstract_code, {raw_abstract_v1,Forms}}]}} ->
Src =
erl_prettypr:format(erl_syntax:form_list(tl(Forms))),
{ok, Fd} = file:open(ErlFName, [write]),
io:fwrite(Fd, "~s~n", [Src]),
file:close(Fd);
Error ->
Error
end.
%% @doc compile an erlang source file into a Core Erlang AST
%%
%% @param Path - The path to the erlang source file
-spec erl_source_to_core_ast(file:filename()) -> CoreAst::term().
erl_source_to_core_ast(Path) ->
{ok, Contents} = file:read_file(Path),
erl_string_to_core_ast(binary_to_list(Contents)).
%% @doc compile an erlang source file into an Erlang AST
%%
%% @param Path - The path to the erlang source file
-spec erl_source_to_erl_ast(file:filename()) -> ErlangAst::term().
erl_source_to_erl_ast(Path) ->
{ok, Contents} = file:read_file(Path),
erl_string_to_erl_ast(binary_to_list(Contents)).
%% @doc compile an erlang source file into erlang terms that represent
%% the relevant ASM
%%
%% @param Path - The path to the erlang source file
-spec erl_source_to_asm(file:filename()) -> ErlangAsm::term().
erl_source_to_asm(Path) ->
{ok, Contents} = file:read_file(Path),
erl_string_to_asm(binary_to_list(Contents)).
%% @doc compile a string representing an erlang expression into an
%% Erlang AST
%%
%% @param StringExpr - The path to the erlang source file
-spec erl_string_to_erl_ast(string()) -> ErlangAst::term().
erl_string_to_erl_ast(StringExpr) ->
Forms0 =
lists:foldl(fun(<<>>, Acc) ->
Acc;
(<<"\n\n">>, Acc) ->
Acc;
(El, Acc) ->
{ok, Tokens, _} =
erl_scan:string(binary_to_list(El)
++ "."),
[Tokens | Acc]
end, [], re:split(StringExpr, "\\.\n")),
%% No need to reverse. This will rereverse for us
lists:foldl(fun(Form, Forms) ->
{ok, ErlAST} = erl_parse:parse_form(Form),
[ErlAST | Forms]
end, [], Forms0).
%% @doc compile a string representing an erlang expression into a
%% Core Erlang AST
%%
%% @param StringExpr - The path to the erlang source file
-spec erl_string_to_core_ast(string()) -> CoreAst::term().
erl_string_to_core_ast(StringExpr) ->
compile:forms(erl_string_to_erl_ast(StringExpr), [to_core]).
%% @doc compile a string representing an erlang expression into a term
%% that represents the ASM
%%
%% @param StringExpr - The path to the erlang source file
-spec erl_string_to_asm(string()) -> ErlangAsm::term().
erl_string_to_asm(StringExpr) ->
compile:forms(erl_string_to_erl_ast(StringExpr), ['S']).

View file

@ -8,6 +8,7 @@
-module(ec_semver). -module(ec_semver).
-export([parse/1, -export([parse/1,
format/1,
eql/2, eql/2,
gt/2, gt/2,
gte/2, gte/2,
@ -54,6 +55,24 @@ parse(Version) when erlang:is_binary(Version) ->
parse(Version) -> parse(Version) ->
Version. Version.
-spec format(semver()) -> iolist().
format({Maj, {AlphaPart, BuildPart}})
when erlang:is_integer(Maj) ->
[erlang:integer_to_list(Maj),
format_vsn_rest(<<"-">>, AlphaPart),
format_vsn_rest(<<"+">>, BuildPart)];
format({{Maj, Min}, {AlphaPart, BuildPart}}) ->
[erlang:integer_to_list(Maj), ".",
erlang:integer_to_list(Min),
format_vsn_rest(<<"-">>, AlphaPart),
format_vsn_rest(<<"+">>, BuildPart)];
format({{Maj, Min, Patch}, {AlphaPart, BuildPart}}) ->
[erlang:integer_to_list(Maj), ".",
erlang:integer_to_list(Min), ".",
erlang:integer_to_list(Patch),
format_vsn_rest(<<"-">>, AlphaPart),
format_vsn_rest(<<"+">>, BuildPart)].
%% @doc test for quality between semver versions %% @doc test for quality between semver versions
-spec eql(any_version(), any_version()) -> boolean(). -spec eql(any_version(), any_version()) -> boolean().
eql(VsnA, VsnB) -> eql(VsnA, VsnB) ->
@ -141,8 +160,8 @@ between(Vsn1, Vsn2, VsnMatch) ->
%% revisions and "~> 2.6.5" is pessimistic about future minor %% revisions and "~> 2.6.5" is pessimistic about future minor
%% revisions. %% revisions.
%% %%
%% "~> 2.6" matches cookbooks >= 2.6.0 AND < 3.0.0 %% "~> 2.6" matches cookbooks >= 2.6.0 AND &lt; 3.0.0
%% "~> 2.6.5" matches cookbooks >= 2.6.5 AND < 2.7.0 %% "~> 2.6.5" matches cookbooks >= 2.6.5 AND &lt; 2.7.0
pes(VsnA, VsnB) -> pes(VsnA, VsnB) ->
internal_pes(parse(VsnA), parse(VsnB)). internal_pes(parse(VsnA), parse(VsnB)).
@ -189,6 +208,19 @@ format_alpha_part([<<".">>, AlphaPart]) ->
%%%=================================================================== %%%===================================================================
%%% Internal Functions %%% Internal Functions
%%%=================================================================== %%%===================================================================
-spec to_list(integer() | binary() | string()) -> string().
to_list(Detail) when erlang:is_integer(Detail) ->
erlang:integer_to_list(Detail);
to_list(Detail) ->
Detail.
-spec format_vsn_rest(binary() | string(), [integer() | binary()]) -> iolist().
format_vsn_rest(_TypeMark, []) ->
[];
format_vsn_rest(TypeMark, [Head | Rest]) ->
[TypeMark, Head |
[[".", to_list(Detail)] || Detail <- Rest]].
%% @doc normalize the semver so they can be compared %% @doc normalize the semver so they can be compared
-spec normalize(semver()) -> semver(). -spec normalize(semver()) -> semver().
normalize({Vsn, Rest}) normalize({Vsn, Rest})
@ -212,9 +244,6 @@ internal_pes(VsnA, {{LM, LMI, LP}, _}) ->
internal_pes(Vsn, LVsn) -> internal_pes(Vsn, LVsn) ->
gte(Vsn, LVsn). gte(Vsn, LVsn).
%%%=================================================================== %%%===================================================================
%%% Test Functions %%% Test Functions
%%%=================================================================== %%%===================================================================
@ -242,7 +271,6 @@ eql_test() ->
?assertMatch(true, not eql("1.0.0+build.1", ?assertMatch(true, not eql("1.0.0+build.1",
"1.0.1+build.2")). "1.0.1+build.2")).
gt_test() -> gt_test() ->
?assertMatch(true, gt("1.0.0-alpha.1", ?assertMatch(true, gt("1.0.0-alpha.1",
"1.0.0-alpha")), "1.0.0-alpha")),
@ -523,4 +551,19 @@ pes_test() ->
?assertMatch(true, not pes("2.7", "2.6.5")), ?assertMatch(true, not pes("2.7", "2.6.5")),
?assertMatch(true, not pes("2.5", "2.6.5")). ?assertMatch(true, not pes("2.5", "2.6.5")).
version_format_test() ->
?assertEqual(["1", [], []], format({1, {[],[]}})),
?assertEqual(["1", ".", "2", ".", "34", [], []], format({{1,2,34},{[],[]}})),
?assertEqual(<<"1">>, erlang:iolist_to_binary(format({1, {[],[]}}))),
?assertEqual(<<"1.2">>, erlang:iolist_to_binary(format({{1,2}, {[],[]}}))),
?assertEqual(<<"1.2.2">>, erlang:iolist_to_binary(format({{1,2,2}, {[],[]}}))),
?assertEqual(<<"1.99.2">>, erlang:iolist_to_binary(format({{1,99,2}, {[],[]}}))),
?assertEqual(<<"1.99.2-alpha">>, erlang:iolist_to_binary(format({{1,99,2}, {["alpha"],[]}}))),
?assertEqual(<<"1.99.2-alpha.1">>, erlang:iolist_to_binary(format({{1,99,2}, {["alpha",1], []}}))),
?assertEqual(<<"1.99.2+build.1.a36">>,
erlang:iolist_to_binary(format({{1,99,2}, {[], ["build", 1, "a36"]}}))),
?assertEqual(<<"1.99.2-alpha.1+build.1.a36">>,
erlang:iolist_to_binary(format({{1,99,2}, {["alpha", 1], ["build", 1, "a36"]}}))),
?assertEqual(<<"1">>, erlang:iolist_to_binary(format({1, {[],[]}}))).
-endif. -endif.