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.
@@ -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
+
@@ -0,0 +1,3 @@
1
+ module Rgo
2
+ VERSION = "0.1.0"
3
+ end
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
@@ -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
@@ -0,0 +1,7 @@
1
+ package main
2
+
3
+ import "fmt"
4
+
5
+ func main() {
6
+ fmt.Println("hello world")
7
+ }
@@ -0,0 +1,7 @@
1
+ module Main
2
+ include Fmt
3
+
4
+ def main
5
+ println("hello world")
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ package main
2
+
3
+ import "fmt"
4
+
5
+ func main() {
6
+ // string
7
+ var a = "mohsen"
8
+ fmt.Println(a)
9
+
10
+ // integer
11
+ var b = 9
12
+ fmt.Println(b)
13
+
14
+ // boolean
15
+ var d = true
16
+ fmt.Println(d)
17
+ }
@@ -0,0 +1,17 @@
1
+ module Main
2
+ include Fmt
3
+
4
+ def main
5
+ # string
6
+ a = "mohsen"
7
+ println(a)
8
+
9
+ # integer
10
+ b = 9
11
+ println(b)
12
+
13
+ # boolean
14
+ d = true
15
+ println(d)
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ package main
2
+
3
+ import "fmt"
4
+
5
+ func main() {
6
+ if 7 % 2 == 0 {
7
+ fmt.Println("7 is even")
8
+ }
9
+
10
+ if 7 % 2 == 0 {
11
+ fmt.Println("7 is even")
12
+ } else {
13
+ fmt.Println("7 is odd")
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ module Main
2
+ include Fmt
3
+
4
+ def main
5
+ if (7%2 == 0)
6
+ println("7 is even")
7
+ end
8
+
9
+ if (7%2 == 0)
10
+ println("7 is even")
11
+ else
12
+ println("7 is odd")
13
+ end
14
+ end
15
+ end