Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

add initial grammar

  • Loading branch information...
commit c68a351ade37c68733dc464a98c8761a69c727a8 1 parent 3a9c845
@vito authored
Showing with 193 additions and 0 deletions.
  1. +1 −0  .rbenv-version
  2. +3 −0  Gemfile
  3. +189 −0 grammar.kpeg
View
1  .rbenv-version
@@ -0,0 +1 @@
+rbx
View
3  Gemfile
@@ -0,0 +1,3 @@
+source "https://rubygems.org"
+
+gem "kpeg"
View
189 grammar.kpeg
@@ -0,0 +1,189 @@
+%% name = Atomy::Grammar
+
+%% number = ast Number(value)
+%% literal = ast Literal(value)
+%% quote = ast Quote(node)
+%% quasiquote = ast QuasiQuote(node)
+%% unquote = ast Unquote(node)
+%% constant = ast Constant(text)
+%% word = ast Word(text)
+%% prefix = ast Prefix(node, operator)
+%% postfix = ast Postfix(node, operator)
+%% infix = ast Infix(left, right, operator)
+%% block = ast Block(nodes)
+%% list = ast List(nodes)
+%% compose = ast Compose(left, right)
+%% application = ast Apply(node, arguments)
+%% strliteral = ast StringLiteral(value, raw)
+
+%%{
+ def current_position(target = pos)
+ cur_offset = 0
+ cur_line = 0
+
+ line_lengths.each do |len|
+ cur_line += 1
+ return [cur_line, target - cur_offset] if cur_offset + len > target
+ cur_offset += len
+ end
+
+ [cur_line, cur_offset]
+ end
+
+ def line_lengths
+ @line_lengths ||= lines.collect { |l| l.size }
+ end
+
+ def current_line(x = pos)
+ current_position(x)[0]
+ end
+
+ def current_column(x = pos)
+ current_position(x)[1]
+ end
+
+ def continue?(x)
+ y = current_position
+ y[0] >= x[0] && y[1] > x[1]
+ end
+}
+
+ root = shebang? wsp expressions:es wsp !. { Array(es) }
+ shebang = "#!" /.*?$/
+
+
+ expressions = ~current_column:c expression:x (delim(c) expression)*:xs {
+ [x] + Array(xs)
+ }
+ delim(c) = (wsp "," wsp) | (sp "\n" sp)+ &{ current_column >= c }
+
+
+ expression = level4
+ one_expression = wsp expression:e wsp !. { e }
+
+
+ sp = (" " | "\t" | comment)*
+ wsp = (" " | "\t" | "\n" | comment)*
+ sig_sp = (" " | "\t" | comment)+
+ sig_wsp = (" " | "\t" | "\n" | comment)+
+
+ cont(p) = ("\n" sp)+ &{ continue?(p) }
+ | sig_sp cont(p)?
+ | !"(" # allows 'foo: bar', but ensures '(x)(y)' is an Apply
+
+
+ op_letter = < /[$+<=>^|~!@#%&*\-\\.\/\?]/u > { text.to_sym }
+
+ operator = < op_letter+ > { text.to_sym }
+
+ identifier = < /[a-z_][a-zA-Z\d\-_]*/u > { text.tr("-", "_").to_sym }
+
+ grouped = "(" wsp expression:x wsp ")" { x }
+
+
+ comment = /--.*?$/ | multi_comment
+ multi_comment = "{-" in_multi
+ in_multi = /[^\-\{\}]*/ "-}"
+ | /[^\-\{\}]*/ "{-" in_multi /[^\-\{\}]*/ "-}"
+ | /[^\-\{\}]*/ /[-{}]/ in_multi
+
+
+ level0 = number
+ | quote
+ | quasi_quote
+ | unquote
+ | string
+ | constant
+ | word
+ | block
+ | list
+ | prefix
+ level1 = apply
+ | grouped
+ | level0
+ level2 = postfix
+ | level1
+ level3 = compose
+ | level2
+ level4 = language
+ | infix
+ | level3
+
+
+ language = "#language" wsp identifier:n ~set_lang(n) %lang.root
+
+
+ number = < /[\+\-]?0[oO][0-7]+/ > ~number(text.to_i(8))
+ | < /[\+\-]?0[xX][\da-fA-F]+/ > ~number(text.to_i(16))
+ | < /[\+\-]?\d+(\.\d+)?[eE][\+\-]?\d+/ > ~literal(text.to_f)
+ | < /[\+\-]?\d+\.\d+/ > ~literal(text.to_f)
+ | < /[\+\-]?\d+/ > ~literal(text.to_i)
+
+
+ quote = "'" level2:e ~quote(e)
+ quasi_quote = "`" level2:e ~quasiquote(e)
+ unquote = "~" level2:e ~unquote(e)
+
+
+ constant = < /[A-Z][a-zA-Z0-9_]*/ > ~constant(text.to_sym)
+
+
+ word = identifier:n ~word(n)
+
+
+ prefix = op_letter:o level2:e ~prefix(e, o)
+
+
+ postfix = postfix:e op_letter:o ~postfix(e, o)
+ | level1:e op_letter:o ~postfix(e, o)
+
+
+ block = ":" wsp expressions?:es (wsp ";")? ~block(Array(es))
+ | "{" wsp expressions?:es wsp "}" ~block(Array(es))
+
+
+ list = "[" wsp expressions?:es wsp "]" ~list(Array(es))
+
+
+ compose = @composes(current_position)
+ composes(p) = compose:l cont(p) level2:r ~compose(l, r)
+ | level2:l cont(p) level2:r ~compose(l, r)
+
+
+ infix = @infixes(current_position)
+ infixes(p) = level3:l cont(p) operator:o cont(p) level3:r ~infix(l, r, o)
+ | operator:o cont(p) level3:r ~infix(nil, r, o)
+
+
+ apply = apply:a args:as ~application(a, as)
+ | name:n args:as ~application(n, as)
+ name = name:n op_letter:o ~postfix(n, o)
+ | grouped
+ | level0
+ args = "(" wsp expressions?:as wsp ")" { Array(as) }
+
+
+ string = "\"" < (("\\" escape) | str_seq)*:c > "\""
+ ~strliteral(c.join, text.gsub("\\\"", "\""))
+ str_seq = < /[^\\"]+/ > { text }
+ escape = number_escapes | escapes
+ escapes = "n" { "\n" } | "s" { " " } | "r" { "\r" }
+ | "t" { "\t" } | "v" { "\v" } | "f" { "\f" }
+ | "b" { "\b" } | "a" { "\a" } | "e" { "\e" }
+ | "\\" { "\\" } | "\"" { "\"" } | "BS" { "\b" }
+ | "HT" { "\t" } | "LF" { "\n" } | "VT" { "\v" }
+ | "FF" { "\f" } | "CR" { "\r" } | "SO" { "\016" }
+ | "SI" { "\017" } | "EM" { "\031" } | "FS" { "\034" }
+ | "GS" { "\035" } | "RS" { "\036" } | "US" { "\037" }
+ | "SP" { " " } | "NUL" { "\000" } | "SOH" { "\001" }
+ | "STX" { "\002" } | "ETX" { "\003" } | "EOT" { "\004" }
+ | "ENQ" { "\005" } | "ACK" { "\006" } | "BEL" { "\a" }
+ | "DLE" { "\020" } | "DC1" { "\021" } | "DC2" { "\022" }
+ | "DC3" { "\023" } | "DC4" { "\024" } | "NAK" { "\025" }
+ | "SYN" { "\026" } | "ETB" { "\027" } | "CAN" { "\030" }
+ | "SUB" { "\032" } | "ESC" { "\e" } | "DEL" { "\177" }
+ | < . > { "\\" + text }
+ number_escapes = /[xX]/ < /[0-9a-fA-F]{1,5}/ > { [text.to_i(16)].pack("U") }
+ | < /\d{1,6}/ > { [text.to_i].pack("U") }
+ | /[oO]/ < /[0-7]{1,7}/ > { [text.to_i(16)].pack("U") }
+ | /[uU]/ < /[0-9a-fA-F]{4}/ > { [text.to_i(16)].pack("U") }
Please sign in to comment.
Something went wrong with that request. Please try again.