Created
October 17, 2012 01:00
-
-
Save thomasbrus/3903140 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Parser do | |
import Enum, only: [ | |
take_while: 2, | |
drop_while: 2, | |
split_with: 2, | |
filter: 2 | |
] | |
defp parse(:digit, [48|xs]) do { 0, xs } end | |
defp parse(:digit, [49|xs]) do { 1, xs } end | |
defp parse(:digit, [50|xs]) do { 2, xs } end | |
defp parse(:digit, [51|xs]) do { 3, xs } end | |
defp parse(:digit, [52|xs]) do { 4, xs } end | |
defp parse(:digit, [53|xs]) do { 5, xs } end | |
defp parse(:digit, [54|xs]) do { 6, xs } end | |
defp parse(:digit, [55|xs]) do { 7, xs } end | |
defp parse(:digit, [56|xs]) do { 8, xs } end | |
defp parse(:digit, [57|xs]) do { 9, xs } end | |
defp parse(:number, xs) do | |
{ ts, rs } = split_with xs, fn x -> 48 <= x and x <= 57 end | |
{ list_to_integer(ts), rs } | |
end | |
defp parse(:operator, [43|xs]) do { '+', xs } end | |
defp parse(:operator, [45|xs]) do { '-', xs } end | |
defp parse(:operator, [42|xs]) do { '*', xs } end | |
defp parse(:operator, [47|xs]) do { '/', xs } end | |
defp parse(:opening_parenthese, [40|xs]) do { '(', xs } end | |
defp parse(:closing_parenthese, [41|xs]) do { ')', xs } end | |
defp parse(:scoped_expression, xs) do | |
{ _, r1 } = parse(:opening_parenthese, xs) | |
{ e1, r2 } = parse(:expression, r1) | |
{ op, r3 } = parse(:operator, r2) | |
{ e2, r4 } = parse(:expression, r3) | |
{ _, r5 } = parse(:closing_parenthese, r4) | |
{ [op, [e1, e2]], r5 } | |
end | |
defp parse(:expression, xs) do | |
try do | |
parse(:scoped_expression, xs) | |
rescue | |
FunctionClauseError -> parse(:number, xs) | |
end | |
end | |
def parse(xs) do | |
without_spaces = filter(xs, fn(x) -> x != 32 end) | |
parse(:expression, without_spaces) | |
end | |
end | |
ExUnit.start | |
defmodule ParserTest do | |
use ExUnit.Case | |
test "parsing a number" do | |
assert Parser.parse('1') == { 1, [] } | |
end | |
test "parsing the addition of two numbers" do | |
assert Parser.parse('(1 + 2)') == { ['+', [1, 2]], [] } | |
end | |
test "parsing multiplication of a number with a nested expression" do | |
assert Parser.parse('(1 * (2 + 3))') == { ['*', [1, ['+', [2, 3]]]], [] } | |
end | |
test "parsing the multiplication of two nested expressions" do | |
assert Parser.parse('((1 + 2) * (3 + 4))') == { ['*', [['+', [1, 2]], ['+', [3, 4]]]], [] } | |
end | |
test "parsing deeply nested expressions" do | |
assert Parser.parse('((1 + (2 * 3)) + 4)') == { ['+', [['+', [1, ['*', [2, 3]]]], 4]], [] } | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment