Skip to content

Instantly share code, notes, and snippets.

@jackalcooper
Created December 10, 2022 02:01
Show Gist options
  • Save jackalcooper/d4ed087872a24bff9e73f48e141bbf7b to your computer and use it in GitHub Desktop.
Save jackalcooper/d4ed087872a24bff9e73f48e141bbf7b to your computer and use it in GitHub Desktop.
defmodule Kinda.ParserHelper do
@moduledoc false
@doc """
define a parser combinator and variable with same name
"""
defmacro defcv(name, expr) do
quote do
defcombinatorp(unquote(name), unquote(expr))
Kernel.var!(unquote({name, [], nil})) = parsec(unquote(name))
_ = Kernel.var!(unquote({name, [], nil}))
end
end
end
defmodule Kinda.Parser do
import NimbleParsec
import Kinda.ParserHelper
# *** forward declare ***
expr = parsec(:expr)
typeexpr = parsec(:typeexpr)
assignexpr = parsec(:assignexpr)
stringlist = parsec(:stringlist)
asminputlist = parsec(:asminputlist)
asmoutputlist = parsec(:asmoutputlist)
ifexpr = parsec(:ifexpr)
ptrpayload = parsec(:ptrpayload)
slicetypestart = parsec(:slicetypestart)
bytealign = parsec(:bytealign)
ptrtypestart = parsec(:ptrtypestart)
arraytypestart = parsec(:arraytypestart)
exprlist = parsec(:exprlist)
containermembers = parsec(:containermembers)
loopexpr = parsec(:loopexpr)
block = parsec(:block)
statement = parsec(:statement)
containerdeclarations = parsec(:containerdeclarations)
topleveldecl = parsec(:topleveldecl)
# *** Tokens ***
defcv(
:container_doc_comment,
string("//!")
|> repeat(ascii_char([?^, ?\n]))
|> repeat(ascii_char([?\s, ?\n]))
|> times(min: 1)
)
defcv(
:doc_comment,
string("///")
|> repeat(ascii_char([?^, ?\n]))
|> repeat(ascii_char([?\s, ?\n]))
|> times(min: 1)
)
defcv(
:line_comment,
choice([
string("//") |> lookahead_not(ascii_char([?!, ?/])) |> repeat(ascii_char([?^, ?\n])),
string("////") |> lookahead_not(ascii_char([?\n])) |> repeat(ascii_char([?^, ?\n]))
])
)
defcv(:skip, choice([ascii_char([?\s, ?\n]), line_comment]) |> repeat)
defcv(
:builtinidentifier,
string("@")
|> ascii_char([?A..?Z, ?a..?z, ?_])
|> concat(ascii_char([?A..?Z, ?a..?z, ?0..?9, ?_]) |> repeat)
|> concat(skip)
)
defcv(:ampersand, string("&") |> lookahead_not(ascii_char([?=])) |> concat(skip))
defcv(:ampersandequal, string("&=") |> concat(skip))
defcv(
:asterisk,
string("*") |> lookahead_not(ascii_char([?*, ?%, ?=])) |> concat(skip)
)
defcv(:asterisk2, string("**") |> concat(skip))
defcv(:asteriskequal, string("*=") |> concat(skip))
defcv(
:asteriskpercent,
string("*%") |> lookahead_not(ascii_char([?=])) |> concat(skip)
)
defcv(:asteriskpercentequal, string("*%=") |> concat(skip))
defcv(:caret, string("^") |> lookahead_not(ascii_char([?=])) |> concat(skip))
defcv(:caretequal, string("^=") |> concat(skip))
defcv(:colon, string(":") |> concat(skip))
defcv(:comma, string(",") |> concat(skip))
defcv(:dot, string(".") |> lookahead_not(ascii_char([?*, ?., ??])) |> concat(skip))
defcv(:dot2, string("..") |> lookahead_not(ascii_char([?.])) |> concat(skip))
defcv(:dot3, string("...") |> concat(skip))
defcv(:dotasterisk, string(".*") |> concat(skip))
defcv(:dotquestionmark, string(".?") |> concat(skip))
defcv(:equal, string("=") |> lookahead_not(ascii_char([?>, ?=])) |> concat(skip))
defcv(:equalequal, string("==") |> concat(skip))
defcv(:equalrarrow, string("=>") |> concat(skip))
defcv(:exclamationmark, string("!") |> lookahead_not(ascii_char([?=])) |> concat(skip))
defcv(:exclamationmarkequal, string("!=") |> concat(skip))
defcv(:larrow, string("<") |> lookahead_not(ascii_char([?<, ?=])) |> concat(skip))
defcv(:larrow2, string("<<") |> lookahead_not(ascii_char([?=])) |> concat(skip))
defcv(:larrow2equal, string("<<=") |> concat(skip))
defcv(:larrowequal, string("<=") |> concat(skip))
defcv(:lbrace, string("{") |> concat(skip))
defcv(:lbracket, string("[") |> concat(skip))
defcv(:lparen, string("(") |> concat(skip))
defcv(:minus, string("-") |> lookahead_not(ascii_char([?%, ?=, ?>])) |> concat(skip))
defcv(:minusequal, string("-=") |> concat(skip))
defcv(:minuspercent, string("-%") |> lookahead_not(ascii_char([?=])) |> concat(skip))
defcv(:minuspercentequal, string("-%=") |> concat(skip))
defcv(:minusrarrow, string("->") |> concat(skip))
defcv(:percent, string("%") |> lookahead_not(ascii_char([?=])) |> concat(skip))
defcv(:percentequal, string("%=") |> concat(skip))
defcv(:pipe, string("|") |> lookahead_not(ascii_char([?|, ?=])) |> concat(skip))
defcv(:pipe2, string("||") |> concat(skip))
defcv(:pipeequal, string("|=") |> concat(skip))
defcv(:plus, string("+") |> lookahead_not(ascii_char([?%, ?+, ?=])) |> concat(skip))
defcv(:plus2, string("++") |> concat(skip))
defcv(:plusequal, string("+=") |> concat(skip))
defcv(:pluspercent, string("+%") |> lookahead_not(ascii_char([?=])) |> concat(skip))
defcv(:pluspercentequal, string("+%=") |> concat(skip))
defcv(:letterc, string("c") |> concat(skip))
defcv(:questionmark, string("?") |> concat(skip))
defcv(:rarrow, string(">") |> lookahead_not(ascii_char([?>, ?=])) |> concat(skip))
defcv(:rarrow2, string(">>") |> lookahead_not(ascii_char([?=])) |> concat(skip))
defcv(:rarrow2equal, string(">>=") |> concat(skip))
defcv(:rarrowequal, string(">=") |> concat(skip))
defcv(:rbrace, string("}") |> concat(skip))
defcv(:rbracket, string("]") |> concat(skip))
defcv(:rparen, string(")") |> concat(skip))
defcv(:semicolon, string(";") |> concat(skip))
defcv(:slash, string("/") |> lookahead_not(ascii_char([?=])) |> concat(skip))
defcv(:slashequal, string("/=") |> concat(skip))
defcv(:tilde, string("~") |> concat(skip))
defcv(
:end_of_word,
lookahead_not(ascii_char([?a..?z, ?A..?Z, ?0..?9, ?_])) |> concat(skip)
)
defcv(:keyword_align, string("align") |> concat(end_of_word))
defcv(:keyword_allowzero, string("allowzero") |> concat(end_of_word))
defcv(:keyword_and, string("and") |> concat(end_of_word))
defcv(:keyword_anyframe, string("anyframe") |> concat(end_of_word))
defcv(:keyword_anytype, string("anytype") |> concat(end_of_word))
defcv(:keyword_asm, string("asm") |> concat(end_of_word))
defcv(:keyword_async, string("async") |> concat(end_of_word))
defcv(:keyword_await, string("await") |> concat(end_of_word))
defcv(:keyword_break, string("break") |> concat(end_of_word))
defcv(:keyword_callconv, string("callconv") |> concat(end_of_word))
defcv(:keyword_catch, string("catch") |> concat(end_of_word))
defcv(:keyword_comptime, string("comptime") |> concat(end_of_word))
defcv(:keyword_const, string("const") |> concat(end_of_word))
defcv(:keyword_continue, string("continue") |> concat(end_of_word))
defcv(:keyword_defer, string("defer") |> concat(end_of_word))
defcv(:keyword_else, string("else") |> concat(end_of_word))
defcv(:keyword_enum, string("enum") |> concat(end_of_word))
defcv(:keyword_errdefer, string("errdefer") |> concat(end_of_word))
defcv(:keyword_error, string("error") |> concat(end_of_word))
defcv(:keyword_export, string("export") |> concat(end_of_word))
defcv(:keyword_extern, string("extern") |> concat(end_of_word))
defcv(:keyword_fn, string("fn") |> concat(end_of_word))
defcv(:keyword_for, string("for") |> concat(end_of_word))
defcv(:keyword_if, string("if") |> concat(end_of_word))
defcv(:keyword_inline, string("inline") |> concat(end_of_word))
defcv(:keyword_noalias, string("noalias") |> concat(end_of_word))
defcv(:keyword_nosuspend, string("nosuspend") |> concat(end_of_word))
defcv(:keyword_noinline, string("noinline") |> concat(end_of_word))
defcv(:keyword_opaque, string("opaque") |> concat(end_of_word))
defcv(:keyword_or, string("or") |> concat(end_of_word))
defcv(:keyword_orelse, string("orelse") |> concat(end_of_word))
defcv(:keyword_packed, string("packed") |> concat(end_of_word))
defcv(:keyword_pub, string("pub") |> concat(end_of_word))
defcv(:keyword_resume, string("resume") |> concat(end_of_word))
defcv(:keyword_return, string("return") |> concat(end_of_word))
defcv(:keyword_linksection, string("linksectio") |> concat(end_of_word))
defcv(:keyword_struct, string("struct") |> concat(end_of_word))
defcv(:keyword_suspend, string("suspend") |> concat(end_of_word))
defcv(:keyword_switch, string("switch") |> concat(end_of_word))
defcv(:keyword_test, string("test") |> concat(end_of_word))
defcv(:keyword_threadlocal, string("threadloca") |> concat(end_of_word))
defcv(:keyword_try, string("try") |> concat(end_of_word))
defcv(:keyword_union, string("union") |> concat(end_of_word))
defcv(:keyword_unreachable, string("unreachabl") |> concat(end_of_word))
defcv(:keyword_usingnamespace, string("usingnamespac") |> concat(end_of_word))
defcv(:keyword_var, string("var") |> concat(end_of_word))
defcv(:keyword_volatile, string("volatile") |> concat(end_of_word))
defcv(:keyword_while, string("while") |> concat(end_of_word))
defcv(
:keyword,
choice([
keyword_align,
keyword_allowzero,
keyword_and,
keyword_anyframe,
keyword_anytype,
keyword_asm,
keyword_async,
keyword_await,
keyword_break,
keyword_callconv,
keyword_catch,
keyword_comptime,
keyword_const,
keyword_continue,
keyword_defer,
keyword_else,
keyword_enum,
keyword_errdefer,
keyword_error,
keyword_export,
keyword_extern,
keyword_fn,
keyword_for,
keyword_if,
keyword_inline,
keyword_noalias,
keyword_nosuspend,
keyword_noinline,
keyword_opaque,
keyword_or,
keyword_orelse,
keyword_packed,
keyword_pub,
keyword_resume,
keyword_return,
keyword_linksection,
keyword_struct,
keyword_suspend,
keyword_switch,
keyword_test,
keyword_threadlocal,
keyword_try,
keyword_union,
keyword_unreachable,
keyword_usingnamespace,
keyword_var,
keyword_volatile,
keyword_while
])
)
defcv(:eof, eos())
defcv(:bin, ascii_char([?0..?1]))
defcv(:bin_, optional(string("_")) |> concat(bin))
defcv(:oct, ascii_char([?0..?7]))
defcv(:oct_, optional(string("_")) |> concat(oct))
defcv(:hex, ascii_char([?0..?9, ?a..?f, ?A..?F]))
defcv(:hex_, optional(string("_")) |> concat(hex))
defcv(:dec, ascii_char([?0..?9]))
defcv(:dec_, optional(string("_")) |> concat(dec))
defcv(:bin_int, bin |> concat(repeat(bin_)))
defcv(:oct_int, oct |> concat(repeat(oct_)))
defcv(:dec_int, dec |> concat(repeat(dec_)))
defcv(:hex_int, hex |> concat(repeat(hex_)))
defcv(:mb_utf8_literal, utf8_char([]))
defcv(
:ascii_char_not_nl_slash_squote,
ascii_char([0..11, 13..46, 46..50, 50..133, 135..177])
)
defcv(
:char_escape,
choice([
string("\\x") |> concat(hex) |> concat(hex),
string("\\u") |> concat(times(hex, min: 1)) |> concat(string("}")),
string("\\") |> concat(hex) |> concat(ascii_char([?n, ?r, ?\\, ?t, ?', ?"]))
])
)
defcv(
:char_char,
choice([
mb_utf8_literal,
char_escape,
ascii_char_not_nl_slash_squote
])
)
defcv(:string_char, choice([char_escape, ascii_char([?^, ?\\, ?", ?\n])]))
defcv(
:line_string,
string("\\\\")
|> concat(ascii_char([?^, ?\n]) |> repeat)
|> concat(ascii_char([?\s, ?\n]) |> repeat)
|> repeat
)
defcv(:char_literal, string("'") |> concat(char_char) |> string("'") |> concat(skip))
defcv(
:float,
choice([
string("0x")
|> concat(hex_int)
|> string(".")
|> concat(hex_int)
|> optional(ascii_char([?p, ?P]) |> optional(ascii_char([?-, ?+])) |> concat(hex_int))
|> concat(skip),
dec_int
|> string(".")
|> concat(dec_int)
|> optional(ascii_char([?e, ?E]) |> optional(ascii_char([?-, ?+])) |> concat(dec_int))
|> concat(skip),
string("0x")
|> concat(hex_int)
|> ascii_char([?p, ?P])
|> optional(ascii_char([?-, ?+]))
|> concat(dec_int)
|> concat(skip),
dec_int
|> ascii_char([?e, ?E])
|> optional(ascii_char([?-, ?+]))
|> concat(dec_int)
|> concat(skip)
])
)
defcv(
:integer,
choice([
string("0b") |> concat(bin_int) |> concat(skip),
string("0o") |> concat(oct_int) |> concat(skip),
string("0x") |> concat(hex_int) |> concat(skip),
dec_int |> concat(skip)
])
)
defcv(
:stringliteralsingle,
string("\"") |> concat(repeat(string_char)) |> concat(string("\"")) |> concat(skip)
)
defcv(
:stringliteral,
choice([
stringliteralsingle,
line_string |> concat(skip) |> times(min: 1)
])
)
defcv(
:identifier,
choice([
lookahead_not(keyword)
|> concat(ascii_char([?a..?z, ?A..?Z, ?_]))
|> concat(ascii_char([?A..?Z, ?a..?z, ?0..?9, ?_]) |> repeat)
|> concat(skip),
string("@\"") |> concat(string_char |> repeat) |> concat(string("\"")) |> concat(skip)
])
)
# *** assembly ***
defcv(:asmclobbers, colon |> concat(stringlist))
defcv(:asminput, colon |> concat(asminputlist) |> optional(asmclobbers))
defcv(:asmoutput, colon |> concat(asmoutputlist) |> optional(asminput))
defcv(
:asmexpr,
keyword_asm
|> optional(keyword_volatile)
|> concat(lparen)
|> concat(expr)
|> optional(asmoutput)
|> concat(rparen)
)
defcv(
:asmoutputitem,
lbracket
|> concat(identifier)
|> concat(rbracket)
|> concat(stringliteral)
|> concat(lparen)
|> concat(minusrarrow |> choice([typeexpr, identifier]))
|> concat(rparen)
)
defcv(
:asminputitem,
lbracket
|> concat(identifier)
|> concat(rbracket)
|> concat(stringliteral)
|> concat(lparen)
|> concat(expr)
|> concat(rparen)
)
# *** helper grammar ***
defcv(:breaklabel, colon |> concat(identifier))
defcv(:blocklabel, identifier |> concat(colon))
defcv(:fieldinit, dot |> concat(identifier) |> concat(equal) |> concat(expr))
defcv(
:whilecontinueexpr,
colon |> concat(lparen) |> concat(assignexpr) |> concat(rparen)
)
defcv(
:linksection,
keyword_linksection |> concat(lparen) |> concat(expr) |> concat(rparen)
)
# fn specific
defcv(:callconv, keyword_callconv |> concat(lparen) |> concat(expr) |> concat(rparen))
defcv(:paramtype, choice([keyword_anytype, typeexpr]))
defcv(
:paramdecl,
choice([
optional(doc_comment)
|> optional(choice([keyword_noalias, keyword_comptime]))
|> optional(identifier |> concat(colon))
|> concat(paramtype),
dot3
])
)
# control flow prefixes
defcv(
:ifprefix,
keyword_if |> concat(lparen) |> concat(expr) |> concat(rparen) |> optional(ptrpayload)
)
defcv(
:whileprefix,
keyword_while
|> concat(lparen)
|> concat(expr)
|> concat(rparen)
|> optional(ptrpayload)
|> optional(whilecontinueexpr)
)
defcv(
:ptrindexpayload,
pipe
|> optional(asterisk)
|> concat(identifier)
|> optional(comma |> concat(identifier))
|> concat(pipe)
)
defcv(
:forprefix,
keyword_for |> concat(lparen) |> concat(expr) |> concat(rparen) |> concat(ptrindexpayload)
)
# payloads
defcv(:payload, pipe |> concat(identifier) |> concat(pipe))
defcv(:ptrpayload, pipe |> optional(asterisk) |> concat(identifier) |> concat(pipe))
# switch specific
defcv(:switchitem, expr |> optional(dot3 |> concat(expr)))
defcv(
:switchcase,
choice([
switchitem |> repeat(comma |> concat(switchitem)) |> optional(comma),
keyword_else
])
)
defcv(
:switchprong,
switchcase |> concat(equalrarrow) |> optional(ptrpayload) |> concat(assignexpr)
)
# operators
defcv(
:assignop,
choice([
asteriskequal,
slashequal,
percentequal,
plusequal,
minusequal,
larrow2equal,
rarrow2equal,
ampersandequal,
caretequal,
pipeequal,
asteriskpercentequal,
pluspercentequal,
minuspercentequal,
equal
])
)
defcv(
:compareop,
choice([
equalequal,
exclamationmarkequal,
larrow,
rarrow,
larrowequal,
rarrowequal
])
)
defcv(
:bitwiseop,
choice([ampersand, caret, pipe, keyword_orelse, keyword_catch |> optional(payload)])
)
defcv(:bitshiftop, choice([larrow2, rarrow2]))
defcv(
:additionop,
choice([
plus,
minus,
plus2,
pluspercent,
minuspercent
])
)
defcv(
:multiplyop,
choice([
pipe2,
asterisk,
slash,
percent,
asterisk2,
asteriskpercent
])
)
defcv(
:prefixop,
choice([
exclamationmark,
minus,
tilde,
minuspercent,
ampersand,
keyword_try,
keyword_await
])
)
defcv(
:prefixtypeop,
choice([
questionmark,
keyword_anyframe |> concat(minusrarrow),
slicetypestart
|> repeat(choice([bytealign, keyword_const, keyword_volatile, keyword_allowzero])),
ptrtypestart
|> repeat(
keyword_align
|> concat(lparen)
|> concat(expr)
|> optional(colon |> concat(integer) |> concat(colon) |> concat(integer))
|> choice([rparen, keyword_const, keyword_volatile, keyword_allowzero])
),
arraytypestart
])
)
defcv(
:suffixop,
choice([
lbracket
|> concat(expr)
|> optional(dot2 |> optional(optional(expr) |> optional(colon |> concat(expr))))
|> concat(rbracket),
dot |> concat(identifier),
dotasterisk,
dotquestionmark
])
)
defcv(:fncallarguments, lparen |> concat(exprlist) |> concat(rparen))
# ptr specific
defcv(:slicetypestart, lbracket |> optional(colon |> concat(expr)) |> concat(rbracket))
defcv(
:ptrtypestart,
choice([
asterisk,
asterisk2,
lbracket
|> concat(asterisk)
|> optional(choice([letterc, colon |> concat(expr)]))
|> concat(rbracket)
])
)
defcv(
:arraytypestart,
lbracket |> concat(expr) |> optional(colon |> concat(expr)) |> concat(rbracket)
)
# containerdecl specific
defcv(
:containerdecltype,
choice([
keyword_struct,
keyword_opaque,
keyword_enum |> optional(lparen |> concat(expr) |> concat(rparen)),
keyword_union
|> optional(
lparen
|> concat(
keyword_enum
|> choice([optional(lparen |> concat(expr) |> concat(rparen)), expr])
)
|> concat(rparen)
)
])
)
defcv(
:containerdeclauto,
containerdecltype
|> concat(lbrace)
|> optional(container_doc_comment)
|> concat(containermembers)
|> concat(rbrace)
)
# alignment
defcv(:bytealign, keyword_align |> concat(lparen) |> concat(expr) |> concat(rparen))
# lists
defcv(
:identifierlist,
repeat(optional(doc_comment) |> concat(identifier) |> concat(comma))
|> optional(optional(doc_comment) |> concat(identifier))
)
defcv(:switchpronglist, repeat(switchprong |> concat(comma)) |> optional(switchprong))
defcv(
:asmoutputlist,
repeat(asmoutputitem |> concat(comma)) |> optional(asmoutputitem)
)
defcv(:asminputlist, repeat(asminputitem |> concat(comma)) |> optional(asminputitem))
defcv(:stringlist, repeat(stringliteral |> concat(comma)) |> optional(stringliteral))
defcv(:paramdecllist, repeat(paramdecl |> concat(comma)) |> optional(paramdecl))
defcv(:exprlist, repeat(expr |> concat(comma)) |> optional(expr))
# *** expression level ***
defcv(
:initlist,
choice([
lbrace
|> concat(fieldinit)
|> repeat(comma |> concat(fieldinit))
|> optional(comma)
|> concat(rbrace),
lbrace
|> concat(expr)
|> repeat(comma |> concat(expr))
|> optional(comma)
|> concat(rbrace),
lbrace |> concat(rbrace)
])
)
defcv(:curlysuffixexpr, typeexpr |> optional(initlist))
defcv(
:primaryexpr,
choice([
asmexpr,
ifexpr,
keyword_break |> optional(breaklabel) |> optional(expr),
keyword_comptime |> concat(expr),
keyword_nosuspend |> concat(expr),
keyword_continue |> optional(breaklabel),
keyword_resume |> concat(expr),
keyword_return |> optional(expr),
optional(blocklabel) |> concat(loopexpr),
block,
curlysuffixexpr
])
)
defcv(:prefixexpr, repeat(prefixop) |> concat(primaryexpr))
defcv(:multiplyexpr, prefixexpr |> optional(multiplyop |> concat(prefixexpr)))
defcv(:additionexpr, multiplyexpr |> optional(additionop |> concat(multiplyexpr)))
defcv(:bitshiftexpr, additionexpr |> optional(bitshiftop |> concat(additionexpr)))
defcv(:bitwiseexpr, bitshiftexpr |> optional(bitwiseop |> concat(bitshiftexpr)))
defcv(:compareexpr, bitwiseexpr |> optional(compareop |> concat(bitwiseexpr)))
defcv(:boolandexpr, compareexpr |> optional(keyword_and |> concat(compareexpr)))
defcv(:boolorexpr, boolandexpr |> optional(keyword_or |> concat(boolandexpr)))
defcv(:expr, boolorexpr)
defcv(:assignexpr, expr |> optional(assignop |> concat(expr)))
defcv(
:ifexpr,
ifprefix |> concat(expr) |> optional(keyword_else |> optional(payload) |> concat(expr))
)
defcv(:block, lbrace |> repeat(statement) |> concat(rbrace))
defcv(:forexpr, forprefix |> concat(expr) |> optional(keyword_else |> concat(expr)))
defcv(
:whileexpr,
whileprefix |> concat(expr) |> optional(keyword_else |> optional(payload) |> concat(expr))
)
defcv(:loopexpr, optional(keyword_inline) |> choice([forexpr, whileexpr]))
defcv(
:containerdecl,
optional(choice([keyword_extern, keyword_packed])) |> concat(containerdeclauto)
)
defcv(
:errorsetdecl,
keyword_error |> concat(lbrace) |> concat(identifierlist) |> concat(rbrace)
)
defcv(
:fnproto,
keyword_fn
|> optional(identifier)
|> concat(lparen)
|> concat(paramdecllist)
|> concat(rparen)
|> optional(bytealign)
|> optional(linksection)
|> optional(callconv)
|> optional(exclamationmark)
|> concat(typeexpr)
)
defcv(:groupedexpr, lparen |> concat(expr) |> concat(rparen))
defcv(
:fortypeexpr,
forprefix |> concat(typeexpr) |> optional(keyword_else |> concat(typeexpr))
)
defcv(
:whiletypeexpr,
whileprefix
|> concat(typeexpr)
|> optional(keyword_else |> optional(payload) |> concat(typeexpr))
)
defcv(:looptypeexpr, optional(keyword_inline) |> choice([fortypeexpr, whiletypeexpr]))
defcv(
:labeledtypeexpr,
choice([
blocklabel |> concat(block),
optional(blocklabel) |> concat(looptypeexpr)
])
)
defcv(
:iftypeexpr,
ifprefix
|> concat(typeexpr)
|> optional(keyword_else |> optional(payload) |> concat(typeexpr))
)
defcv(
:switchexpr,
keyword_switch
|> concat(lparen)
|> concat(expr)
|> concat(rparen)
|> concat(lbrace)
|> concat(switchpronglist)
|> concat(rbrace)
)
defcv(
:primarytypeexpr,
choice([
builtinidentifier |> concat(fncallarguments),
char_literal,
containerdecl,
dot |> concat(identifier),
dot |> concat(initlist),
errorsetdecl,
float,
fnproto,
groupedexpr,
labeledtypeexpr,
identifier,
iftypeexpr,
integer,
keyword_comptime |> concat(typeexpr),
keyword_error |> concat(dot) |> concat(identifier),
keyword_anyframe,
keyword_unreachable,
stringliteral,
switchexpr
])
)
defcv(
:suffixexpr,
choice([
keyword_async |> concat(primarytypeexpr) |> repeat(suffixop) |> concat(fncallarguments),
primarytypeexpr |> repeat(choice([suffixop, fncallarguments]))
])
)
defcv(:errorunionexpr, suffixexpr |> optional(exclamationmark |> concat(typeexpr)))
defcv(:typeexpr, repeat(prefixtypeop) |> concat(errorunionexpr))
# *** Top level ***
defcv(
:testdecl,
optional(doc_comment)
|> concat(keyword_test)
|> concat(optional(stringliteralsingle))
|> concat(block)
)
defcv(
:toplevelcomptime,
optional(doc_comment) |> concat(keyword_comptime) |> concat(block)
)
defcv(
:containerdeclarations,
choice([
testdecl |> concat(containerdeclarations),
toplevelcomptime |> concat(containerdeclarations),
optional(doc_comment)
|> optional(keyword_pub)
|> concat(topleveldecl)
|> concat(containerdeclarations)
])
)
defcv(
:containerfield,
optional(doc_comment)
|> optional(keyword_comptime)
|> concat(identifier)
|> optional(colon |> concat(typeexpr) |> optional(bytealign))
|> optional(equal |> concat(expr))
)
defcv(
:containermembers,
containerdeclarations
|> repeat(containerfield |> concat(comma))
|> choice([containerfield, containerdeclarations])
)
defcv(
:vardecl,
choice([keyword_const, keyword_var])
|> concat(identifier)
|> optional(colon |> concat(typeexpr))
|> optional(bytealign)
|> optional(linksection)
|> optional(equal |> concat(expr))
|> concat(semicolon)
)
defcv(
:topleveldecl,
choice([
choice([
keyword_export,
keyword_extern |> optional(stringliteralsingle),
choice([keyword_inline, keyword_noinline])
])
|> optional
|> concat(fnproto)
|> choice([semicolon, block]),
choice([keyword_export, keyword_extern |> optional(stringliteralsingle)])
|> optional
|> optional(keyword_threadlocal)
|> concat(vardecl),
keyword_usingnamespace |> concat(expr) |> concat(semicolon)
])
)
# *** block level ***
defcv(:blockexpr, optional(blocklabel) |> concat(block))
defcv(:blockexprstatement, choice([blockexpr, assignexpr |> concat(semicolon)]))
defcv(
:ifstatement,
choice([
ifprefix
|> concat(blockexpr)
|> optional(keyword_else |> optional(payload) |> concat(statement)),
ifprefix
|> concat(assignexpr)
|> choice([semicolon, keyword_else |> optional(payload) |> concat(statement)])
])
)
defcv(
:forstatement,
choice([
forprefix |> concat(blockexpr) |> optional(keyword_else |> concat(statement)),
forprefix |> concat(assignexpr) |> choice([semicolon, keyword_else |> concat(statement)])
])
)
defcv(
:whilestatement,
choice([
whileprefix
|> concat(blockexpr)
|> optional(keyword_else |> optional(payload) |> concat(statement)),
whileprefix
|> concat(assignexpr)
|> choice([semicolon, keyword_else |> optional(payload) |> concat(statement)])
])
)
defcv(
:loopstatement,
optional(keyword_inline) |> choice([forstatement, whilestatement])
)
defcv(:labeledstatement, optional(blocklabel) |> choice([block, loopstatement]))
defcv(
:statement,
choice([
optional(keyword_comptime) |> concat(vardecl),
keyword_comptime |> concat(blockexprstatement),
keyword_nosuspend |> concat(blockexprstatement),
keyword_suspend |> concat(blockexprstatement),
keyword_defer |> concat(blockexprstatement),
keyword_errdefer |> optional(payload) |> concat(blockexprstatement),
ifstatement,
labeledstatement,
switchexpr,
assignexpr |> concat(semicolon)
])
)
defcv(
:root,
skip |> optional(container_doc_comment) |> concat(containermembers) |> concat(eof)
)
defparsec(:zig_src, root, debug: true)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment