Skip to content

Instantly share code, notes, and snippets.

@takahashim
Last active January 3, 2016 10:39
Show Gist options
  • Save takahashim/8451126 to your computer and use it in GitHub Desktop.
Save takahashim/8451126 to your computer and use it in GitHub Desktop.
%% name = ReVIEW::Compiler::Literals
%% header {
##
# Provides Literals appropriate for your ruby version.
#--
# This set of literals is for Ruby 1.8 regular expressions.
}
Alphanumeric = /[0-9A-Za-z\200-\377]/n
AlphanumericAscii = /[A-Za-z0-9]/
LowerAlphabetAscii = /[a-z]/
Digit = /[0-9]/
BOM = "\357\273\277"
Newline = /\n|\r\n?/
NonAlphanumeric = /[\000-\057\072-\100\133-\140\173-\177]/n
Spacechar = / |\t/
%% name = ReVIEW::Compiler::Literals
%% header {
# coding: UTF-8
##
#--
# This set of literals is for Ruby 1.9 regular expressions and gives full
# unicode support.
#
# Unlike peg-markdown, this set of literals recognizes Unicode alphanumeric
# characters, newlines and spaces.
}
Alphanumeric = /\p{Word}/
AlphanumericAscii = /[A-Za-z0-9]/
LowerAlphabetAscii = /[a-z]/
Digit = /[0-9]/
BOM = "\uFEFF"
Newline = /\n|\r\n?|\p{Zl}|\p{Zp}/
NonAlphanumeric = /\p{^Word}/
Spacechar = /\t|\p{Zs}/
%% name = ReVIEW::Compiler
%% {
if RUBY_VERSION > '1.9' then
require_relative 'literals_1_9.kpeg'
else
require_relative 'literals_1_8.kpeg'
end
##
# Creates extension methods for the `name` extension to enable and disable
# the extension and to query if they are active.
attr_reader :strategy
class SyntaxElement
def initialize(name, type, argc, &block)
@name = name
@type = type
@argc_spec = argc
@checker = block
end
attr_reader :name
def check_args(args)
unless @argc_spec === args.size
raise CompileError, "wrong # of parameters (block command //#{@name}, expect #{@argc_spec} but #{args.size})"
end
@checker.call(*args) if @checker
end
def min_argc
case @argc_spec
when Range then @argc_spec.begin
when Integer then @argc_spec
else
raise TypeError, "argc_spec is not Range/Integer: #{inspect()}"
end
end
def block_required?
@type == :block
end
def block_allowed?
@type == :block or @type == :optional
end
end
SYNTAX = {}
def self.defblock(name, argc, optional = false, &block)
defsyntax name, (optional ? :optional : :block), argc, &block
end
def self.defsingle(name, argc, &block)
defsyntax name, :line, argc, &block
end
def self.defsyntax(name, type, argc, &block)
SYNTAX[name] = SyntaxElement.new(name, type, argc, &block)
end
def syntax_defined?(name)
SYNTAX.key?(name.to_sym)
end
def syntax_descriptor(name)
SYNTAX[name.to_sym]
end
class InlineSyntaxElement
def initialize(name)
@name = name
end
attr_reader :name
end
INLINE = {}
def self.definline(name)
INLINE[name] = InlineSyntaxElement.new(name)
end
def inline_defined?(name)
INLINE.key?(name.to_sym)
end
defblock :read, 0
defblock :lead, 0
defblock :list, 2
defblock :emlist, 0..1
defblock :cmd, 0..1
defblock :table, 0..2
defblock :quote, 0
defblock :image, 2..3, true
defblock :source, 0..1
defblock :listnum, 2
defblock :emlistnum, 0..1
defblock :bibpaper, 2..3, true
defblock :doorquote, 1
defblock :talk, 0
defblock :texequation, 0
defblock :graph, 1..3
defblock :address, 0
defblock :blockquote, 0
defblock :bpo, 0
defblock :flushright, 0
defblock :centering, 0
defblock :note, 0..1
defblock :box, 0..1
defblock :comment, 0..1, true
defsingle :footnote, 2
defsingle :noindent, 0
defsingle :linebreak, 0
defsingle :pagebreak, 0
defsingle :indepimage, 1..3
defsingle :numberlessimage, 1..3
defsingle :hr, 0
defsingle :parasep, 0
defsingle :label, 1
defsingle :raw, 1
defsingle :tsize, 1
defsingle :include, 1
defsingle :olnum, 1
definline :chapref
definline :chap
definline :title
definline :img
definline :icon
definline :list
definline :table
definline :fn
definline :kw
definline :ruby
definline :bou
definline :ami
definline :b
definline :dtp
definline :code
definline :bib
definline :hd
definline :href
definline :recipe
definline :abbr
definline :acronym
definline :cite
definline :dfn
definline :em
definline :kbd
definline :q
definline :samp
definline :strong
definline :var
definline :big
definline :small
definline :del
definline :ins
definline :sup
definline :sub
definline :tt
definline :i
definline :tti
definline :ttb
definline :u
definline :raw
definline :br
definline :m
definline :uchar
definline :idx
definline :hidx
definline :comment
definline :include
def tagged_section_init
@tagged_section = []
end
def open_tagged_section(tag, args, contents)
mid = "#{tag}_begin"
unless @strategy.respond_to?(mid)
error "strategy does not support tagged section: #{tag}"
return
end
@tagged_section.push [tag, level]
## @strategy.__send__ mid, level, label, caption
puts "@strategy.__send__ #{mid}, #{level}, #{label}, #{caption}"
end
def close_tagged_section(tag, level)
mid = "#{tag}_end"
if @strategy.respond_to?(mid)
@strategy.__send__ mid, level
else
error "strategy does not support block op: #{mid}"
end
end
def compile_command(name, args, lines)
p :compile_command, name,args,lines
# syntax = syntax_descriptor(name)
return ""
unless @strategy.respond_to?(syntax.name)
error "strategy does not support command: //#{syntax.name}"
compile_unknown_command args, lines
return
end
begin
syntax.check_args args
rescue CompileError => err
error err.message
args = ['(NoArgument)'] * syntax.min_argc
end
if syntax.block_allowed?
compile_block syntax, args, lines
else
if lines
error "block is not allowed for command //#{syntax.name}; ignore"
end
compile_single syntax, args
end
end
}
root = Start
Start = &. { tagged_section_init } Block*
## TODO InlineElement の後に Ulist / Olist / Dlist が来ると先頭行じゃなくてマッチできてしまうかも
## using &. to detect EOF
Block = BlankLine*
( SinglelineComment:c
| Headline:headline
| BlockElement:c
| Ulist:c
| Olist:c
| Dlist:c
| Paragraph:c
)
BlankLine = SP Newline
Headline = ( HeadlinePrefix:level BracketArg?:cmd BraceArg?:label Space* SinglelineContent:caption Newline* )
{ puts "@strategy.headline #{level}, #{cmd}, #{label}, #{caption}" }
HeadlinePrefix = < /={1,5}/ > { text.length }
Paragraph = !"=" ParagraphSub+ SP
ParagraphSub = ( InlineElement:c
| < ContentText > { text }
)+:d { d }
ContentText = !Newline !Headline !SinglelineComment !BlockElement !Ulist !Olist !Dlist NonInlineElement+:c Newline? { c }
NonInlineElement = !InlineElement < /[^\r\n]/ > { text }
BlockElement = ( "//" ElementName:symbol BracketArg*:args "{" Newline BlockElementContents?:contents "//}" SP
{ compile_command(symbol, args, contents) }
| "//" ElementName:symbol BracketArg*:args SP
)
InlineElement = "@<" < /[^>\r\n]+/ > {symbol = text} ">" "{" < InlineElementContents? > { contents = text} "}"
{ puts "@<> #{symbol} #{contents}" }
BracketArg = "[" < /([^\r\n\]\\]|\\[^\r\n])*/ > "]" { text }
BraceArg = "{" < /([^\r\n}\\]|\\[^\r\n])*/ > "}" { text }
## contents との差は paragraph を切るか切らないか
BlockElementContents = BlockElementContent+:c SP { c }
## 各要素は Newline で終わらなければならない
BlockElementContent = ( SinglelineComment:c
| BlockElement:c
| Ulist:c
| Olist:c
| Dlist:c
| BlockElementParagraph:c
)
BlockElementParagraph = &. { @blockElem = [] } BlockElementParagraphSub+:c SP { @blockElem }
BlockElementParagraphSub = ( InlineElement:c
| BlockElementContentText:c { @blockElem << c }
)+
BlockElementContentText = ( &. !"//}" !SinglelineComment !BlockElement !Ulist !Olist !Dlist < NonInlineElement+ Newline? > ):c { text }
InlineElementContents = !"}" InlineElementContent+:c
InlineElementContent = ( InlineElement:c
| InlineElementContentText:c
)
InlineElementContentText = ( !InlineElement /[^\r\n}]/ )+
SinglelineContent = ContentInlines:c (Newline | EOF) { c }
ContentInlines = < ContentInline+:c > { text }
ContentInline = ( InlineElement:c
| ContentInlineText+:c
)
ContentInlineText = !InlineElement !Newline .
## * 箇条書き
## 行頭から… の指定がない
Ulist = (UlistElement | SinglelineComment):c Ulist?:cc
UlistElement = " "+ "*"+:level Space* SinglelineContent:text
## 1. 番号付き箇条書き
## 行頭から… の指定がない
Olist = (OlistElement | SinglelineComment):c Olist?:cc
OlistElement = " "+ Digits:n "." Space* SinglelineContent:text
## : 用語リスト
## 行頭から… の指定がない
Dlist = (DlistElement | SinglelineComment):c Dlist?:cc
DlistElement = " "* ":" " " Space* SinglelineContent:text DlistElementContent:content SP
DlistElementContent = /[ \t]+/ SinglelineContent:c
SinglelineComment = "#@" /[^\r\n]+/ Newline? SP { "(skip comment" }
Digits = Digit+
SP = /[ \t\r\n]*/
## Space = /[  \t]/
Space = /[ \t]/
EOF = !.
ElementName = < LowerAlphabetAscii+ > { text }
%literals = ReVIEW::Compiler::Literals
Alphanumeric = %literals.Alphanumeric
AlphanumericAscii = %literals.AlphanumericAscii
LowerAlphabetAscii = %literals.LowerAlphabetAscii
Digit = %literals.Digit
BOM = %literals.BOM
Newline = %literals.Newline
NonAlphanumeric = %literals.NonAlphanumeric
Spacechar = %literals.Spacechar
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment