rblade 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d9ff80cf4efc20f03172676c57e11c4fe325d5ce304cf855416a4b6d119a654a
4
+ data.tar.gz: 7283baf017d3b28a4609160551bc265f27355bb501d2f42a9303fe1bb825e837
5
+ SHA512:
6
+ metadata.gz: dce7d4c704f87acab8e1b2d9999acca4fd77aa5739845fa82417304e5223d6fed5dc5be5a52dc46fe003546635907346029ddc995656b6773bb63aaba19ab90e
7
+ data.tar.gz: 9336ac0fdb096d3d6c05992916db5bbb594e965ac4c036e99f86b65dd77062842b42f825979fa3b013b84a35f2d8913c3ef6a43a0ec3163cc2c491da521a16bb
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ storage
2
+ Gemfile.lock
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ ignore:
2
+ - storage/**/*
3
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "minitest/test_task"
2
+ require "standard/rake"
3
+
4
+ Minitest::TestTask.create
5
+
6
+ task default: "test"
data/do ADDED
@@ -0,0 +1,94 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ if [ -z "$DOCKER_COMPOSE_COMMAND" ]
5
+ then
6
+ DOCKER_COMPOSE_COMMAND="docker compose"
7
+ fi
8
+
9
+ if [ -z "$1" ]
10
+ then
11
+ echo "Usage:"
12
+ echo "./do run [command] - run a command"
13
+ exit 1
14
+ fi
15
+
16
+ if [ "$1" == "build" ] || [ "$1" == "b" ]
17
+ then
18
+ echo Running: ${DOCKER_COMPOSE_COMMAND} build
19
+ ${DOCKER_COMPOSE_COMMAND} build
20
+ exit 0
21
+ fi
22
+
23
+ if [ "$1" == "up" ] || [ "$1" == "u" ]
24
+ then
25
+ echo Running: ${DOCKER_COMPOSE_COMMAND} up -d --remove-orphans
26
+ ${DOCKER_COMPOSE_COMMAND} up -d --remove-orphans
27
+ exit 0
28
+ fi
29
+
30
+ if [ "$1" == "down" ] || [ "$1" == "d" ]
31
+ then
32
+ echo Running: ${DOCKER_COMPOSE_COMMAND} down "${@:2}"
33
+ ${DOCKER_COMPOSE_COMMAND} down "${@:2}"
34
+ exit 0
35
+ fi
36
+
37
+ if [ "$1" == "restart" ] || [ "$1" == "rs" ]
38
+ then
39
+ echo Running: ${DOCKER_COMPOSE_COMMAND} restart "${@:2}"
40
+ ${DOCKER_COMPOSE_COMMAND} restart "${@:2}"
41
+ exit 0
42
+ fi
43
+
44
+ if [ "$1" == "run" ] || [ "$1" == "r" ]
45
+ then
46
+ echo Running: ${DOCKER_COMPOSE_COMMAND} run blade ${@:2}
47
+ ${DOCKER_COMPOSE_COMMAND} run blade "${@:2}"
48
+ exit 0
49
+ fi
50
+
51
+ if [ "$1" == "rake" ] || [ "$1" == "rk" ]
52
+ then
53
+ echo Running: ${DOCKER_COMPOSE_COMMAND} run blade rake ${@:2}
54
+ ${DOCKER_COMPOSE_COMMAND} run blade rake "${@:2}"
55
+ exit 0
56
+ fi
57
+
58
+ if [ "$1" == "cs" ] || [ "$1" == "c" ]
59
+ then
60
+ echo Running: ${DOCKER_COMPOSE_COMMAND} run blade rake standard "${@:2}"
61
+ ${DOCKER_COMPOSE_COMMAND} run blade rake standard "${@:2}"
62
+ exit 0
63
+ fi
64
+
65
+ if [ "$1" == "cs:fix" ]
66
+ then
67
+ echo Running: ${DOCKER_COMPOSE_COMMAND} run blade rake standard:fix "${@:2}"
68
+ ${DOCKER_COMPOSE_COMMAND} run blade rake standard:fix "${@:2}"
69
+ exit 0
70
+ fi
71
+
72
+ if [ "$1" == "test" ] || [ "$1" == "t" ]
73
+ then
74
+ echo Running: ${DOCKER_COMPOSE_COMMAND} run blade rake test "${@:2}"
75
+ ${DOCKER_COMPOSE_COMMAND} run blade rake test "${@:2}"
76
+ exit 0
77
+ fi
78
+
79
+ if [ "$1" == "l" ] || [ "$1" == "log" ] || [ "$1" == "logs" ]
80
+ then
81
+ echo Running: ${DOCKER_COMPOSE_COMMAND} logs "${@:2}"
82
+ ${DOCKER_COMPOSE_COMMAND} logs "${@:2}"
83
+ exit 0
84
+ fi
85
+
86
+ if [ "$1" == "ps" ]
87
+ then
88
+ echo Running: ${DOCKER_COMPOSE_COMMAND} ps "${@:2}"
89
+ ${DOCKER_COMPOSE_COMMAND} ps "${@:2}"
90
+ exit 0
91
+ fi
92
+
93
+ echo Running: ${DOCKER_COMPOSE_COMMAND} "${@:1}"
94
+ ${DOCKER_COMPOSE_COMMAND} "${@:1}"
@@ -0,0 +1,7 @@
1
+ services:
2
+ blade:
3
+ image: ruby:3.3.4
4
+ working_dir: /var/source
5
+ volumes:
6
+ - .:/var/source
7
+ - ./storage/bundle_cache:/usr/local/bundle
@@ -0,0 +1,12 @@
1
+ module RBlade
2
+ class CompilesComments
3
+ def compile!(tokens)
4
+ tokens.each do |token|
5
+ next if token.type != :unprocessed
6
+
7
+ token.value.gsub!(/\{\{--.*?--\}\}/m, "")
8
+ token.value.gsub!(/<%#.*?%>/m, "")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,75 @@
1
+ require "rblade/component_store"
2
+
3
+ module RBlade
4
+ class CompilesComponents
5
+ def compile!(tokens)
6
+ tokens.each do |token|
7
+ if [:component, :component_start, :component_end].none? token.type
8
+ next
9
+ end
10
+
11
+ token.value = if token.type == :component_start
12
+ compile_token_start token
13
+ elsif token.type == :component_end
14
+ compile_token_end token
15
+ else
16
+ compile_token_start(token) + compile_token_end(token)
17
+ end
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def compile_token_start token
24
+ attributes = compile_attributes token
25
+ "def _component(attributes={#{attributes[:arguments].join(",")}});#{attributes[:assignments].join}_out='';"
26
+ end
27
+
28
+ def compile_token_end token
29
+ code = "slot=_out;_out='';_stacks=[];"
30
+ code << ComponentStore.fetchComponent(token.value[:name])
31
+ code << "RBlade::StackManager.get(_stacks) + _out;end;_out<<_component();"
32
+
33
+ code
34
+ end
35
+
36
+ def compile_attributes token
37
+ attribute_arguments = []
38
+ attribute_assignments = []
39
+
40
+ token.value[:attributes].each do |attribute|
41
+ if attribute[:type] == "class" || attribute[:type] == "style"
42
+ attribute_arguments.push "'#{attribute[:type]}': #{attribute[:value]}'"
43
+
44
+ next
45
+ end
46
+
47
+ if attribute[:type] == "string"
48
+ attribute_arguments.push "'#{attribute[:name]}': '#{RBlade.escape_quotes(attribute[:value])}'"
49
+ end
50
+
51
+ if attribute[:type] == "ruby"
52
+ attribute_arguments.push "'#{attribute[:name]}': (#{attribute[:value]})'"
53
+ end
54
+
55
+ if attribute[:type] == "pass_through"
56
+ attribute_arguments.push "#{attribute[:name]}:"
57
+ end
58
+
59
+ if attribute[:type] == "empty"
60
+ attribute_arguments.push "'#{attribute[:name]}': true"
61
+ end
62
+
63
+ variable_name = attribute[:name]&.tr("-", "_")
64
+ if !variable_name.nil? && variable_name.match(/^[A-Za-z_][A-Za-z0-9_]*$/)
65
+ keywords = %w[__FILE__ __LINE__ alias and begin BEGIN break case class def defined? do else elsif end END ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield attributes _out slot]
66
+ next if keywords.include? variable_name
67
+
68
+ attribute_assignments.push "#{variable_name} = attributes[:'#{attribute[:name]}'];"
69
+ end
70
+ end
71
+
72
+ {arguments: attribute_arguments, assignments: attribute_assignments}
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,59 @@
1
+ module RBlade
2
+ class CompilesEchos
3
+ def compile!(tokens)
4
+ compile_regular_echos!(tokens)
5
+ compile_unsafe_echos!(tokens)
6
+ end
7
+
8
+ private
9
+
10
+ def compile_regular_echos!(tokens)
11
+ compile_echos! tokens, "{{", "}}", "h"
12
+ compile_echos! tokens, "<%=", "%>", "h"
13
+ end
14
+
15
+ def compile_unsafe_echos!(tokens)
16
+ compile_echos! tokens, "{!!", "!!}"
17
+ end
18
+
19
+ def compile_echos!(tokens, start_token, end_token, wrapper_function = nil)
20
+ tokens.map! do |token|
21
+ next(token) if token.type != :unprocessed
22
+
23
+ start_token_escaped = Regexp.escape start_token
24
+ end_token_escaped = Regexp.escape end_token
25
+ segments = token.value.split(/(?:(@)(#{start_token_escaped}.+?#{end_token_escaped})|(#{start_token_escaped})\s*(.+?)\s*(#{end_token_escaped}))/m)
26
+
27
+ i = 0
28
+ while i < segments.count
29
+ if segments[i] == "@"
30
+ segments.delete_at i
31
+ segments[i] = Token.new(type: :raw_text, value: segments[i])
32
+
33
+ i += 1
34
+ elsif segments[i] == start_token
35
+ segments.delete_at i
36
+ segments.delete_at i + 1
37
+ segment_value = "_out<<"
38
+ # Special case for slot - we want this to be able to output HTML
39
+ if !wrapper_function.nil? && segments[i] != "slot"
40
+ segment_value <<= wrapper_function
41
+ end
42
+ segment_value <<= "(" + segments[i] + ");"
43
+ segments[i] = Token.new(:echo, segment_value)
44
+
45
+ i += 1
46
+ elsif !segments[i].nil? && segments[i] != ""
47
+ segments[i] = Token.new(type: :unprocessed, value: segments[i])
48
+
49
+ i += 1
50
+ else
51
+ segments.delete_at i
52
+ end
53
+ end
54
+
55
+ segments
56
+ end.flatten!
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,57 @@
1
+ module RBlade
2
+ class CompilesRuby
3
+ def compile!(tokens)
4
+ tokens.map! do |token|
5
+ next(token) if token.type != :unprocessed
6
+
7
+ segments = token.value.split(/
8
+ # @ escapes blade style tags
9
+ (@)(@ruby.+?@endruby)
10
+ |
11
+ # <%% and %%> are escape ERB style tags
12
+ (<%%)(.+?)(%%>)
13
+ |
14
+ (?:^|[\b\s])(@ruby)\s+(.+?)[\s;]*(@endruby)(?:$|[\b\s])
15
+ |
16
+ (<%)\s+(.+?)[\s;]*(%>)
17
+ /xm)
18
+
19
+ i = 0
20
+ while i < segments.count
21
+ if segments[i] == "@"
22
+ segments.delete_at i
23
+ segments[i] = Token.new(type: :raw_text, value: segments[i])
24
+
25
+ i += 1
26
+ elsif segments[i] == "<%%"
27
+ segments.delete_at i
28
+ segments.delete_at i + 1
29
+ segments[i] = Token.new(type: :raw_text, value: "<%#{segments[i]}%>")
30
+
31
+ i += 1
32
+ elsif segments[i] == "@ruby" || segments[i] == "<%"
33
+ segments.delete_at i
34
+ segments.delete_at i + 1
35
+
36
+ segments[i].strip!
37
+ if segments[i][-1] != ";"
38
+ segments[i] << ";"
39
+ end
40
+
41
+ segments[i] = Token.new(type: :php, value: segments[i])
42
+
43
+ i += 1
44
+ elsif !segments[i].nil? && segments[i] != ""
45
+ segments[i] = Token.new(type: :unprocessed, value: segments[i])
46
+
47
+ i += 1
48
+ else
49
+ segments.delete_at i
50
+ end
51
+ end
52
+
53
+ segments
54
+ end.flatten!
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,103 @@
1
+ require "rblade/compiler/statements/compiles_conditionals"
2
+ require "rblade/compiler/statements/compiles_inline_ruby"
3
+ require "rblade/compiler/statements/compiles_loops"
4
+ require "rblade/compiler/statements/compiles_stacks"
5
+
6
+ module RBlade
7
+ class CompilesStatements
8
+ def compile!(tokens)
9
+ token_index = 0
10
+ while token_index < tokens.count
11
+ token = tokens[token_index]
12
+ if token.type != :statement
13
+ token_index += 1
14
+ next
15
+ end
16
+
17
+ name = token.value[:name]
18
+ arguments = token.value[:arguments]
19
+ handler = getHandler(name)
20
+
21
+ handler_arguments = []
22
+ handler.parameters.each do |parameter|
23
+ case parameter.last
24
+ when :args
25
+ handler_arguments.push arguments
26
+ when :tokens
27
+ handler_arguments.push tokens
28
+ when :token_index
29
+ handler_arguments.push token_index
30
+ end
31
+ end
32
+
33
+ token.value = handler.call(*handler_arguments)
34
+ token_index += 1
35
+ end
36
+ end
37
+
38
+ def compileEnd
39
+ "end;"
40
+ end
41
+
42
+ private
43
+
44
+ def getHandler(name)
45
+ handler_class, handler_method = @@statement_handlers[name]
46
+
47
+ if !handler_class&.method_defined?(handler_method)
48
+ raise StandardError.new "Unhandled statement: @#{name}"
49
+ end
50
+
51
+ if handler_class == CompilesStatements
52
+ @@handler_instances[handler_class] = self
53
+ else
54
+ @@handler_instances[handler_class] ||= handler_class.new
55
+ end
56
+
57
+ @@handler_instances[handler_class].method(handler_method)
58
+ end
59
+
60
+ @@handler_instances = {}
61
+
62
+ @@statement_handlers = {
63
+ "break" => [CompilesLoops, :compileBreak],
64
+ "breakif" => [CompilesLoops, :compileBreakIf],
65
+ "case" => [CompilesConditionals, :compileCase],
66
+ "checked" => [CompilesConditionals, :compileChecked],
67
+ "disabled" => [CompilesConditionals, :compileDisabled],
68
+ "else" => [CompilesConditionals, :compileElse],
69
+ "elsif" => [CompilesConditionals, :compileElsif],
70
+ "each" => [CompilesLoops, :compileEach],
71
+ "eachelse" => [CompilesLoops, :compileEachElse],
72
+ "empty" => [CompilesLoops, :compileEmpty],
73
+ "end" => [CompilesStatements, :compileEnd],
74
+ "endcase" => [CompilesStatements, :compileEnd],
75
+ "endeach" => [CompilesStatements, :compileEnd],
76
+ "endeachelse" => [CompilesStatements, :compileEnd],
77
+ "endfor" => [CompilesStatements, :compileEnd],
78
+ "endforelse" => [CompilesStatements, :compileEnd],
79
+ "endif" => [CompilesStatements, :compileEnd],
80
+ "endprepend" => [CompilesStacks, :compileEndPrepend],
81
+ "endpush" => [CompilesStacks, :compileEndPush],
82
+ "endunless" => [CompilesStatements, :compileEnd],
83
+ "enduntil" => [CompilesStatements, :compileEnd],
84
+ "endwhile" => [CompilesStatements, :compileEnd],
85
+ "for" => [CompilesLoops, :compileFor],
86
+ "forelse" => [CompilesLoops, :compileForElse],
87
+ "if" => [CompilesConditionals, :compileIf],
88
+ "next" => [CompilesLoops, :compileNext],
89
+ "nextif" => [CompilesLoops, :compileNextIf],
90
+ "prepend" => [CompilesStacks, :compilePrepend],
91
+ "push" => [CompilesStacks, :compilePush],
92
+ "readonly" => [CompilesConditionals, :compileReadonly],
93
+ "required" => [CompilesConditionals, :compileRequired],
94
+ "ruby" => [CompilesInlineRuby, :compile],
95
+ "selected" => [CompilesConditionals, :compileSelected],
96
+ "stack" => [CompilesStacks, :compileStack],
97
+ "unless" => [CompilesConditionals, :compileUnless],
98
+ "until" => [CompilesLoops, :compileUntil],
99
+ "when" => [CompilesConditionals, :compileWhen],
100
+ "while" => [CompilesLoops, :compileWhile]
101
+ }
102
+ end
103
+ end
@@ -0,0 +1,93 @@
1
+ module RBlade
2
+ class CompilesStatements
3
+ class CompilesConditionals
4
+ def compileIf args
5
+ if args&.count != 1
6
+ raise StandardError.new "If statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
7
+ end
8
+
9
+ "if #{args[0]};"
10
+ end
11
+
12
+ def compileElsif args
13
+ if args&.count != 1
14
+ raise StandardError.new "Elsif statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
15
+ end
16
+
17
+ "elsif #{args[0]};"
18
+ end
19
+
20
+ def compileElse args
21
+ if !args.nil?
22
+ raise StandardError.new "Else statement: wrong number of arguments (given #{args&.count || 0}, expecting 0)"
23
+ end
24
+
25
+ "else;"
26
+ end
27
+
28
+ def compileUnless args
29
+ if args&.count != 1
30
+ raise StandardError.new "Unless statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
31
+ end
32
+
33
+ "unless #{args[0]};"
34
+ end
35
+
36
+ def compileCase args
37
+ if args&.count != 1
38
+ raise StandardError.new "Case statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
39
+ end
40
+
41
+ "case #{args[0]};"
42
+ end
43
+
44
+ def compileWhen args
45
+ if args.nil? || args.count == 0
46
+ raise StandardError.new "When statement: wrong number of arguments (given #{args&.count || 0}, expecting at least 1)"
47
+ end
48
+
49
+ "when #{args.join ","};"
50
+ end
51
+
52
+ def compileChecked args
53
+ if args&.count != 1
54
+ raise StandardError.new "Checked statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
55
+ end
56
+
57
+ "if #{args[0]};_out<<'checked';end;"
58
+ end
59
+
60
+ def compileDisabled args
61
+ if args&.count != 1
62
+ raise StandardError.new "Disabled statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
63
+ end
64
+
65
+ "if #{args[0]};_out<<'disabled';end;"
66
+ end
67
+
68
+ def compileReadonly args
69
+ if args&.count != 1
70
+ raise StandardError.new "Readonly statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
71
+ end
72
+
73
+ "if #{args[0]};_out<<'readonly';end;"
74
+ end
75
+
76
+ def compileRequired args
77
+ if args&.count != 1
78
+ raise StandardError.new "Required statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
79
+ end
80
+
81
+ "if #{args[0]};_out<<'required';end;"
82
+ end
83
+
84
+ def compileSelected args
85
+ if args&.count != 1
86
+ raise StandardError.new "Selected statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
87
+ end
88
+
89
+ "if #{args[0]};_out<<'selected';end;"
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,17 @@
1
+ module RBlade
2
+ class CompilesStatements
3
+ class CompilesInlineRuby
4
+ def compile args
5
+ if args&.count != 1
6
+ raise StandardError.new "Ruby statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
7
+ end
8
+
9
+ arg = args[0].strip
10
+ if arg[-1] != ";"
11
+ arg << ";"
12
+ end
13
+ arg
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,109 @@
1
+ module RBlade
2
+ class CompilesStatements
3
+ class CompilesLoops
4
+ def initialize
5
+ @loop_else_counter = 0
6
+ end
7
+
8
+ def compileBreak args
9
+ if !args.nil?
10
+ raise StandardError.new "Break statement: wrong number of arguments (given #{args&.count}, expecting 0)"
11
+ end
12
+
13
+ "break;"
14
+ end
15
+
16
+ def compileBreakIf args
17
+ if args&.count != 1
18
+ raise StandardError.new "Break statement: wrong number of arguments (given #{args&.count}, expecting 1)"
19
+ end
20
+
21
+ "if #{args[0]};break;end;"
22
+ end
23
+
24
+ def compileEach args
25
+ if args&.count != 1
26
+ raise StandardError.new "Each statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
27
+ end
28
+
29
+ variables, collection = args[0].split(" in ")
30
+
31
+ "#{collection}.each do |#{variables}|;"
32
+ end
33
+
34
+ def compileEachElse args
35
+ if args&.count != 1
36
+ raise StandardError.new "Each else statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
37
+ end
38
+ @loop_else_counter += 1
39
+
40
+ variables, collection = args[0].split(" in ")
41
+
42
+ "_looped_#{@loop_else_counter}=true;#{collection}.each do |#{variables}|;_looped_#{@loop_else_counter}=false;"
43
+ end
44
+
45
+ def compileFor args
46
+ if args&.count != 1
47
+ raise StandardError.new "For statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
48
+ end
49
+
50
+ "for #{args[0]};"
51
+ end
52
+
53
+ def compileForElse args
54
+ if args&.count != 1
55
+ raise StandardError.new "For else statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
56
+ end
57
+ @loop_else_counter += 1
58
+
59
+ "_looped_#{@loop_else_counter}=true;for #{args[0]};_looped_#{@loop_else_counter}=false;"
60
+ end
61
+
62
+ def compileEmpty
63
+ @loop_else_counter -= 1
64
+
65
+ "end;if _looped_#{@loop_else_counter + 1};"
66
+ end
67
+
68
+ def compileNext args
69
+ if args&.count&.> 1
70
+ raise StandardError.new "For statement: wrong number of arguments (given #{args&.count || 0}, expecting 0 or 1)"
71
+ end
72
+
73
+ if args.nil?
74
+ "next;"
75
+ else
76
+ "next #{args[0]};"
77
+ end
78
+ end
79
+
80
+ def compileNextIf args
81
+ if args.nil? || args.count > 2
82
+ raise StandardError.new "For statement: wrong number of arguments (given #{args&.count || 0}, expecting 1 or 2)"
83
+ end
84
+
85
+ if args.count == 1
86
+ "if #{args[0]};next;end;"
87
+ else
88
+ "if #{args[0]};next #{args[1]};end;"
89
+ end
90
+ end
91
+
92
+ def compileUntil args
93
+ if args&.count != 1
94
+ raise StandardError.new "Until statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
95
+ end
96
+
97
+ "until #{args[0]};"
98
+ end
99
+
100
+ def compileWhile args
101
+ if args&.count != 1
102
+ raise StandardError.new "While statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
103
+ end
104
+
105
+ "while #{args[0]};"
106
+ end
107
+ end
108
+ end
109
+ end