Skip to content

Commit

Permalink
Added control flow support... wipes forehead
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromegn committed Mar 13, 2016
1 parent 5557664 commit 997027a
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 7 deletions.
18 changes: 18 additions & 0 deletions spec/fixtures/begin-rescue.slang
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
div
- begin
span beginning
- raise Exception.new("yup")
- rescue ex : Exception
span rescued #{ex.message}
- begin
span beginning 2
- array = [] of Int32
- array[2] > 10
- rescue ex : IndexError
span rescued IndexError
- begin
span beginning 3
- rescue
span rescued begin 3
- else
span nothing to rescue
17 changes: 17 additions & 0 deletions spec/fixtures/case-when.slang
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
div
- case "string"
- when "blah"
span \"string\" is \"blah\"
- when false
span \"string\" is false
- when String
span this guy is nested
- if false
span nope
- else
span deeply nested
- if false
- elsif false
- elsif false
- else
span true is just true man
18 changes: 18 additions & 0 deletions spec/fixtures/if-elsif-else.slang
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
div
- if true == false
span true is false
- elsif true != true
span true is not true
- elsif !"blah".is_a?(String)
span blah is a string
- else
span this guy is nested
- if false
span nope
- else
span deeply nested
- if false
- elsif false
- elsif false
- else
span true is just true man
45 changes: 45 additions & 0 deletions spec/slang_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,49 @@ describe Slang do
HTML
end
end

describe "if elsif else" do
it "renders the correct branches" do
res = render_file "spec/fixtures/if-elsif-else.slang"

res.should eq <<-HTML
<div>
<span>this guy is nested</span>
<span>deeply nested</span>
<span>true is just true man</span>
</div>
HTML
end
end

describe "case when" do
it "renders the correct branches" do
res = render_file "spec/fixtures/case-when.slang"

res.should eq <<-HTML
<div>
<span>this guy is nested</span>
<span>deeply nested</span>
<span>true is just true man</span>
</div>
HTML
end
end

describe "begin rescue" do
it "renders the correct branches" do
res = render_file "spec/fixtures/begin-rescue.slang"

res.should eq <<-HTML
<div>
<span>beginning</span>
<span>rescued yup</span>
<span>beginning 2</span>
<span>rescued IndexError</span>
<span>beginning 3</span>
<span>nothing to rescue</span>
</div>
HTML
end
end
end
67 changes: 66 additions & 1 deletion src/slang/nodes/control.cr
Original file line number Diff line number Diff line change
@@ -1,14 +1,79 @@
module Slang
module Nodes
class Control < Node

def branches
@branches ||= [] of Nodes::Control
end
def branches?
!branches.empty?
end

def if?
value.not_nil!.starts_with?("if ")
end
def else?
value.not_nil!.match /^else\s{0,}/
end
def elsif?
value.not_nil!.starts_with?("elsif ")
end

def begin?
value.not_nil!.match(/^begin\s{0,}/)
end
def rescue?
value.not_nil!.match(/^rescue\s{0,}/)
end
def ensure?
value.not_nil!.match /^ensure\s{0,}/
end

def case?
value.not_nil!.starts_with?("case ")
end
def when?
value.not_nil!.starts_with?("when ")
end

def branch?
else? || elsif? || rescue? || when? || ensure?
end
def branchable?
if? || case? || begin?
end

def allow_branch?(branch)
return false unless branch.is_a?(Nodes::Control)
return false unless branchable?
if if?
branch.else? || branch.elsif?
elsif begin?
branch.rescue? || branch.ensure? || branch.else?
elsif case?
branch.when? || branch.else?
else
false
end
end

def endable?
!branch? && children? || branches?
end

def to_s(str, buffer_name)
str << "#{value}\n"
if children?
nodes.each do |node|
node.to_s(str, buffer_name)
end
str << "end\n"
end
if branches?
branches.each do |branch|
branch.to_s(str, buffer_name)
end
end
str << "end\n" if endable?
end
end
end
Expand Down
33 changes: 28 additions & 5 deletions src/slang/parser.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@ module Slang
class Parser
def initialize(string)
@lexer = Lexer.new(string)
@document = Document.new
@current_node = @document
@control_nodes_per_column = {} of Int32 => Nodes::Control
next_token
end

def parse(io_name = Slang::DEFAULT_BUFFER_NAME)
document = Document.new
@current_node = document
String.build do |str|
loop do
# puts token.inspect
case token.type
when :EOF
break
when :NEWLINE
next_token
when :DOCTYPE
document.nodes << Nodes::Doctype.new(document, token)
@document.nodes << Nodes::Doctype.new(@document, token)
next_token
when :ELEMENT, :TEXT, :HTML, :COMMENT, :CONTROL, :OUTPUT
parent = @current_node.not_nil!
Expand All @@ -35,14 +37,35 @@ module Slang
else
Nodes::Text.new(parent, token)
end
parent.not_nil!.nodes << node

# puts node.inspect
# puts @control_nodes_per_column[node.column_number]?

if node.is_a?(Nodes::Control)
if @control_nodes_per_column[node.column_number]?
last_control_node = @control_nodes_per_column[node.column_number]
# puts "LAST CONTROL NODE"
# puts last_control_node.inspect
if last_control_node.allow_branch?(node)
last_control_node.branches << node
else
@control_nodes_per_column[node.column_number] = node
parent.not_nil!.nodes << node
end
else
@control_nodes_per_column[node.column_number] = node
parent.not_nil!.nodes << node
end
else
parent.not_nil!.nodes << node
end
@current_node = node
next_token
else
unexpected_token
end
end
document.to_s(str, io_name)
@document.to_s(str, io_name)
end
end

Expand Down
2 changes: 1 addition & 1 deletion src/slang/version.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Slang
VERSION = "1.0.1"
VERSION = "1.1.0"
end

0 comments on commit 997027a

Please sign in to comment.