ityonemo

ityonemo

Pegasus - PEG grammar nimbleparsec generator

Pegasus - Nimbleparsec parser generator

This library converts a PEG parser library to nimbleparsec parsers. You can “hook” extra functions on to the combinators generated by the PEG language.

The PEG language is here:

Unlike yecc/leex, This PEG grammar is extremely easy to read and write, given ABNF descriptions given in most RFCs or other standards documents (e.g. ECMA). This also leverages the extremely effective compile-time nature of the NimbleParsec library.

Most Liked

tj0

tj0

Wow, I didn’t realize I needed this library. Much, much easier to use than regular expressions. PEG seems like it would be an excellent addition to the core library as an alternative to Regex.

The following code is me just messing around trying to get things to work, but I hope it helps someone.

defmodule PegasusExample do
  import NimbleParsec
  require Pegasus
  @moduledoc """

  Examples for PEG parsing.

  PegasusExample.get_pairs("grass=4,horse=1, star=2")

  From https://github.com/xored/peg/blob/master/docs/grammar-examples.md
  PegasusExample.get_timestamp("2009-09-22T06:59:28")
  PegasusExample.get_timestamp("2009-09-22 06:59:28")
  PegasusExample.get_timestamp("Fri Jun 17 03:50:56 PDT 2011")
  PegasusExample.get_timestamp("2010-10-26 10:00:53.360")
  """

  @parser_options [
    Pair: [tag: :pair],
    Word: [tag: :word],
    Number: [tag: :number],
    Space: [ignore: true],
    Separator: [ignore: true],
    Equals: [ignore: true],
  ]
  Pegasus.parser_from_string(
  """
  List <- Pair (Space* Separator Space* Pair)*
  Pair <- Word Equals Number
  Word <- [A-Za-z0-9_]+
  Number <- [0-9]+
  Space           <- ' ' / '\t' / EndOfLine
  EndOfLine       <- '\r\n' / '\n' / '\r'
  EndOfFile       <- !.
  Separator       <- ','
  Equals          <- '='
  """,
  @parser_options
  )
  defparsec :get_pairs, parsec(:List)

  @parser_timestamp [
    Hour: [tag: :hour],
    Minute: [tag: :minute],
    Second: [tag: :second],
    Year: [tag: :year],
    Month: [tag: :month],
    Day: [tag: :day],
    TZ: [tag: :tz],
    Space: [ignore: true],
    Separator: [ignore: true],
    Equals: [ignore: true],
  ]
  Pegasus.parser_from_string(
  """
    Timestamp <- DateTime / FreeDateTime

    # Times
    Hour <- [0-1] [0-9] / '2' [0-4]
    Minute <- [0-5] [0-9]
    Second <- [0-5] [0-9] / '60'
    Fraction <- ('.' / ',') [0-9]+
    IsoTz <- 'Z' / ('+' / '-') Hour (':'? Minute)?
    TzL <- [A-Z]
    TzAbbr <- TzL TzL (TzL (TzL TzL?)?)?
    TZ <- IsoTz / TzAbbr
    HM <- Hour ':' Minute Fraction?
    HMS <- Hour ':' Minute ':' Second Fraction?
    Time <- ('T' ' '?)? (HMS / HM) (' '? TZ)?

    # Dates
    Year <- [0-9] [0-9] [0-9] [0-9]
    Month <- '0' [1-9] / '1' [0-2]
    Day <- '0' [1-9] / [1-2] [0-9] / '3' [0-1]
    Date <- Year '-' Month ('-' Day)?

    # Combined
    DateTime <- Date ' '? Time

    # Free style
    MonthAbbr <- 'Jan' / 'Feb' / 'Mar' / 'Apr' / 'May' / 'Jun' / 'Jul' / 'Aug' / 'Sep' / 'Sept' / 'Oct' / 'Nov' / 'Dec'
    WeekDayAbbr <- 'Mon' / 'Tu' / 'Tue' / 'Tues' / 'Wed' / 'Th' / 'Thu' / 'Thur' / 'Thurs' / 'Fri' / 'Sat' / 'Sun'
    FreeDateTime <- WeekDayAbbr ' ' MonthAbbr ' ' Day ' ' Time ' ' Year
 """,
   @parser_timestamp)
   defparsec :get_timestamp, parsec(:Timestamp)
end

iex>  PegasusExample.get_pairs("grass=4,horse=1, star=2")
{:ok,
 [
   pair: [word: ~c"grass", number: ~c"4"],
   pair: [word: ~c"horse", number: ~c"1"],
   pair: [word: ~c"star", number: ~c"2"]
 ], "", %{}, {1, 0}, 23}

TwistingTwists

TwistingTwists

Wow. Combining PEG grammars with Nimbleparsec is :chef_kiss: :pinched_fingers:

ityonemo

ityonemo

Most of these:

And this:

https://github.com/E-xyza/zig_parser/blob/main/lib/grammar/grammar.y

Where Next?

Popular in Announcing Top

OvermindDL1
Been making an MLElixir thing (not released yet…) for fun in spare time in the past day. I’m just trying to see how much I can get an ML...
132 14347 106
New
OvermindDL1
I created a new library (rather I pulled out a couple files from my big project), it manages an operating system PID file for the BEAM. ...
New
mspanc
I am pleased to announce an initial release of the Membrane Framework - an Elixir-based framework with special focus on processing multim...
New
Qqwy
TypeCheck: Fast and flexible runtime type-checking for your Elixir projects. Core ideas Type- and function specifications are const...
336 14703 100
New
tfwright
After working on it for a couple of months and using it in production for most of that time, today I’ve released LiveAdmin, a LiveView ba...
New
scohen
Lexical Lexical is a next-generation language server for the Elixir programming language. Features Context aware code completion As-you...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 130286 1222
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36654 110
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
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
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement