Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: elixir-lang/elixir
base: 37199581e4
...
head fork: elixir-lang/elixir
compare: 834d0c8d28
Checking mergeability… Don't worry, you can still create the pull request.
  • 2 commits
  • 8 files changed
  • 0 commit comments
  • 1 contributor
View
32 lib/macro.ex
@@ -0,0 +1,32 @@
+defmodule Macro do
+ @moduledoc """
+ This module provides conveniences for working with macros.
+ """
+
+ @doc """
+ Escapes the given value so it can be inserted into a syntax
+ tree. Structures that are valid syntax nodes (like atoms,
+ integers, binaries) are represented by themselves.
+
+ ## Examples
+
+ Macro.escape(:foo)
+ #=> :foo
+
+ Macro.escape({ :a, :b, :c })
+ #=> { :{}, 0, [:a, :b, :c] }
+ """
+ def escape({ left, right }) do
+ { escape(left), escape(right) }
+ end
+
+ def escape(tuple) when is_tuple(tuple) do
+ { :{}, 0, escape(tuple_to_list(tuple)) }
+ end
+
+ def escape(list) when is_list(list) do
+ lc item in list, do: escape(item)
+ end
+
+ def escape(other), do: other
+end
View
3  lib/record.ex
@@ -26,6 +26,9 @@ defmodule Record do
# Private endpoint that defines the functions for the Record.
def define_functions(module, values, definition) do
+ # Escape the values so they are valid syntax nodes
+ values = Macro.escape(values)
+
contents = [
reflection(module, values),
getters_and_setters(values, 1, [], definition),
View
1  src/elixir_compiler.erl
@@ -338,6 +338,7 @@ core_main() ->
"lib/list.ex",
"lib/protocol.ex",
"lib/enum.ex",
+ "lib/macro.ex",
"lib/record.ex",
"lib/exception.ex",
"lib/binary/inspect.ex",
View
3  src/elixir_interpolation.erl
@@ -77,8 +77,7 @@ unescape_token(Other, _Map) -> Other.
unescape_chars(String) -> unescape_chars(String, fun unescape_map/1).
-define(to_octal(List),
- { ok, [Integer], [] } = io_lib:fread("~8u", List),
- <<Integer, (unescape_chars(Rest, Map))/binary>>
+ <<(list_to_integer(List, 8))/integer, (unescape_chars(Rest, Map))/binary>>
).
unescape_chars(<<$\\,A,B,C,Rest/binary>>, Map) when ?is_octal(A), ?is_octal(B), ?is_octal(C) ->
View
31 src/elixir_tokenizer.erl
@@ -4,6 +4,9 @@
-import(elixir_interpolation, [unescape_chars/1, unescape_tokens/1]).
-define(is_digit(S), S >= $0 andalso S =< $9).
+-define(is_hex(S), ?is_digit(S) orelse (S >= $A andalso S =< $F)).
+-define(is_bin(S), S >= $0 andalso S =< $1).
+-define(is_octal(S), S >= $0 andalso S =< $7).
-define(is_upcase(S), S >= $A andalso S =< $Z).
-define(is_downcase(S), S >= $a andalso S =< $z).
-define(is_word(S), ?is_digit(S) orelse ?is_upcase(S) orelse ?is_downcase(S)).
@@ -16,6 +19,18 @@ tokenize(_, [], Tokens) ->
% Integers and floats
+tokenize(Line, [$0,$x,H|T], Tokens) when ?is_hex(H) ->
+ { Rest, Number } = tokenize_hex([H|T], []),
+ tokenize(Line, Rest, [{number,Line,Number}|Tokens]);
+
+tokenize(Line, [$0,$o,H|T], Tokens) when ?is_octal(H) ->
+ { Rest, Number } = tokenize_octal([H|T], []),
+ tokenize(Line, Rest, [{number,Line,Number}|Tokens]);
+
+tokenize(Line, [$0,$b,H|T], Tokens) when ?is_bin(H) ->
+ { Rest, Number } = tokenize_bin([H|T], []),
+ tokenize(Line, Rest, [{number,Line,Number}|Tokens]);
+
tokenize(Line, [H|_] = String, Tokens) when ?is_digit(H) ->
{ Rest, Number } = tokenize_number(String, [], false),
tokenize(Line, Rest, [{number,Line,Number}|Tokens]);
@@ -419,11 +434,23 @@ tokenize_number([H|T], Acc, Bool) when ?is_digit(H) ->
% Cast to float...
tokenize_number(Rest, Acc, true) ->
- { Rest, erlang:list_to_float(lists:reverse(Acc)) };
+ { Rest, list_to_float(lists:reverse(Acc)) };
% Or integer.
tokenize_number(Rest, Acc, false) ->
- { Rest, erlang:list_to_integer(lists:reverse(Acc)) }.
+ { Rest, list_to_integer(lists:reverse(Acc)) }.
+
+% Hex
+tokenize_hex([H|T], Acc) when ?is_hex(H) -> tokenize_hex(T, [H|Acc]);
+tokenize_hex(Rest, Acc) -> { Rest, list_to_integer(lists:reverse(Acc), 16) }.
+
+% Octal
+tokenize_octal([H|T], Acc) when ?is_octal(H) -> tokenize_octal(T, [H|Acc]);
+tokenize_octal(Rest, Acc) -> { Rest, list_to_integer(lists:reverse(Acc), 8) }.
+
+% Bin
+tokenize_bin([H|T], Acc) when ?is_bin(H) -> tokenize_bin(T, [H|Acc]);
+tokenize_bin(Rest, Acc) -> { Rest, list_to_integer(lists:reverse(Acc), 2) }.
% Comments
View
2  test/elixir/access_test.exs
@@ -3,7 +3,7 @@ Code.require_file "../test_helper", __FILE__
defmodule Access.TupleTest do
use ExUnit.Case
- defrecord Config, other: { :a, :b }
+ defrecord Config, other: { :a, :b, :c }
test :literal do
assert_equal :a, { :a, :b, :c }[1]
View
22 test/elixir/macro_test.exs
@@ -0,0 +1,22 @@
+Code.require_file "../test_helper", __FILE__
+
+defmodule MacroTest do
+ use ExUnit.Case
+
+ test :escapes_tuples_with_size_different_than_two do
+ assert_equal { :{}, 0, [:a] }, Macro.escape({ :a })
+ assert_equal { :{}, 0, [:a, :b, :c] }, Macro.escape({ :a, :b, :c })
+ end
+
+ test :simply_returns_macros_with_size_equal_to_two do
+ assert_equal { :a, :b }, Macro.escape({ :a, :b })
+ end
+
+ test :returns_any_other_structure do
+ assert_equal [1,2,3], Macro.escape([1,2,3])
+ end
+
+ test :works_recursively do
+ assert_equal [1,{:{}, 0, [:a,:b,:c]},3], Macro.escape([1, { :a, :b, :c },3])
+ end
+end
View
5 test/erlang/tokenizer_test.erl
@@ -12,6 +12,11 @@ arithmetic_test() ->
scientific_test() ->
[{number, 1, 0.1}] = tokenize("1.0e-1").
+hex_bin_octal_test() ->
+ [{number,1,255}] = tokenize("0xFF"),
+ [{number,1,63}] = tokenize("0o77"),
+ [{number,1,3}] = tokenize("0b11").
+
unquoted_atom_test() ->
[{atom, 1, ['+']}] = tokenize(":+"),
[{atom, 1, ['-']}] = tokenize(":-"),

No commit comments for this range

Something went wrong with that request. Please try again.