diff --git a/lib/ex_pression/interpreter.ex b/lib/ex_pression/interpreter.ex index 17bd868..c996eec 100644 --- a/lib/ex_pression/interpreter.ex +++ b/lib/ex_pression/interpreter.ex @@ -20,10 +20,13 @@ defmodule ExPression.Interpreter do args = Enum.map(args, &do_eval(&1, context)) arity = length(args) + # Ensure functions_module is loaded first so its atoms are available + _ = context.functions_module && Code.ensure_loaded?(context.functions_module) + with :ok <- args_find_error(args), {:ok, f_name} <- string_to_existing_atom(name) do cond do - context.functions_module && Code.ensure_loaded?(context.functions_module) && + context.functions_module && Kernel.function_exported?(context.functions_module, f_name, arity) -> safe_fun_call(context.functions_module, f_name, args) diff --git a/lib/ex_pression/parser/grammar.ex b/lib/ex_pression/parser/grammar.ex index 11d1b72..5d5df0b 100644 --- a/lib/ex_pression/parser/grammar.ex +++ b/lib/ex_pression/parser/grammar.ex @@ -8,7 +8,7 @@ defmodule ExPression.Parser.Grammar do def peg do peg Expr do # Space characters - S <- {' ', '\t', '\r', '\n'} + S <- {?\s, ?\t, ?\r, ?\n} # Basic atoms True <- ("True" | "true") * fn cs -> [true | cs] end @@ -16,19 +16,19 @@ defmodule ExPression.Parser.Grammar do Null <- ("None" | "null") * fn cs -> [nil | cs] end # Strings - Xdigit <- {'0'..'9', 'a'..'f', 'A'..'F'} - Unicode_escape <- 'u' * Xdigit[4] - Escape <- '\\' * ({'"', '\\', '/', 'b', 'f', 'n', 'r', 't'} | Unicode_escape) - String_body <- star(Escape) * star(+({'\x20'..'\x7f', 'а'..'я', 'А'..'Я', '\xC2\xA0'..'\xC2\xBF', '\xC3\x80'..'\xC3\xBF'} - {'"'} - {'\\'}) * star(Escape)) - String <- '"' * str(String_body) * '"' + Xdigit <- {?0..?9, ?a..?f, ?A..?F} + Unicode_escape <- {?u} * Xdigit[4] + Escape <- {?\\} * ({?", ?\\, ?/, ?b, ?f, ?n, ?r, ?t} | Unicode_escape) + String_body <- star(Escape) * star(+({?\s..?~, ?а..?я, ?А..?Я, 0xA0..0xBF, 0xC0..0xFF} - {?"} - {?\\}) * star(Escape)) + String <- {?"} * str(String_body) * {?"} # Numbers - Integer <- int(opt('-') * ('0' | {'1'..'9'}) * star({'0'..'9'})) - Float <- float(opt('-') * ('0' | {'1'..'9'}) * star({'0'..'9'}) * (("." * +{'0'..'9'}) | ({'e', 'E'} * opt({'+', '-'}) * +{'0'..'9'}))) + Integer <- int(opt("-") * ("0" | {?1..?9}) * star({?0..?9})) + Float <- float(opt("-") * ("0" | {?1..?9}) * star({?0..?9}) * (("." * +{?0..?9}) | ({?e, ?E} * opt({?+, ?-}) * +{?0..?9}))) KeyWord <- ("None" | "False" | "True" | "false" | "true" | "null" | "or" | "and" | "not") - IdentifierRest <- {'a'..'z', 'A'..'Z', '_', '0'..'9'} - Identifier1 <- {'a'..'z', 'A'..'Z', '_'} * star(IdentifierRest) + IdentifierRest <- {?a..?z, ?A..?Z, ?_, ?0..?9} + Identifier1 <- {?a..?z, ?A..?Z, ?_} * star(IdentifierRest) Identifier <- str((KeyWord * Identifier1) | (!KeyWord * Identifier1)) # Expressions @@ -88,14 +88,14 @@ defmodule ExPression.Parser.Grammar do end end - L5BinOp <- star(S) * str({'+', '-'}) * star(S) * L5 * fn [b, op, a | cs] -> + L5BinOp <- star(S) * str({?+, ?-}) * star(S) * L5 * fn [b, op, a | cs] -> case op do "+" -> [{:+, [a, b]} | cs] "-" -> [{:-, [a, b]} | cs] end end - L6BinOp <- star(S) * str({'*', '/'}) * star(S) * L6 * fn [b, op, a | cs] -> + L6BinOp <- star(S) * str({?*, ?/}) * star(S) * L6 * fn [b, op, a | cs] -> case op do "*" -> [{:*, [a, b]} | cs] "/" -> [{:/, [a, b]} | cs] diff --git a/mix.exs b/mix.exs index 1b62bdb..6d1cc2b 100644 --- a/mix.exs +++ b/mix.exs @@ -16,8 +16,13 @@ defmodule ExPression.MixProject do package: package(), docs: docs(), # Testing - test_coverage: [tool: ExCoveralls], - preferred_cli_env: [ + test_coverage: [tool: ExCoveralls] + ] + end + + def cli do + [ + preferred_envs: [ coveralls: :test, "coveralls.detail": :test, "coveralls.post": :test, @@ -39,7 +44,7 @@ defmodule ExPression.MixProject do # JSON Encode/Decode {:jason, "~> 1.4"}, # PEG parser - {:xpeg2, "~> 0.9.0"}, + {:xpeg2, github: "Houdini/xpeg2", branch: "fix-warnings-2"}, # DEV tools # Test coverage {:excoveralls, "~> 0.18.0", only: :test}, diff --git a/mix.lock b/mix.lock index 264478a..60e3e38 100644 --- a/mix.lock +++ b/mix.lock @@ -1,20 +1,22 @@ %{ - "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, - "credo": {:hex, :credo, "1.7.2", "fdee3a7cb553d8f2e773569181f0a4a2bb7d192e27e325404cc31b354f59d68c", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dd15d6fbc280f6cf9b269f41df4e4992dee6615939653b164ef951f60afcb68e"}, - "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, - "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.31.0", "06eb1dfd787445d9cab9a45088405593dd3bb7fe99e097eaa71f37ba80c7a676", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "5350cafa6b7f77bdd107aa2199fe277acf29d739aba5aee7e865fc680c62a110"}, - "excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"}, - "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, - "glob_ex": {:hex, :glob_ex, "0.1.6", "3a311ade50f6b71d638af660edcc844c3ab4eb2a2c816cfebb73a1d521bb2f9d", [:mix], [], "hexpm", "fda1e90e10f6029bd72967fef0c9891d0d14da89ca7163076e6028bfcb2c42fa"}, - "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, - "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.3", "d684f4bac8690e70b06eb52dad65d26de2eefa44cd19d64a8095e1417df7c8fd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "b78dc853d2e670ff6390b605d807263bf606da3c82be37f9d7f68635bd886fc9"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, - "recode": {:hex, :recode, "0.6.5", "067335c383e807c1a6f5df22a92856f83e852f1acdbedaa2cced52df082dbe25", [:mix], [{:bunt, "~> 0.2", [hex: :bunt, repo: "hexpm", optional: false]}, {:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}], "hexpm", "d03c66c1dd1ca5b19ad14a3a5fbb2218060352e91d4ad7925fb52f1915a4aabe"}, - "rewrite": {:hex, :rewrite, "0.10.0", "5d756b6dc67679e7156ff6055f9654be02dbaeb177aaf1ff6af7ee8da8718248", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.13", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "68d7808cf549e7bf51b0119a8edc14d50970bad479115249030baa580c1d7b50"}, - "sourceror": {:hex, :sourceror, "0.14.1", "c6fb848d55bd34362880da671debc56e77fd722fa13b4dcbeac89a8998fc8b09", [:mix], [], "hexpm", "8b488a219e4c4d7d9ff29d16346fd4a5858085ccdd010e509101e226bbfd8efc"}, - "xpeg2": {:hex, :xpeg2, "0.9.0", "0a91064dfb6b9e3168eaf5d5c8f01a892329941b9e51c93a458b6bce408e4ec5", [:mix], [], "hexpm", "91152bcb0fcaf09284a7ac90ac8c4267491da70d11efcbdb21ce3d3cdb036b5d"}, + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, + "credo": {:hex, :credo, "1.7.16", "a9f1389d13d19c631cb123c77a813dbf16449a2aebf602f590defa08953309d4", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d0562af33756b21f248f066a9119e3890722031b6d199f22e3cf95550e4f1579"}, + "dialyxir": {:hex, :dialyxir, "1.4.7", "dda948fcee52962e4b6c5b4b16b2d8fa7d50d8645bbae8b8685c3f9ecb7f5f4d", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b34527202e6eb8cee198efec110996c25c5898f43a4094df157f8d28f27d9efe"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, + "erlex": {:hex, :erlex, "0.2.8", "cd8116f20f3c0afe376d1e8d1f0ae2452337729f68be016ea544a72f767d9c12", [:mix], [], "hexpm", "9d66ff9fedf69e49dc3fd12831e12a8a37b76f8651dd21cd45fcf5561a8a7590"}, + "escape": {:hex, :escape, "0.4.1", "065164d0d18a70e75092fc71124978e7b50ac99de69748739e48609825ab1c9e", [:mix], [], "hexpm", "867d641d66ffb1afbb1cdf872eff3c21b1af90fec3d21916b1b5eda51e244158"}, + "ex_doc": {:hex, :ex_doc, "0.40.1", "67542e4b6dde74811cfd580e2c0149b78010fd13001fda7cfeb2b2c2ffb1344d", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "bcef0e2d360d93ac19f01a85d58f91752d930c0a30e2681145feea6bd3516e00"}, + "excoveralls": {:hex, :excoveralls, "0.18.5", "e229d0a65982613332ec30f07940038fe451a2e5b29bce2a5022165f0c9b157e", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "523fe8a15603f86d64852aab2abe8ddbd78e68579c8525ae765facc5eae01562"}, + "file_system": {:hex, :file_system, "1.1.1", "31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], "hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"}, + "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, + "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.3", "4252d5d4098da7415c390e847c814bad3764c94a814a0b4245176215615e1035", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "953297c02582a33411ac6208f2c6e55f0e870df7f80da724ed613f10e6706afd"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, + "recode": {:hex, :recode, "0.8.0", "4e324f608fbac8a01794902703ba04fa1aaab25217108410f7a0cdcecdb1027c", [:mix], [{:escape, "~> 0.1", [hex: :escape, repo: "hexpm", optional: false]}, {:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:rewrite, "~> 1.2", [hex: :rewrite, repo: "hexpm", optional: false]}], "hexpm", "c71d24ebb5a460679d55f8e27585f83542787e238f5a317162ee8e77de74ebba"}, + "rewrite": {:hex, :rewrite, "1.2.0", "80220eb14010e175b67c939397e1a8cdaa2c32db6e2e0a9d5e23e45c0414ce21", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "a1cd702bbb9d51613ab21091f04a386d750fc6f4516b81900df082d78b2d8c50"}, + "sourceror": {:hex, :sourceror, "1.10.1", "325753ed460fe9fa34ebb4deda76d57b2e1507dcd78a5eb9e1c41bfb78b7cdfe", [:mix], [], "hexpm", "288f3079d93865cd1e3e20df5b884ef2cb440e0e03e8ae393624ee8a770ba588"}, + "text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"}, + "xpeg2": {:git, "https://github.com/Houdini/xpeg2.git", "42e4a7b3cf36ce35b7b811014aed715c5f641861", [branch: "fix-warnings-2"]}, }