Skip to content

Instantly share code, notes, and snippets.

@thomasbrus
Created October 17, 2012 01:00
Show Gist options
  • Save thomasbrus/3903140 to your computer and use it in GitHub Desktop.
Save thomasbrus/3903140 to your computer and use it in GitHub Desktop.
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