Skip to content

Commit 997027a

Browse files
committed
Added control flow support... wipes forehead
1 parent 5557664 commit 997027a

7 files changed

Lines changed: 193 additions & 7 deletions

File tree

spec/fixtures/begin-rescue.slang

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
div
2+
- begin
3+
span beginning
4+
- raise Exception.new("yup")
5+
- rescue ex : Exception
6+
span rescued #{ex.message}
7+
- begin
8+
span beginning 2
9+
- array = [] of Int32
10+
- array[2] > 10
11+
- rescue ex : IndexError
12+
span rescued IndexError
13+
- begin
14+
span beginning 3
15+
- rescue
16+
span rescued begin 3
17+
- else
18+
span nothing to rescue

spec/fixtures/case-when.slang

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
div
2+
- case "string"
3+
- when "blah"
4+
span \"string\" is \"blah\"
5+
- when false
6+
span \"string\" is false
7+
- when String
8+
span this guy is nested
9+
- if false
10+
span nope
11+
- else
12+
span deeply nested
13+
- if false
14+
- elsif false
15+
- elsif false
16+
- else
17+
span true is just true man

spec/fixtures/if-elsif-else.slang

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
div
2+
- if true == false
3+
span true is false
4+
- elsif true != true
5+
span true is not true
6+
- elsif !"blah".is_a?(String)
7+
span blah is a string
8+
- else
9+
span this guy is nested
10+
- if false
11+
span nope
12+
- else
13+
span deeply nested
14+
- if false
15+
- elsif false
16+
- elsif false
17+
- else
18+
span true is just true man

spec/slang_spec.cr

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,49 @@ describe Slang do
9898
HTML
9999
end
100100
end
101+
102+
describe "if elsif else" do
103+
it "renders the correct branches" do
104+
res = render_file "spec/fixtures/if-elsif-else.slang"
105+
106+
res.should eq <<-HTML
107+
<div>
108+
<span>this guy is nested</span>
109+
<span>deeply nested</span>
110+
<span>true is just true man</span>
111+
</div>
112+
HTML
113+
end
114+
end
115+
116+
describe "case when" do
117+
it "renders the correct branches" do
118+
res = render_file "spec/fixtures/case-when.slang"
119+
120+
res.should eq <<-HTML
121+
<div>
122+
<span>this guy is nested</span>
123+
<span>deeply nested</span>
124+
<span>true is just true man</span>
125+
</div>
126+
HTML
127+
end
128+
end
129+
130+
describe "begin rescue" do
131+
it "renders the correct branches" do
132+
res = render_file "spec/fixtures/begin-rescue.slang"
133+
134+
res.should eq <<-HTML
135+
<div>
136+
<span>beginning</span>
137+
<span>rescued yup</span>
138+
<span>beginning 2</span>
139+
<span>rescued IndexError</span>
140+
<span>beginning 3</span>
141+
<span>nothing to rescue</span>
142+
</div>
143+
HTML
144+
end
145+
end
101146
end

src/slang/nodes/control.cr

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,79 @@
11
module Slang
22
module Nodes
33
class Control < Node
4+
5+
def branches
6+
@branches ||= [] of Nodes::Control
7+
end
8+
def branches?
9+
!branches.empty?
10+
end
11+
12+
def if?
13+
value.not_nil!.starts_with?("if ")
14+
end
15+
def else?
16+
value.not_nil!.match /^else\s{0,}/
17+
end
18+
def elsif?
19+
value.not_nil!.starts_with?("elsif ")
20+
end
21+
22+
def begin?
23+
value.not_nil!.match(/^begin\s{0,}/)
24+
end
25+
def rescue?
26+
value.not_nil!.match(/^rescue\s{0,}/)
27+
end
28+
def ensure?
29+
value.not_nil!.match /^ensure\s{0,}/
30+
end
31+
32+
def case?
33+
value.not_nil!.starts_with?("case ")
34+
end
35+
def when?
36+
value.not_nil!.starts_with?("when ")
37+
end
38+
39+
def branch?
40+
else? || elsif? || rescue? || when? || ensure?
41+
end
42+
def branchable?
43+
if? || case? || begin?
44+
end
45+
46+
def allow_branch?(branch)
47+
return false unless branch.is_a?(Nodes::Control)
48+
return false unless branchable?
49+
if if?
50+
branch.else? || branch.elsif?
51+
elsif begin?
52+
branch.rescue? || branch.ensure? || branch.else?
53+
elsif case?
54+
branch.when? || branch.else?
55+
else
56+
false
57+
end
58+
end
59+
60+
def endable?
61+
!branch? && children? || branches?
62+
end
63+
464
def to_s(str, buffer_name)
565
str << "#{value}\n"
666
if children?
767
nodes.each do |node|
868
node.to_s(str, buffer_name)
969
end
10-
str << "end\n"
1170
end
71+
if branches?
72+
branches.each do |branch|
73+
branch.to_s(str, buffer_name)
74+
end
75+
end
76+
str << "end\n" if endable?
1277
end
1378
end
1479
end

src/slang/parser.cr

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,23 @@ module Slang
22
class Parser
33
def initialize(string)
44
@lexer = Lexer.new(string)
5+
@document = Document.new
6+
@current_node = @document
7+
@control_nodes_per_column = {} of Int32 => Nodes::Control
58
next_token
69
end
710

811
def parse(io_name = Slang::DEFAULT_BUFFER_NAME)
9-
document = Document.new
10-
@current_node = document
1112
String.build do |str|
1213
loop do
14+
# puts token.inspect
1315
case token.type
1416
when :EOF
1517
break
1618
when :NEWLINE
1719
next_token
1820
when :DOCTYPE
19-
document.nodes << Nodes::Doctype.new(document, token)
21+
@document.nodes << Nodes::Doctype.new(@document, token)
2022
next_token
2123
when :ELEMENT, :TEXT, :HTML, :COMMENT, :CONTROL, :OUTPUT
2224
parent = @current_node.not_nil!
@@ -35,14 +37,35 @@ module Slang
3537
else
3638
Nodes::Text.new(parent, token)
3739
end
38-
parent.not_nil!.nodes << node
40+
41+
# puts node.inspect
42+
# puts @control_nodes_per_column[node.column_number]?
43+
44+
if node.is_a?(Nodes::Control)
45+
if @control_nodes_per_column[node.column_number]?
46+
last_control_node = @control_nodes_per_column[node.column_number]
47+
# puts "LAST CONTROL NODE"
48+
# puts last_control_node.inspect
49+
if last_control_node.allow_branch?(node)
50+
last_control_node.branches << node
51+
else
52+
@control_nodes_per_column[node.column_number] = node
53+
parent.not_nil!.nodes << node
54+
end
55+
else
56+
@control_nodes_per_column[node.column_number] = node
57+
parent.not_nil!.nodes << node
58+
end
59+
else
60+
parent.not_nil!.nodes << node
61+
end
3962
@current_node = node
4063
next_token
4164
else
4265
unexpected_token
4366
end
4467
end
45-
document.to_s(str, io_name)
68+
@document.to_s(str, io_name)
4669
end
4770
end
4871

src/slang/version.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module Slang
2-
VERSION = "1.0.1"
2+
VERSION = "1.1.0"
33
end

0 commit comments

Comments
 (0)