statsailr 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +6 -0
- data/Gemfile +7 -0
- data/HISTORY.md +15 -0
- data/LICENSE.txt +675 -0
- data/README.md +287 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/example/blank.slr +3 -0
- data/example/category.slr +5 -0
- data/example/example_read.slr +10 -0
- data/example/iris.csv +151 -0
- data/example/mtcars.rda +0 -0
- data/example/new_mtcars.csv +33 -0
- data/example/new_mtcars.rda +0 -0
- data/example/plot_reg_example.slr +55 -0
- data/example/scatter.png +0 -0
- data/exe/sailr +54 -0
- data/exe/sailrREPL +75 -0
- data/lib/statsailr.rb +7 -0
- data/lib/statsailr/block_builder/sts_block.rb +167 -0
- data/lib/statsailr/block_builder/sts_block_parse_proc_opts.rb +168 -0
- data/lib/statsailr/block_to_r/proc_setting_support/proc_opt_validator.rb +52 -0
- data/lib/statsailr/block_to_r/proc_setting_support/proc_setting_manager.rb +49 -0
- data/lib/statsailr/block_to_r/proc_setting_support/proc_setting_module.rb +44 -0
- data/lib/statsailr/block_to_r/sts_block_to_r.rb +98 -0
- data/lib/statsailr/block_to_r/sts_lazy_func_gen.rb +236 -0
- data/lib/statsailr/block_to_r/top_stmt/top_stmt_to_r_func.rb +182 -0
- data/lib/statsailr/parser/sts_gram_node.rb +9 -0
- data/lib/statsailr/parser/sts_parse.output +831 -0
- data/lib/statsailr/parser/sts_parse.ry +132 -0
- data/lib/statsailr/parser/sts_parse.tab.rb +682 -0
- data/lib/statsailr/scanner/sample1.sts +37 -0
- data/lib/statsailr/scanner/sts_scanner.rb +433 -0
- data/lib/statsailr/scanner/test_sample1.rb +8 -0
- data/lib/statsailr/sts_build_exec.rb +304 -0
- data/lib/statsailr/sts_controller.rb +66 -0
- data/lib/statsailr/sts_output/output_manager.rb +192 -0
- data/lib/statsailr/sts_runner.rb +17 -0
- data/lib/statsailr/sts_server.rb +85 -0
- data/lib/statsailr/version.rb +3 -0
- data/statsailr.gemspec +32 -0
- metadata +133 -0
data/example/mtcars.rda
ADDED
Binary file
|
@@ -0,0 +1,33 @@
|
|
1
|
+
"","mpg","cyl","disp","hp","drat","wt","qsec","vs","am","gear","carb","powerful"
|
2
|
+
"Mazda RX4",21,6,160,110,3.9,2.62,16.46,0,1,4,4,1
|
3
|
+
"Mazda RX4 Wag",21,6,160,110,3.9,2.875,17.02,0,1,4,4,1
|
4
|
+
"Datsun 710",22.8,4,108,93,3.85,2.32,18.61,1,1,4,1,0
|
5
|
+
"Hornet 4 Drive",21.4,6,258,110,3.08,3.215,19.44,1,0,3,1,1
|
6
|
+
"Hornet Sportabout",18.7,8,360,175,3.15,3.44,17.02,0,0,3,2,1
|
7
|
+
"Valiant",18.1,6,225,105,2.76,3.46,20.22,1,0,3,1,1
|
8
|
+
"Duster 360",14.3,8,360,245,3.21,3.57,15.84,0,0,3,4,1
|
9
|
+
"Merc 240D",24.4,4,146.7,62,3.69,3.19,20,1,0,4,2,0
|
10
|
+
"Merc 230",22.8,4,140.8,95,3.92,3.15,22.9,1,0,4,2,0
|
11
|
+
"Merc 280",19.2,6,167.6,123,3.92,3.44,18.3,1,0,4,4,1
|
12
|
+
"Merc 280C",17.8,6,167.6,123,3.92,3.44,18.9,1,0,4,4,1
|
13
|
+
"Merc 450SE",16.4,8,275.8,180,3.07,4.07,17.4,0,0,3,3,1
|
14
|
+
"Merc 450SL",17.3,8,275.8,180,3.07,3.73,17.6,0,0,3,3,1
|
15
|
+
"Merc 450SLC",15.2,8,275.8,180,3.07,3.78,18,0,0,3,3,1
|
16
|
+
"Cadillac Fleetwood",10.4,8,472,205,2.93,5.25,17.98,0,0,3,4,1
|
17
|
+
"Lincoln Continental",10.4,8,460,215,3,5.424,17.82,0,0,3,4,1
|
18
|
+
"Chrysler Imperial",14.7,8,440,230,3.23,5.345,17.42,0,0,3,4,1
|
19
|
+
"Fiat 128",32.4,4,78.7,66,4.08,2.2,19.47,1,1,4,1,0
|
20
|
+
"Honda Civic",30.4,4,75.7,52,4.93,1.615,18.52,1,1,4,2,0
|
21
|
+
"Toyota Corolla",33.9,4,71.1,65,4.22,1.835,19.9,1,1,4,1,0
|
22
|
+
"Toyota Corona",21.5,4,120.1,97,3.7,2.465,20.01,1,0,3,1,0
|
23
|
+
"Dodge Challenger",15.5,8,318,150,2.76,3.52,16.87,0,0,3,2,1
|
24
|
+
"AMC Javelin",15.2,8,304,150,3.15,3.435,17.3,0,0,3,2,1
|
25
|
+
"Camaro Z28",13.3,8,350,245,3.73,3.84,15.41,0,0,3,4,1
|
26
|
+
"Pontiac Firebird",19.2,8,400,175,3.08,3.845,17.05,0,0,3,2,1
|
27
|
+
"Fiat X1-9",27.3,4,79,66,4.08,1.935,18.9,1,1,4,1,0
|
28
|
+
"Porsche 914-2",26,4,120.3,91,4.43,2.14,16.7,0,1,5,2,0
|
29
|
+
"Lotus Europa",30.4,4,95.1,113,3.77,1.513,16.9,1,1,5,2,0
|
30
|
+
"Ford Pantera L",15.8,8,351,264,4.22,3.17,14.5,0,1,5,4,1
|
31
|
+
"Ferrari Dino",19.7,6,145,175,3.62,2.77,15.5,0,1,5,6,1
|
32
|
+
"Maserati Bora",15,8,301,335,3.54,3.57,14.6,0,1,5,8,1
|
33
|
+
"Volvo 142E",21.4,4,121,109,4.11,2.78,18.6,1,1,4,2,0
|
Binary file
|
@@ -0,0 +1,55 @@
|
|
1
|
+
// comment
|
2
|
+
/*
|
3
|
+
multipe line comments
|
4
|
+
*/
|
5
|
+
|
6
|
+
READ builtin = "mtcars"
|
7
|
+
|
8
|
+
DATA new_mtcars set=mtcars
|
9
|
+
if(cyl > 4){
|
10
|
+
powerful = 1
|
11
|
+
}else{
|
12
|
+
powerful = 0
|
13
|
+
}
|
14
|
+
END
|
15
|
+
|
16
|
+
PROC PRINT data=new_mtcars
|
17
|
+
head 10
|
18
|
+
tail
|
19
|
+
tail / n = 10
|
20
|
+
END
|
21
|
+
|
22
|
+
PROC PLOT data=new_mtcars
|
23
|
+
scatter powerful cyl
|
24
|
+
dev.copy png / file = "scatter.png"
|
25
|
+
END
|
26
|
+
|
27
|
+
PROC CAT data=new_mtcars
|
28
|
+
/* Calculate frequencies & show in list format
|
29
|
+
*/
|
30
|
+
xtabs ~ cyl + powerful
|
31
|
+
fisher.test
|
32
|
+
chisq.test
|
33
|
+
END
|
34
|
+
|
35
|
+
PROC UNI data=new_mtcars
|
36
|
+
var cyl carb
|
37
|
+
END
|
38
|
+
|
39
|
+
|
40
|
+
PROC REG data=new_mtcars
|
41
|
+
lm hp ~ factor(cyl) + factor(carb)
|
42
|
+
END
|
43
|
+
|
44
|
+
GETWD
|
45
|
+
|
46
|
+
SAVE new_mtcars file="./new_mtcars.csv"
|
47
|
+
|
48
|
+
SAVE new_mtcars file="./new_mtcars.rda"
|
49
|
+
|
50
|
+
|
51
|
+
// READ builtin = "CO2"
|
52
|
+
|
53
|
+
// DATA:SQLDF CO2v2
|
54
|
+
// SELECT Plant, conc, uptake FROM CO2 WHERE Plant IN ('Qn1','Mn1') ORDER BY uptake
|
55
|
+
// END
|
data/example/scatter.png
ADDED
Binary file
|
data/exe/sailr
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
## Parse argumnet and initialize setting
|
4
|
+
|
5
|
+
require('optparse')
|
6
|
+
opt = OptionParser.new
|
7
|
+
params = {}
|
8
|
+
new_params = {}
|
9
|
+
|
10
|
+
opt.on('--procs-gem VAL')
|
11
|
+
opt.parse!(ARGV, into: params)
|
12
|
+
|
13
|
+
if params[:"procs-gem"]
|
14
|
+
if params[:"procs-gem"] =~ /[a-zA-Z,_-]+/
|
15
|
+
if params[:"procs-gem"].include?( "," )
|
16
|
+
new_params[:"procs_gem"] = params[:"procs-gem"].split(",")
|
17
|
+
else
|
18
|
+
new_params[:"procs_gem"] = params[:"procs-gem"]
|
19
|
+
end
|
20
|
+
else
|
21
|
+
raise "--procs-gem option takes gem name or gem names separated with comma(,)."
|
22
|
+
end
|
23
|
+
else
|
24
|
+
# nothing to be specified.
|
25
|
+
end
|
26
|
+
|
27
|
+
specified_script_path = ARGV[0]
|
28
|
+
|
29
|
+
raise "Please spcify StatSailr script path" if( specified_script_path.nil? )
|
30
|
+
|
31
|
+
|
32
|
+
## Set path
|
33
|
+
|
34
|
+
require('pathname')
|
35
|
+
|
36
|
+
if Pathname.new(specified_script_path).relative?
|
37
|
+
$script_file_path = Dir.pwd + "/" + specified_script_path
|
38
|
+
else
|
39
|
+
$script_file_path = specified_script_path
|
40
|
+
end
|
41
|
+
|
42
|
+
raise "StatSailr script file specified does not exist" if ! File.exist?( $script_file_path )
|
43
|
+
|
44
|
+
$script_dir_path = File.dirname( $script_file_path )
|
45
|
+
|
46
|
+
|
47
|
+
## Run
|
48
|
+
|
49
|
+
require("statsailr")
|
50
|
+
|
51
|
+
StatSailr.run( **new_params )
|
52
|
+
|
53
|
+
|
54
|
+
|
data/exe/sailrREPL
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
## Parse argumnet and initialize setting
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
opt = OptionParser.new
|
7
|
+
params = {}
|
8
|
+
new_params = {}
|
9
|
+
|
10
|
+
opt.on('--thread')
|
11
|
+
opt.on('--procs-gem VAL')
|
12
|
+
opt.parse!(ARGV, into: params)
|
13
|
+
|
14
|
+
fork_or_thread = params[:thread]
|
15
|
+
if fork_or_thread
|
16
|
+
new_params[:fork_or_thread] = "thread"
|
17
|
+
else
|
18
|
+
new_params[:fork_or_thread] = "fork"
|
19
|
+
end
|
20
|
+
|
21
|
+
if new_params[:fork_or_thread] == "fork"
|
22
|
+
if Process.respond_to?(:fork)
|
23
|
+
# "fork" is used and system has "fork" implementation.
|
24
|
+
else
|
25
|
+
raise 'fork is not implemented on this system. Please try to run sailrREPL with "--thread" option'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
if params[:"procs-gem"]
|
30
|
+
if params[:"procs-gem"] =~ /[a-zA-Z,_-]+/
|
31
|
+
if params[:"procs-gem"].include?( "," )
|
32
|
+
new_params[:"procs_gem"] = params[:"procs-gem"].split(",")
|
33
|
+
else
|
34
|
+
new_params[:"procs_gem"] = params[:"procs-gem"]
|
35
|
+
end
|
36
|
+
else
|
37
|
+
raise "--procs-gem option takes gem name or gem names separated with comma(,)."
|
38
|
+
end
|
39
|
+
else
|
40
|
+
# nothing to be specified.
|
41
|
+
end
|
42
|
+
|
43
|
+
## Main
|
44
|
+
|
45
|
+
require("statsailr")
|
46
|
+
|
47
|
+
reader, writer = IO.pipe
|
48
|
+
|
49
|
+
child_service = StatSailr::Service.start( reader , writer, **new_params )
|
50
|
+
|
51
|
+
prompt = "(^^)v: "
|
52
|
+
line = ""
|
53
|
+
print prompt
|
54
|
+
while true
|
55
|
+
line = STDIN.gets()
|
56
|
+
if line.nil? # When C-d
|
57
|
+
puts "C-d : Parent process finishes. Close pipe."
|
58
|
+
writer.close
|
59
|
+
break
|
60
|
+
elsif line =~ /^!exit/
|
61
|
+
puts "!exit : Parent process finishes. Close pipe."
|
62
|
+
writer.close
|
63
|
+
break
|
64
|
+
else
|
65
|
+
writer.write line
|
66
|
+
print prompt
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
case fork_or_thread
|
71
|
+
when "fork"
|
72
|
+
Process.waitpid(child_service)
|
73
|
+
when "thread"
|
74
|
+
child_service.join()
|
75
|
+
end
|
data/lib/statsailr.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
require "r_bridge"
|
2
|
+
require_relative "./sts_block_parse_proc_opts.rb"
|
3
|
+
|
4
|
+
module BlockSupport
|
5
|
+
def type_adjust(obj , type)
|
6
|
+
case type
|
7
|
+
when :ident
|
8
|
+
if obj.is_a?(String)
|
9
|
+
result = RBridge::SymbolR.new( obj )
|
10
|
+
else
|
11
|
+
raise "GramNode should have string value for type(#{type.to_s})"
|
12
|
+
end
|
13
|
+
when :num
|
14
|
+
if obj.is_a?(Integer) || obj.is_a?(Float)
|
15
|
+
result = obj
|
16
|
+
else
|
17
|
+
raise "GramNode with inconsistent type(#{type.to_s}) and object(#{obj.class})"
|
18
|
+
end
|
19
|
+
when :string
|
20
|
+
if obj.is_a?(String)
|
21
|
+
result = obj
|
22
|
+
else
|
23
|
+
raise "GramNode with inconsistent type(#{type.to_s}) and object(#{obj.class})"
|
24
|
+
end
|
25
|
+
when :sign
|
26
|
+
if obj.is_a?(String)
|
27
|
+
result = RBridge::SignR.new(obj)
|
28
|
+
else
|
29
|
+
raise "GramNode with inconsistent type(#{type.to_s}) and object(#{obj.class})"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
return result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class TopStmt
|
37
|
+
extend BlockSupport
|
38
|
+
attr :command, :opts
|
39
|
+
|
40
|
+
def initialize( str, hash )
|
41
|
+
@command = str
|
42
|
+
@opts = hash
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.new_from_gram_node( node )
|
46
|
+
command_name = node.e1
|
47
|
+
top_opts = node.e2
|
48
|
+
if (! top_opts.nil? ) && (top_opts.size != 0 )
|
49
|
+
hash = {}
|
50
|
+
top_opts.each(){|nd|
|
51
|
+
top_opt_key = nd.e1
|
52
|
+
if(!nd.e2.nil?)
|
53
|
+
top_opt_val = type_adjust( nd.e2.e1 , nd.e2.type )
|
54
|
+
else
|
55
|
+
top_opt_val = nil
|
56
|
+
end
|
57
|
+
hash[top_opt_key] = top_opt_val
|
58
|
+
}
|
59
|
+
else
|
60
|
+
hash = {}
|
61
|
+
end
|
62
|
+
return TopStmt.new( command_name, hash)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class DataBlock
|
67
|
+
extend BlockSupport
|
68
|
+
attr :out, :opts, :script
|
69
|
+
|
70
|
+
def initialize( str, hash, script)
|
71
|
+
@out = str
|
72
|
+
@opts = hash
|
73
|
+
@script = script
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.new_from_gram_node( node )
|
77
|
+
out_df = type_adjust( node.e1.e1, node.e1.type )
|
78
|
+
data_hash = {}
|
79
|
+
data_opts = node.e2
|
80
|
+
|
81
|
+
if ! data_opts.nil?
|
82
|
+
data_opts.each(){|nd|
|
83
|
+
data_opt_key = nd.e1
|
84
|
+
if(!nd.e2.nil?)
|
85
|
+
data_opt_val = type_adjust( nd.e2.e1 , nd.e2.type )
|
86
|
+
else
|
87
|
+
data_opt_val = nil
|
88
|
+
end
|
89
|
+
data_hash[data_opt_key] = data_opt_val
|
90
|
+
}
|
91
|
+
else
|
92
|
+
data_opts = {}
|
93
|
+
end
|
94
|
+
|
95
|
+
data_script = type_adjust( node.e3.e1, node.e3.type )
|
96
|
+
|
97
|
+
return DataBlock.new( out_df , data_hash , data_script)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class ProcBlock
|
102
|
+
extend BlockSupport
|
103
|
+
attr :command, :opts, :stmts
|
104
|
+
|
105
|
+
def initialize( command, opts, stmts )
|
106
|
+
@command = command
|
107
|
+
@opts = opts
|
108
|
+
@stmts = stmts
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.new_from_gram_node( node )
|
112
|
+
proc_command = type_adjust( node.e1.e1, :string )
|
113
|
+
|
114
|
+
proc_opt_hash = {}
|
115
|
+
proc_opts = node.e2
|
116
|
+
if(! proc_opts.nil?)
|
117
|
+
proc_opts.each(){|nd|
|
118
|
+
proc_opt_key = nd.e1
|
119
|
+
proc_opt_val = type_adjust( nd.e2.e1 , nd.e2.type )
|
120
|
+
proc_opt_hash[proc_opt_key] = proc_opt_val
|
121
|
+
}
|
122
|
+
else
|
123
|
+
proc_opt_hash = {}
|
124
|
+
end
|
125
|
+
|
126
|
+
proc_stmts = []
|
127
|
+
|
128
|
+
proc_stmts_ori = node.e3
|
129
|
+
proc_stmts_ori.each(){|proc_stmt_ori|
|
130
|
+
proc_stmt_inst = ""
|
131
|
+
proc_stmt_arg = []
|
132
|
+
proc_stmt_opt_hash = {}
|
133
|
+
|
134
|
+
proc_stmt_inst = type_adjust( proc_stmt_ori.e1.e1, :string) # String
|
135
|
+
proc_stmt_arg_ori = proc_stmt_ori.e2
|
136
|
+
if ! proc_stmt_arg_ori.nil? then
|
137
|
+
idx = 0
|
138
|
+
while idx < proc_stmt_arg_ori.size() do
|
139
|
+
elem = proc_stmt_arg_ori[idx]
|
140
|
+
if( elem.type == :sign && elem.e1 == "/" )
|
141
|
+
break
|
142
|
+
else
|
143
|
+
x = type_adjust( elem.e1, elem.type )
|
144
|
+
proc_stmt_arg << x
|
145
|
+
idx = idx + 1
|
146
|
+
end
|
147
|
+
end
|
148
|
+
idx = idx + 1
|
149
|
+
if idx < proc_stmt_arg_ori.size()
|
150
|
+
|
151
|
+
proc_stmt_opt_hash = STSBlockParseProcOpts.include(BlockSupport).new(proc_stmt_arg_ori, idx).parse()
|
152
|
+
else
|
153
|
+
proc_stmt_opt_hash = {}
|
154
|
+
end
|
155
|
+
else # When no arguments (even )
|
156
|
+
prc_stmt_arg = []
|
157
|
+
end
|
158
|
+
|
159
|
+
proc_stmts.push( [proc_stmt_inst, proc_stmt_arg, proc_stmt_opt_hash ] )
|
160
|
+
}
|
161
|
+
|
162
|
+
return ProcBlock.new( proc_command , proc_opt_hash, proc_stmts)
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
|
@@ -0,0 +1,168 @@
|
|
1
|
+
class STSBlockParseProcOpts
|
2
|
+
|
3
|
+
def initialize(elems, idx)
|
4
|
+
@size = elems.size
|
5
|
+
@elems = elems
|
6
|
+
@idx = idx
|
7
|
+
@result_hash = Hash.new()
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_next?()
|
11
|
+
if @idx + 1 < @size
|
12
|
+
return true
|
13
|
+
else
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def next_token()
|
19
|
+
if has_next?
|
20
|
+
@idx = @idx + 1
|
21
|
+
@elems[@idx]
|
22
|
+
else
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def peek()
|
28
|
+
if has_next?
|
29
|
+
@elems[@idx + 1]
|
30
|
+
else
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def current_token()
|
36
|
+
@elems[@idx]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Entry point
|
40
|
+
def parse()
|
41
|
+
arg_opts()
|
42
|
+
return @result_hash
|
43
|
+
end
|
44
|
+
|
45
|
+
# The following grammar is parsed using recursive descent algorithm
|
46
|
+
|
47
|
+
# arg_opts : arg_opt
|
48
|
+
# | arg_opts arg_opt
|
49
|
+
#
|
50
|
+
# arg_opt : IDENT = primary
|
51
|
+
# | IDENT = array
|
52
|
+
# | IDENT = func
|
53
|
+
# | IDENT
|
54
|
+
#
|
55
|
+
# parimary : STRING
|
56
|
+
# | NUM
|
57
|
+
# | IDENT
|
58
|
+
#
|
59
|
+
# array : [ elems ]
|
60
|
+
#
|
61
|
+
# func : IDENT ( elems )
|
62
|
+
#
|
63
|
+
# elems : primary
|
64
|
+
# | elems , primary
|
65
|
+
#
|
66
|
+
#
|
67
|
+
|
68
|
+
def arg_opts()
|
69
|
+
arg_opt()
|
70
|
+
if has_next?
|
71
|
+
next_token()
|
72
|
+
arg_opts()
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def arg_opt()
|
77
|
+
opt_key = ident()
|
78
|
+
if (!peek.nil?) && peek.type == :sign && peek.e1 == "="
|
79
|
+
next_token() # At =
|
80
|
+
if peek.type == :sign && peek.e1 == "[" # RHS of = is array
|
81
|
+
next_token() # Now at [
|
82
|
+
opt_value = array()
|
83
|
+
elsif peek.type == :ident # RHS of = is ident, meaning just ident or function
|
84
|
+
next_token()
|
85
|
+
if (! peek.nil?) && peek.type == :sign && peek.e1 == "("
|
86
|
+
opt_value = func()
|
87
|
+
else
|
88
|
+
opt_value = ident() # According to BNF, this should be parimary(). However, ident() is more direct and makes sense here.
|
89
|
+
end
|
90
|
+
elsif [:string, :num].include? peek.type
|
91
|
+
next_token()
|
92
|
+
opt_value = primary()
|
93
|
+
else
|
94
|
+
p current_token()
|
95
|
+
raise "the token should be :ident or primaries such as :ident, :num and :string after = . Current token: " + current_token().type.to_s
|
96
|
+
end
|
97
|
+
else
|
98
|
+
opt_value = true
|
99
|
+
end
|
100
|
+
@result_hash[opt_key.to_s] = opt_value
|
101
|
+
end
|
102
|
+
|
103
|
+
def array()
|
104
|
+
raise "array should start with [ " if ! (current_token.type == :sign && current_token.e1 == "[")
|
105
|
+
|
106
|
+
next_token()
|
107
|
+
ary = Array.new()
|
108
|
+
elems( ary )
|
109
|
+
|
110
|
+
raise "array should end with ] " if ! (current_token.type == :sign && current_token.e1 == "]")
|
111
|
+
|
112
|
+
return ary
|
113
|
+
end
|
114
|
+
|
115
|
+
def elems( ary )
|
116
|
+
ary.push primary()
|
117
|
+
next_token
|
118
|
+
if current_token.type == :sign && current_token.e1 == ","
|
119
|
+
next_token
|
120
|
+
elems( ary )
|
121
|
+
else
|
122
|
+
return ary
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def primary()
|
127
|
+
case current_token.type
|
128
|
+
when :ident
|
129
|
+
return ident()
|
130
|
+
when :string
|
131
|
+
return string()
|
132
|
+
when :num
|
133
|
+
return num()
|
134
|
+
else
|
135
|
+
raise "the current token should be :ident, :string or :num."
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def func()
|
140
|
+
func_name = ident()
|
141
|
+
parenthesis = next_token()
|
142
|
+
raise "func arg should start with ( " if ! (parenthesis.type == :sign && parenthesis.e1 == "(")
|
143
|
+
|
144
|
+
next_token()
|
145
|
+
func_args = elems( Array.new() )
|
146
|
+
raise "func should end with ) " if ! (current_token.type == :sign && current_token.e1 == ")")
|
147
|
+
|
148
|
+
func_hash = {"type" => :func , "fname" => func_name.to_s , "fargs" => func_args}
|
149
|
+
return func_hash
|
150
|
+
end
|
151
|
+
|
152
|
+
def ident()
|
153
|
+
raise "the current token should be ident" if current_token.type != :ident
|
154
|
+
return type_adjust( current_token.e1, :ident)
|
155
|
+
end
|
156
|
+
|
157
|
+
def string()
|
158
|
+
raise "the current token should be string" if current_token.type != :string
|
159
|
+
return type_adjust( current_token.e1, :string)
|
160
|
+
end
|
161
|
+
|
162
|
+
def num()
|
163
|
+
raise "the current token should be num" if current_token.type != :num
|
164
|
+
return type_adjust( current_token.e1, :num)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
|