rgo-lang 0.1.0
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/.gitattributes +2 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +9 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +36 -0
- data/LICENSE.txt +21 -0
- data/README.md +21 -0
- data/Rakefile +28 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/rgo +15 -0
- data/lib/rgo.rb +7 -0
- data/lib/rgo/compile.rb +340 -0
- data/lib/rgo/node.rb +11 -0
- data/lib/rgo/parser.rb +847 -0
- data/lib/rgo/tokenizer.rb +105 -0
- data/lib/rgo/version.rb +3 -0
- data/parse.y +224 -0
- data/rgo.gemspec +29 -0
- data/samples/1_hello_world.go +7 -0
- data/samples/1_hello_world.rgo +7 -0
- data/samples/3_variables.go +17 -0
- data/samples/3_variables.rgo +17 -0
- data/samples/4_if_else.go +15 -0
- data/samples/4_if_else.rgo +15 -0
- data/samples/5_constants.go +15 -0
- data/samples/5_constants.rgo +15 -0
- data/samples/6_functions.go +21 -0
- data/samples/6_functions.rgo +23 -0
- data/samples/7_methods.go +25 -0
- data/samples/7_methods.rgo +28 -0
- data/std/fmt.rgo +8 -0
- metadata +94 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
module Rgo
|
4
|
+
class Tokenizer
|
5
|
+
def initialize(source)
|
6
|
+
@source = source
|
7
|
+
end
|
8
|
+
|
9
|
+
def tokens
|
10
|
+
@q = []
|
11
|
+
scanner = StringScanner.new(@source)
|
12
|
+
|
13
|
+
until scanner.empty?
|
14
|
+
case
|
15
|
+
when m=scanner.scan(/\s+/)
|
16
|
+
blank_lines = m.count("\n") - 1
|
17
|
+
blank_lines.times do
|
18
|
+
@q.push [:BLANK_LINE, ""]
|
19
|
+
end
|
20
|
+
when m = scanner.scan(Expression::INTEGER)
|
21
|
+
@q.push [:INTEGER, m.to_i]
|
22
|
+
when m = scanner.scan(Expression::KEYWORDS)
|
23
|
+
@q.push [:"KEYWORD_#{m.upcase}", m]
|
24
|
+
when m = scanner.scan(Expression::COMMENT)
|
25
|
+
@q.push [:COMMENT, m[1..-1]]
|
26
|
+
when m = scanner.scan(Expression::STRING)
|
27
|
+
@q.push [:STRING, m[1..-2]]
|
28
|
+
when m = scanner.scan(Expression::CONSTANT)
|
29
|
+
@q.push [:CONSTANT, m]
|
30
|
+
when m = scanner.scan(Expression::IDENTIFIER)
|
31
|
+
@q.push [:IDENTIFIER, m]
|
32
|
+
when m = scanner.scan(/==/)
|
33
|
+
@q.push [:EQUAL, "=="]
|
34
|
+
when m = scanner.scan(/=/)
|
35
|
+
@q.push [:KEYWORD_ASSIGN, "="]
|
36
|
+
when m = scanner.scan(/\+/)
|
37
|
+
@q.push [:PLUS, "+"]
|
38
|
+
when m = scanner.scan(/\-/)
|
39
|
+
@q.push [:MINUS, "-"]
|
40
|
+
when m = scanner.scan(/\*/)
|
41
|
+
@q.push [:MULTIPLY, "*"]
|
42
|
+
when m = scanner.scan(/\//)
|
43
|
+
@q.push [:DIVIDE, "/"]
|
44
|
+
when m = scanner.scan(/>/)
|
45
|
+
@q.push [:GREATER, ">"]
|
46
|
+
when m = scanner.scan(/</)
|
47
|
+
@q.push [:LESS, "<"]
|
48
|
+
when m = scanner.scan(/\%/)
|
49
|
+
@q.push [:MOD, "%"]
|
50
|
+
when m = scanner.scan(/\(/)
|
51
|
+
@q.push [:LPAREN, "("]
|
52
|
+
when m = scanner.scan(/\)/)
|
53
|
+
@q.push [:RPAREN, ")"]
|
54
|
+
when m = scanner.scan(/\,/)
|
55
|
+
@q.push [:COMMA, ","]
|
56
|
+
when m = scanner.scan(/\./)
|
57
|
+
@q.push [:DOT, "."]
|
58
|
+
when m = scanner.scan(/\:/)
|
59
|
+
@q.push [:COLON, ":"]
|
60
|
+
when m = scanner.scan(Expression::INSTANCE_VARIABLE)
|
61
|
+
@q.push [:INSTANCE_VARIABLE, m[1..-1]]
|
62
|
+
when m = scanner.scan(/.|\n/)
|
63
|
+
@q.push [m, m]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
@q.push [false, false]
|
68
|
+
|
69
|
+
@q
|
70
|
+
end
|
71
|
+
|
72
|
+
module Expression
|
73
|
+
NEWLINE = /\r\n|\n\r|\r|\n/
|
74
|
+
|
75
|
+
SPACE_1 = /[\t ]+/
|
76
|
+
SPACE_2 = /\\[\t ]*#{NEWLINE}/
|
77
|
+
#SPACE = %r(#{SPACE_1}|#{SPACE_2})
|
78
|
+
|
79
|
+
IDENTIFIER = /[a-z]\w*/
|
80
|
+
|
81
|
+
INTEGER = /[0-9]+/
|
82
|
+
|
83
|
+
BOOLEAN = /(true|false)/
|
84
|
+
|
85
|
+
# scarry comment - bad style - beward of '\' at end of line...
|
86
|
+
comment = /\#(?:\\[ \t]*#{NEWLINE}|[^\r\n])*/m
|
87
|
+
COMMENT = %r(#{comment})m
|
88
|
+
|
89
|
+
sym_1 = /\+=|\-=|\*=|\/=|%=|\&=|\^=|\|=|<<=|>>=|##|\.\.\./
|
90
|
+
sym_2 = /==|!=|<=|>=|->|\&\&|\|\||<<|>>|\+\+|\-\-/
|
91
|
+
sym_3 = /<:|:>|<%|%>|%:%:|%:/ # Digraph
|
92
|
+
sym_4 = /[\(\)\[\]\{\}\|\&\+\-\/\*%<>\.,=!:;\?\^~#]/
|
93
|
+
SYMBOL = %r(#{sym_1}|#{sym_2}|#{sym_3}|#{sym_4})
|
94
|
+
|
95
|
+
STRING = /L?"(?:\\.|[^"])*"/m
|
96
|
+
|
97
|
+
CONSTANT = /[A-Z]\w*/
|
98
|
+
|
99
|
+
INSTANCE_VARIABLE= /\@\w+/
|
100
|
+
|
101
|
+
KEYWORDS = /class|end|require|module|def|include|true|false|if|else|elsif|alias|return/
|
102
|
+
end # Expression
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
data/lib/rgo/version.rb
ADDED
data/parse.y
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
class Rgo::Parser
|
2
|
+
options no_result_var
|
3
|
+
|
4
|
+
prechigh
|
5
|
+
nonassoc UMINUS
|
6
|
+
left '^'
|
7
|
+
left '*' '/'
|
8
|
+
left '+' '-'
|
9
|
+
preclow
|
10
|
+
|
11
|
+
rule
|
12
|
+
target
|
13
|
+
: statement_list
|
14
|
+
;
|
15
|
+
|
16
|
+
statement_list
|
17
|
+
: statement
|
18
|
+
| statement_list statement { val }
|
19
|
+
;
|
20
|
+
|
21
|
+
statement
|
22
|
+
: /* NONDE */
|
23
|
+
| comment_statement
|
24
|
+
| module_statement
|
25
|
+
| require_statement
|
26
|
+
| func_call
|
27
|
+
| func_def
|
28
|
+
| include_statement
|
29
|
+
| assignment_statement
|
30
|
+
| constant_assignment_statement
|
31
|
+
| blank_line
|
32
|
+
| if_statement
|
33
|
+
| expression_statement
|
34
|
+
| alias_statement
|
35
|
+
| return_statement
|
36
|
+
| class_statement
|
37
|
+
;
|
38
|
+
|
39
|
+
if_statement
|
40
|
+
: KEYWORD_IF LPAREN expression RPAREN statement_list KEYWORD_END
|
41
|
+
{ Node.new(:if, val[2], val[4]) }
|
42
|
+
|
43
|
+
| KEYWORD_IF LPAREN expression RPAREN statement_list KEYWORD_ELSE statement_list KEYWORD_END
|
44
|
+
{ Node.new(:if_else, val[2], [val[4], val[6]]) }
|
45
|
+
;
|
46
|
+
|
47
|
+
else_statement
|
48
|
+
: KEYWORD_ELSE statement_list
|
49
|
+
|
50
|
+
require_statement: KEYWORD_REQUIRE STRING { Node.new(:require, val[1]) }
|
51
|
+
|
52
|
+
module_statement
|
53
|
+
: KEYWORD_MODULE CONSTANT statement_list KEYWORD_END
|
54
|
+
{ Node.new(:module, val[1], val[2]) }
|
55
|
+
;
|
56
|
+
|
57
|
+
func_call: IDENTIFIER LPAREN args RPAREN { Node.new(:func_call, val[0], val[2]) }
|
58
|
+
|
59
|
+
args
|
60
|
+
: arg { Array(val[0]).flatten }
|
61
|
+
| args COMMA arg { [val[0], val[2]].flatten }
|
62
|
+
;
|
63
|
+
|
64
|
+
arg
|
65
|
+
: none
|
66
|
+
| STRING { Node.new(:string, val[0]) }
|
67
|
+
| IDENTIFIER { Node.new(:variable, val[0]) }
|
68
|
+
| expression { val[0] }
|
69
|
+
;
|
70
|
+
|
71
|
+
|
72
|
+
func_def
|
73
|
+
: KEYWORD_DEF IDENTIFIER LPAREN func_def_args RPAREN statement_list KEYWORD_END
|
74
|
+
{ Node.new(:func_def, val[1], [val[3], val[5]]) }
|
75
|
+
|
76
|
+
| KEYWORD_DEF IDENTIFIER LPAREN RPAREN statement_list KEYWORD_END
|
77
|
+
{ Node.new(:func_def, val[1], [nil, val[4]]) }
|
78
|
+
|
79
|
+
| KEYWORD_DEF IDENTIFIER statement_list KEYWORD_END
|
80
|
+
{ Node.new(:func_def, val[1], [nil, val[2]]) }
|
81
|
+
|
82
|
+
;
|
83
|
+
|
84
|
+
func_def_args
|
85
|
+
: func_def_arg { val[0] }
|
86
|
+
| func_def_args COMMA func_def_arg { [val[0], val[2]].flatten }
|
87
|
+
;
|
88
|
+
|
89
|
+
func_def_arg
|
90
|
+
: IDENTIFIER { Node.new(:variable, val[0]) }
|
91
|
+
;
|
92
|
+
|
93
|
+
include_statement: KEYWORD_INCLUDE CONSTANT { Node.new(:include, val[1]) };
|
94
|
+
|
95
|
+
comment_statement: COMMENT { Node.new(:comment, val[0]) };
|
96
|
+
|
97
|
+
assignment_statement: IDENTIFIER KEYWORD_ASSIGN expression { Node.new(:assignment, val[0], [val[2]]) }
|
98
|
+
|
99
|
+
constant_assignment_statement: CONSTANT KEYWORD_ASSIGN expression { Node.new(:constant_assignment, val[0], [val[2]]) }
|
100
|
+
|
101
|
+
expression_statement
|
102
|
+
: expression { Node.new(:return, nil, val[0]) }
|
103
|
+
;
|
104
|
+
|
105
|
+
alias_statement
|
106
|
+
: KEYWORD_ALIAS IDENTIFIER IDENTIFIER { Node.new(:alias, val[1], val[2]) }
|
107
|
+
;
|
108
|
+
|
109
|
+
expression
|
110
|
+
: IDENTIFIER '(' ')' { val[0,3].join }
|
111
|
+
| IDENTIFIER { Node.new(:variable, val[0]) }
|
112
|
+
| STRING { Node.new(:string, val[0]) }
|
113
|
+
| INTEGER { Node.new(:integer, val[0].to_i) }
|
114
|
+
| boolean
|
115
|
+
| expression number_operator expression { Node.new(val[1], nil, [val[0], val[2]]) }
|
116
|
+
| CONSTANT { Node.new(:constant, val[0]) }
|
117
|
+
| func_call
|
118
|
+
| INSTANCE_VARIABLE { Node.new(:instance_variable_get, val[0]) }
|
119
|
+
| class_new
|
120
|
+
| class_instance_method_call
|
121
|
+
;
|
122
|
+
|
123
|
+
|
124
|
+
return_statement
|
125
|
+
: KEYWORD_RETURN expression { Node.new(:return, nil, val[1]) }
|
126
|
+
;
|
127
|
+
|
128
|
+
class_statement
|
129
|
+
: KEYWORD_CLASS CONSTANT instance_variables_def methods_def KEYWORD_END
|
130
|
+
{ Node.new(:class, val[1], [val[2], val[3]]) }
|
131
|
+
;
|
132
|
+
|
133
|
+
instance_variables_def
|
134
|
+
: instance_variable_def
|
135
|
+
| instance_variables_def instance_variable_def
|
136
|
+
{ val.flatten }
|
137
|
+
;
|
138
|
+
|
139
|
+
instance_variable_def
|
140
|
+
: INSTANCE_VARIABLE { Node.new(:instance_variable_def, val[0]) }
|
141
|
+
| blank_line
|
142
|
+
| comment_statement
|
143
|
+
;
|
144
|
+
|
145
|
+
methods_def
|
146
|
+
: method_def
|
147
|
+
| methods_def method_def
|
148
|
+
{ val.flatten }
|
149
|
+
;
|
150
|
+
|
151
|
+
method_def
|
152
|
+
: comment_statement
|
153
|
+
| func_def
|
154
|
+
| blank_line
|
155
|
+
;
|
156
|
+
|
157
|
+
|
158
|
+
class_new
|
159
|
+
: CONSTANT DOT IDENTIFIER LPAREN arg_options RPAREN { Node.new(:class_method_call, val[0], [val[2], val[4]]) }
|
160
|
+
;
|
161
|
+
|
162
|
+
arg_options
|
163
|
+
: arg_option
|
164
|
+
| arg_options COMMA arg_option { [val[0], val[2]] }
|
165
|
+
;
|
166
|
+
|
167
|
+
arg_option
|
168
|
+
: none
|
169
|
+
| IDENTIFIER COLON expression { [val[0], val[2]] }
|
170
|
+
;
|
171
|
+
|
172
|
+
class_instance_method_call
|
173
|
+
: IDENTIFIER DOT IDENTIFIER LPAREN args RPAREN { Node.new(:class_instance_method_call, val[0], [val[2], val[4]]) }
|
174
|
+
|
175
|
+
number_operator
|
176
|
+
: PLUS { :plus }
|
177
|
+
| MINUS { :minus }
|
178
|
+
| MULTIPLY { :multiply }
|
179
|
+
| DIVIDE { :divide }
|
180
|
+
| GREATER { :greater }
|
181
|
+
| LESS { :less }
|
182
|
+
| EQUAL { :equal }
|
183
|
+
| MOD { :mod }
|
184
|
+
;
|
185
|
+
|
186
|
+
boolean
|
187
|
+
: KEYWORD_TRUE { Node.new(:boolean, true) }
|
188
|
+
| KEYWORD_FALSE { Node.new(:boolean, false) }
|
189
|
+
;
|
190
|
+
|
191
|
+
blank_line: BLANK_LINE { Node.new(:blank_line, "") }
|
192
|
+
|
193
|
+
none
|
194
|
+
: /* NONE */
|
195
|
+
;
|
196
|
+
end
|
197
|
+
|
198
|
+
---- header ----
|
199
|
+
|
200
|
+
require 'strscan'
|
201
|
+
require_relative './tokenizer.rb'
|
202
|
+
require_relative './node.rb'
|
203
|
+
|
204
|
+
---- inner ----
|
205
|
+
|
206
|
+
def parse(str)
|
207
|
+
@q = Tokenizer.new(str).tokens
|
208
|
+
|
209
|
+
do_parse
|
210
|
+
end
|
211
|
+
|
212
|
+
def next_token
|
213
|
+
@q.shift
|
214
|
+
end
|
215
|
+
|
216
|
+
def on_error(error_token_id, error_value, value_stack)
|
217
|
+
token_name = token_to_str(error_token_id)
|
218
|
+
token = error_value.to_s.inspect
|
219
|
+
|
220
|
+
str = 'parse error on '
|
221
|
+
str << token_name << ' ' unless token_name == token
|
222
|
+
str << token
|
223
|
+
raise str
|
224
|
+
end
|
data/rgo.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'lib/rgo/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "rgo-lang"
|
5
|
+
spec.version = Rgo::VERSION
|
6
|
+
spec.authors = ["Mohsen Alizadeh"]
|
7
|
+
spec.email = ["mohsen@alizadeh.us"]
|
8
|
+
|
9
|
+
spec.summary = %q{ruby like programming langauge}
|
10
|
+
spec.description = %q{syntax by Ruby, performance by Go}
|
11
|
+
spec.homepage = "https://github.com/mohsen-alizadeh/rgo-lang"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
14
|
+
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
+
spec.metadata["source_code_uri"] = "https://github.com/mohsen-alizadeh/rgo-lang"
|
17
|
+
spec.metadata["changelog_uri"] = "https://github.com/mohsen-alizadeh/rgo-lang"
|
18
|
+
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
end
|
24
|
+
spec.bindir = "exe"
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
|
28
|
+
spec.add_development_dependency "racc", "~> 1.4.16"
|
29
|
+
end
|