Aetherus

Aetherus

Can I configure Erlang leex module to accept Unicode input?

Hi, all.

I’m recently assigned a task to convert some custom DSL to some sort of custom AST. The first step I’m trying is tokenizing the DSL using Erlang’s leex module (not the “Live EEX” in Phoenix). You can find the documentation here: Erlang -- leex

The problem is that the DSL contains Unicode characters, and whenever I try to tokenize a piece of the DSL code, leex complains about the input is not iodata.

src/my_lexer.xrl

Definitions.

STRING = "[^"]*"

Rules.

{STRING} : {token, {string, TokenLine, token_to_string(TokenChars)}}.

Erlang code.

token_to_string([$"|Chars]) ->
  [$"|Reversed] = lists:reverse(Chars),
  iolist_to_binary(lists:reverse(Reversed)).

iex -S mix

iex> :my_lexer.string('"hello"')
{:ok, {:string, 1, "hello"}, 1}

iex> :my_lexer.string('"你好"')
** (ArgumentError) errors were found at the given arguments:

  * 1st argument: not an iodata term

    :erlang.iolist_to_binary([20320, 22909])
    ./my_lexer.xrl:13: :my_lexer.token_to_string/1
    ./my_lexer.xrl:7: :my_lexer.yyaction/4
    /opt/homebrew/Cellar/erlang/24.0.5/lib/erlang/lib/parsetools-2.3/include/leexinc.hrl:34: :my_lexer.string/4

I noticed that if I compile the regex in unicode mode, it works.

iex> {:ok, regex} = :re.compile('"[^"]*"', [:unicode])
iex> :re.run('"你好"', regex)
{:match, [{0, 8}]}

But it panics when the regex is not compiled in unicode mode

iex> {:ok, regex} = :re.compile('"[^"]*"')
iex> :re.run('"你好"', regex)
** (ArgumentError) errors were found at the given arguments:

  * 1st argument: not an iodata term

    (stdlib 3.15.2) :re.run([34, 20320, 22909, 34], {:re_pattern, 0, 0, 0, <<69, 82, 67, 80, 77, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 34, 0, 34, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...>>})

I guess that’s the cause of the leex problem, but I don’t know how to configure leex so that it compiles regular expressions in unicode mode.

For now, I just escape all non-ASCII characters to things like '\\u1234', and convert them back when tokenizing strings, but this approach messes up the locations of the tokens, and may generate inaccurate error messages. Are there any better solutions?

Thanks! :smiley:

Marked As Solved

kip

kip

ex_cldr Core Team

The issue here isn’t the regex (and I don’t think leex uses the :re engine, I think iirc that it has its own engine). The issue is that iodata can only be:

iodata()	iolist() | binary()
iolist()	maybe_improper_list(byte() | binary() | iolist(), binary() | [])

So your call to iolist_to_binary/1 is what is failing. You can use unicode:characters_to_binary/1 instead, like this:

token_to_string([$"|Chars]) ->
  [$"|Reversed] = lists:reverse(Chars),
  unicode:characters_to_binary(lists:reverse(Reversed)).

I tested on my machine and that appears to work with your input.

Where Next?

Popular in Questions Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New

Other popular topics Top

lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
William
I would like to know that is there any online source for learning Phoenix Framework for building E-Commerce Store? Any advantage on build...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

We're in Beta

About us Mission Statement