alphalang 0.2.9 → 0.3.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 +4 -4
- data/bin/alphalang +3 -1
- data/lib/alpha.rb +21 -11
- data/lib/error_handler.rb +68 -0
- data/lib/error_handler.rb~ +0 -0
- data/lib/nodes/basenodes.rb +49 -10
- data/lib/nodes/stmtnodes.rb +3 -0
- data/lib/rdparse.rb +2 -54
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c79a0fb156d98b42640f99526fcf8b6274828c07f8504b9d4b3563fdedb9078d
|
4
|
+
data.tar.gz: 9b0c5a2476e297ba4b78165608e43adb96cf4312e99f8530a1a6cb4d8d466a09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df72d6c52254c86ad8cd85000bf5e44a614d2909d1e55b1620cba8fdb2ba9a8b3552b27b8b034e4f5147752a21e51686c3613b36b237b2ced95fc4fcffafedc2
|
7
|
+
data.tar.gz: d8bc966079ac40acf1af38adf08654fd8b7961f4b79067d747d94b23f6e99cff5f7a0ee75a6829de8eb34679284b623fb6891e7f893d1eb8c655ecb7dac8ae84
|
data/bin/alphalang
CHANGED
@@ -45,7 +45,7 @@ OptionParser.new do |opts|
|
|
45
45
|
options[:listlocale] = true
|
46
46
|
end
|
47
47
|
|
48
|
-
opts.on('--printtree', '
|
48
|
+
opts.on('-p', '--printtree', 'Prints the abstract syntax tree in a simple form.') do
|
49
49
|
options[:printtree] = true
|
50
50
|
end
|
51
51
|
end.parse!
|
@@ -61,6 +61,8 @@ list_locale_flag = options[:listlocale]
|
|
61
61
|
PRINT_TREE_FLAG = options[:printtree]
|
62
62
|
TREE_ARRAY = []
|
63
63
|
|
64
|
+
raise Errno::EBADR, "Don't use --logger and --printtree together." if PRINT_TREE_FLAG and verbose_flag
|
65
|
+
|
64
66
|
if create_locale_flag
|
65
67
|
require_relative '../lib/locale_creator'
|
66
68
|
create_locale_file
|
data/lib/alpha.rb
CHANGED
@@ -24,11 +24,6 @@ class LangParser
|
|
24
24
|
|
25
25
|
start :program do
|
26
26
|
match(:comp_stmt)
|
27
|
-
match(:terminal)
|
28
|
-
end
|
29
|
-
|
30
|
-
rule :terminal do
|
31
|
-
match(/\n|;/)
|
32
27
|
end
|
33
28
|
|
34
29
|
rule :comp_stmt do
|
@@ -64,12 +59,12 @@ class LangParser
|
|
64
59
|
|
65
60
|
rule :if_comp_stmt do
|
66
61
|
match(:if_stmt, :comp_elseif, :else_stmt, :STOP) { |a, b, c| IfCompStmtNode.new(a, b, c) }
|
62
|
+
match(:if_stmt, :comp_elseif, :STOP) { |a, b| IfCompStmtNode.new(a, b) }
|
67
63
|
match(:if_stmt, :else_stmt, :STOP) { |a, b| IfCompStmtNode.new(a, b) }
|
68
64
|
match(:if_stmt, :STOP) { |a| IfCompStmtNode.new(a) }
|
69
65
|
end
|
70
66
|
|
71
67
|
rule :if_stmt do
|
72
|
-
match(:IF, :expr_stmt, :and, :expr_stmt, :comp_stmt) { |_, a, b, c, d| IfCompactNode.new(a, b, c, d) }
|
73
68
|
match(:IF, :expr_stmt, :comp_stmt) { |_, a, b| IfNode.new(a, b) }
|
74
69
|
end
|
75
70
|
|
@@ -165,15 +160,11 @@ class LangParser
|
|
165
160
|
rule :atom do
|
166
161
|
match(:number)
|
167
162
|
match(:boolean)
|
163
|
+
match(:string)
|
168
164
|
match(:call_member)
|
169
165
|
match(:prio_stmt)
|
170
166
|
end
|
171
167
|
|
172
|
-
rule :boolean do
|
173
|
-
match(ScopeManager.true_value) { |a| BoolNode.new(a) }
|
174
|
-
match(ScopeManager.false_value) { |a| BoolNode.new(a) }
|
175
|
-
end
|
176
|
-
|
177
168
|
rule :number do
|
178
169
|
match('-', /\d+/, '.', /\d+/) { |neg, a, dot, b| NumberNode.new(neg + a + dot + b) }
|
179
170
|
match(/\d+/, '.', /\d+/) { |a, dot, b| NumberNode.new(a + dot + b) }
|
@@ -181,6 +172,25 @@ class LangParser
|
|
181
172
|
match(/\d+/) { |a| NumberNode.new(a) }
|
182
173
|
end
|
183
174
|
|
175
|
+
rule :boolean do
|
176
|
+
match(ScopeManager.true_value) { |a| BoolNode.new(a) }
|
177
|
+
match(ScopeManager.false_value) { |a| BoolNode.new(a) }
|
178
|
+
end
|
179
|
+
|
180
|
+
rule :string do
|
181
|
+
match('"', :comp_string, '"') { |_, str, _| StringNode.new(str) }
|
182
|
+
end
|
183
|
+
|
184
|
+
# TODO: Figure out if this is possible with char without messing too much with lexer
|
185
|
+
rule :comp_string do
|
186
|
+
match(:word, :comp_string) { |a, b| [a, b].flatten }
|
187
|
+
match(:word)
|
188
|
+
end
|
189
|
+
|
190
|
+
rule :word do
|
191
|
+
match(/\w/) { |m| m }
|
192
|
+
end
|
193
|
+
|
184
194
|
rule :call_member do
|
185
195
|
match(:member, '(', :arg_list, ')') { |var, _, args, _| FuncCallNode.new(var, args) }
|
186
196
|
match(:member, '(', ')') { |var, _, _| FuncCallNode.new(var, NilClass) }
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Error Handler, imported by RDParse.
|
2
|
+
class ErrorHandler
|
3
|
+
class ParseError < RuntimeError
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.convert_regex_sensitive_token(token, token_list)
|
7
|
+
token = token_list['end'] if token == :STOP
|
8
|
+
token = "#{token_list['(not|!)'].split('|')[0][1..]}" if token == :NOT
|
9
|
+
token = "#{token_list['(and|&&)'].split('|')[0][1..]}" if token == :AND
|
10
|
+
token = "#{token_list['(or|\|\|)'].split('|')[0][1..]}" if token == :OR
|
11
|
+
token = '[(]' if token == '('
|
12
|
+
token = '[)]' if token == ')'
|
13
|
+
token = '[+]' if token == '+'
|
14
|
+
token = '[-]' if token == '-'
|
15
|
+
token = '[*]' if token == '*'
|
16
|
+
token = '[/]' if token == '/'
|
17
|
+
token
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.translate_tokens_array(array, token_list)
|
21
|
+
result = []
|
22
|
+
array.each do |token|
|
23
|
+
token = convert_regex_sensitive_token(token, token_list)
|
24
|
+
result << token unless token.is_a?(Symbol)
|
25
|
+
result << token_list[token.to_s.downcase] if token.is_a?(Symbol)
|
26
|
+
end
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.find_surrounding_code(problem_pos, tokens)
|
31
|
+
tokens_before_problem = []
|
32
|
+
temp = problem_pos
|
33
|
+
while temp >= 0
|
34
|
+
tokens_before_problem << tokens[temp]
|
35
|
+
temp -= 1
|
36
|
+
end
|
37
|
+
tokens_before_problem.reverse
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.find_faulty_line(pos, file_string, tokens, token_list)
|
41
|
+
tokens_before_problem = find_surrounding_code(pos - 1, tokens)
|
42
|
+
file_as_array_without_whitespaces = translate_tokens_array(tokens_before_problem, token_list)
|
43
|
+
|
44
|
+
pattern = file_as_array_without_whitespaces.join('\s*')
|
45
|
+
regex = Regexp.new(pattern)
|
46
|
+
|
47
|
+
# Remove comments, replace entire comment lines with "\n" to perserve num_lines
|
48
|
+
cleaned_string = file_string.gsub(/^;;.*/, "\n")
|
49
|
+
cleaned_string = cleaned_string.gsub(/;;.*/, '')
|
50
|
+
|
51
|
+
match_data = regex.match(cleaned_string)
|
52
|
+
num_lines = match_data[0].count("\n") + 1 unless NilClass # TODO: Find out what causes these edge cases
|
53
|
+
|
54
|
+
problem = tokens[pos]
|
55
|
+
line_msg = "There is a problem on line #{num_lines}"
|
56
|
+
line_msg = "Couldn't precise the exact line" if num_lines.is_a?(NilClass) # TODO: Find out edge cases
|
57
|
+
|
58
|
+
if tokens_before_problem[-1] == :PRINT
|
59
|
+
raise ParseError, "#{line_msg} with the <#{token_list['print']}> statement, needs something to print."
|
60
|
+
elsif tokens_before_problem[-1] == :PAUSE
|
61
|
+
raise ParseError, "#{line_msg} with the <#{token_list['pause']}> statement, pause needs a numeric argument."
|
62
|
+
elsif problem == :STOP
|
63
|
+
raise ParseError, "#{line_msg}. Found <#{token_list['end']}>\nEmpty if-statements and functions are not allowed"
|
64
|
+
else
|
65
|
+
raise ParseError, "#{line_msg}. Found <#{problem}>"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
File without changes
|
data/lib/nodes/basenodes.rb
CHANGED
@@ -45,16 +45,57 @@ class BoolNode < Node
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
# See ArrayNode for a more complete Data Structure
|
49
|
+
class StringNode < Node
|
50
|
+
def initialize(value)
|
51
|
+
if value.is_a?(String)
|
52
|
+
super
|
53
|
+
else
|
54
|
+
super(value.join(' '))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def +(other)
|
59
|
+
raise NotImplementedError, 'Addition is not implemented for Strings.'
|
60
|
+
end
|
61
|
+
|
62
|
+
def -(other)
|
63
|
+
raise NotImplementedError, 'Subtraction is not implemented for Strings.'
|
64
|
+
end
|
65
|
+
|
66
|
+
def *(other)
|
67
|
+
raise NotImplementedError, 'Multiplication is not implemented for Strings.'
|
68
|
+
end
|
69
|
+
|
70
|
+
def /(other)
|
71
|
+
raise NotImplementedError, 'Division is not implemented for Strings.'
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_i
|
75
|
+
@value.to_i
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_f
|
79
|
+
@value.to_f
|
80
|
+
end
|
81
|
+
|
82
|
+
def contains?(other)
|
83
|
+
return if @value.include?(other)
|
84
|
+
end
|
85
|
+
|
86
|
+
def evaluate
|
87
|
+
self
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
48
91
|
###################### Logic Gate Nodes
|
49
92
|
|
50
93
|
class AndNode < Node
|
51
94
|
def initialize(lhs, rhs)
|
52
95
|
@lhs, @rhs = lhs, rhs
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
96
|
+
return unless @rhs.class.method_defined?(:lhs)
|
97
|
+
|
98
|
+
@rhs.lhs = @lhs.lhs if @rhs.lhs == nil
|
58
99
|
end
|
59
100
|
|
60
101
|
def to_s
|
@@ -69,11 +110,9 @@ end
|
|
69
110
|
class OrNode < Node
|
70
111
|
def initialize(lhs, rhs)
|
71
112
|
@lhs, @rhs = lhs, rhs
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
end
|
113
|
+
return unless @rhs.class.method_defined?(:lhs)
|
114
|
+
|
115
|
+
@rhs.lhs = @lhs.lhs if @rhs.lhs == nil
|
77
116
|
end
|
78
117
|
|
79
118
|
def to_s
|
data/lib/nodes/stmtnodes.rb
CHANGED
@@ -306,6 +306,9 @@ class PauseNode < Node
|
|
306
306
|
end
|
307
307
|
|
308
308
|
def evaluate
|
309
|
+
# TODO: Create an Error Handler class... Needs to use rdparses functions here for a more helpful msg.
|
310
|
+
raise SyntaxError, 'Pause needs a numeric argument.' unless @value.evaluate.is_a?(Numeric)
|
311
|
+
|
309
312
|
@value = 0 if @value.evaluate.negative?
|
310
313
|
create_tree_entry if PRINT_TREE_FLAG
|
311
314
|
sleep @value.evaluate
|
data/lib/rdparse.rb
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
# 2014-02-16 New version that handles { false } blocks and :empty tokens.
|
9
9
|
|
10
10
|
require 'logger'
|
11
|
+
require_relative 'error_handler'
|
11
12
|
|
12
13
|
class Rule
|
13
14
|
|
@@ -187,58 +188,6 @@ class Parser
|
|
187
188
|
end # until
|
188
189
|
end
|
189
190
|
|
190
|
-
def convert_regex_sensitive_token(token)
|
191
|
-
token = @token_list['end'] if token == :STOP # fulhack pga :END påstods inte funka för länge sen
|
192
|
-
token = '[(]' if token == '('
|
193
|
-
token = '[)]' if token == ')'
|
194
|
-
token = '[+]' if token == '+'
|
195
|
-
token = '[-]' if token == '-'
|
196
|
-
token = '[*]' if token == '*'
|
197
|
-
token = '[/]' if token == '/'
|
198
|
-
token = "#{@token_list['(not|!)'].split('|')[0][1..]}" if token == :NOT
|
199
|
-
token = "#{@token_list['(and|&&)'].split('|')[0][1..]}" if token == :AND
|
200
|
-
token = "#{@token_list['(or|\|\|)'].split('|')[0][1..]}" if token == :OR
|
201
|
-
token
|
202
|
-
end
|
203
|
-
|
204
|
-
def translate_tokens_array(array)
|
205
|
-
result = []
|
206
|
-
array.each do |token|
|
207
|
-
token = convert_regex_sensitive_token(token)
|
208
|
-
result << token unless token.is_a?(Symbol)
|
209
|
-
result << @token_list[token.to_s.downcase] if token.is_a?(Symbol)
|
210
|
-
end
|
211
|
-
result
|
212
|
-
end
|
213
|
-
|
214
|
-
def find_surrounding_code(problem_pos)
|
215
|
-
tokens_before_problem = []
|
216
|
-
temp = problem_pos
|
217
|
-
while temp >= 0
|
218
|
-
tokens_before_problem << @tokens[temp]
|
219
|
-
temp -= 1
|
220
|
-
end
|
221
|
-
tokens_before_problem.reverse
|
222
|
-
end
|
223
|
-
|
224
|
-
def find_faulty_line
|
225
|
-
tokens_before_problem = find_surrounding_code(@max_pos - 1)
|
226
|
-
file_as_array_without_whitespaces = translate_tokens_array(tokens_before_problem)
|
227
|
-
|
228
|
-
pattern = file_as_array_without_whitespaces.join('\s*')
|
229
|
-
regex = Regexp.new(pattern)
|
230
|
-
|
231
|
-
cleaned_string = @file_string.gsub(/;;.*/, '')
|
232
|
-
|
233
|
-
match_data = regex.match(cleaned_string)
|
234
|
-
num_lines = match_data[0].count("\n") + 1
|
235
|
-
|
236
|
-
problem = @tokens[@max_pos]
|
237
|
-
problem = @token_list[problem.to_s.downcase] unless @token_list[problem.to_s.downcase].is_a?(NilClass)
|
238
|
-
|
239
|
-
raise ParseError, "There is a problem around line #{num_lines}. Found <#{problem}>"
|
240
|
-
end
|
241
|
-
|
242
191
|
def parse(string)
|
243
192
|
# First, split the string according to the "token" instructions given.
|
244
193
|
# Afterwards @tokens contains all tokens that are to be parsed.
|
@@ -259,8 +208,7 @@ class Parser
|
|
259
208
|
raise ParseError, 'Mismatched parenthesis! In Emacs: M-x check-parens RET'
|
260
209
|
end
|
261
210
|
|
262
|
-
|
263
|
-
return find_faulty_line
|
211
|
+
return ErrorHandler.find_faulty_line(@max_pos, @file_string, @tokens, @token_list)
|
264
212
|
end
|
265
213
|
return result
|
266
214
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alphalang
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mattias, victor
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-05-
|
11
|
+
date: 2024-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logger
|
@@ -60,6 +60,8 @@ extra_rdoc_files: []
|
|
60
60
|
files:
|
61
61
|
- bin/alphalang
|
62
62
|
- lib/alpha.rb
|
63
|
+
- lib/error_handler.rb
|
64
|
+
- lib/error_handler.rb~
|
63
65
|
- lib/locale_creator.rb
|
64
66
|
- lib/locale_defaulter.rb
|
65
67
|
- lib/locale_deleter.rb
|