Skip to content

Instantly share code, notes, and snippets.

@fooqri
Last active December 11, 2015 08:29
Show Gist options
  • Save fooqri/4573704 to your computer and use it in GitHub Desktop.
Save fooqri/4573704 to your computer and use it in GitHub Desktop.
A simple Ragel example for parsing a markdown styled todo list.
## Tasks
- Go to Whole Foods
- Go to produce section
- get oranges
maybe Mandarine and Valencia
- get avocados
- get squash
maybe buttercup if they have it
- Go to bakery section
- get bagels
- get 12 cupcakes
- Go to Dairy
- get milk
should be organic 2% if they have it
- Pay for items
## Tasks
- Write up a Ragel example for blog
- Create simple example for parsing lists
- Ragel code for a parser
Should provide support for parsing multiple task lists.
It should also support hierarchical task lists
- Create a simple ruby class that uses the parser
- post code as gists
- Write up a blog post describing the use of ragel in the example
- Post to blog
require 'rubygems'
require './mdlist_parser.rb'
class MDList
def initialize(filename)
contents = File.open(filename, 'r') { |f| f.read }
lexer_lists = MDListParser.new(contents.to_str.gsub('\n',"\n"))
puts lexer_lists
lexer_lists.lists.each do |list|
puts "Tasks:"
list[:items].each do |item|
puts "-".rjust(4*item[:level]) + item[:title] + " : (" + item[:level].to_s + ")"
item[:description].split(/\r?\n/).each do |l|
puts " ".rjust(4*item[:level]) + l.strip
end
end
end
end
end
class MDListParser
attr_accessor :lists
%%{
machine test_lexer;
action MarkTaskStart {
task_start = fpc
lists_index += 1
@lists[lists_index] = {:items => []}
item_index=-1
}
action MarkTaskTitleStart {
task_start = fpc
}
action MarkTaskDescriptionStart {
task_start = fpc
item_index=-1
}
action IncrementTaskLevel {
task_level += 1
}
action TaskText {
if data[p]
item_index += 1
@lists[lists_index][:items] << { :type => task_item_type, :level => task_level, :title => data[task_start...p].pack('c*').strip, :description => ""}
task_level = 1
end
}
action TaskDescriptionText {
if data[p]
@lists[lists_index][:items][item_index][:description] = data[task_start...p].pack('c*').strip
task_level = 1
end
}
space_or_tab = " " | [\t];
indent_or_tab = " " | [\t];
task_header = "##" space_or_tab* "Tasks" space_or_tab* [\n];
task_char = (digit+ '.' >{task_item_type = :ordered}) | ('-' >{task_item_type = :unordered});
task_title = [^\n]+ [\n];
task_starter = indent_or_tab* @IncrementTaskLevel task_char;
task_description_line = ([^\n]+ - ^[##]) [\n];
task_description = (task_description_line - task_header)+;
#task_description = (task_description_line)+;
task_item = task_starter space_or_tab* (task_title >MarkTaskTitleStart %TaskText) (task_description* >MarkTaskDescriptionStart %TaskDescriptionText);
task = (task_header >MarkTaskStart) . task_item*;
main := |*
task+;
*|;
}%%
def initialize(data)
%% write data;
data = data.unpack("c*") if(data.is_a?(String))
eof = data.length
@lists = []
token_array = []
task_item_type = ""
lists_index=-1
task_level = 1
fpc = 0
fc = ""
%% write init;
%% write exec;
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment