alphalang 0.1.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/bin/alphalang +59 -0
- data/lib/alpha.rb +168 -0
- data/lib/lang_creator.rb +124 -0
- data/lib/locales/de +17 -0
- data/lib/locales/en +17 -0
- data/lib/locales/locale_template +17 -0
- data/lib/locales/sv +17 -0
- data/lib/nodes/#stmtnodes.rb# +196 -0
- data/lib/nodes/basenodes.rb +195 -0
- data/lib/nodes/stmtnodes.rb +200 -0
- data/lib/rdparse.rb +238 -0
- data/lib/rdparse_quiet.rb +237 -0
- data/lib/tester/fibonacci.alpha +19 -0
- data/lib/tester/test_unit.rb +217 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2f7356e9bd0fa5e53d01733fa3266b7294f969037c665941daaac523e50e3b9f
|
4
|
+
data.tar.gz: '060006929bc0e33a766c001622f0079f9f3c3c51163138c867cc5bb67f31755d'
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c1e5673759a21f75cc4d7fa14147b5a60fab5319e07ebce2349cdf35121e6a79bb1e78714c641c9061806c50ff1d9d60c2ca0c615c09f13c32f08a38eb812fb7
|
7
|
+
data.tar.gz: 53a824dd4c27bd9cf3ffb35d9db46a7b98a67b2ffd095d365cd1cc569faa835fa2d41e4e0752f3d4ba2b0c31825fd8e1000e0aca4a3e62686187ef66916e35e8
|
data/bin/alphalang
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require File.expand_path('../lib/alpha', __dir__)
|
4
|
+
|
5
|
+
basic_error_msg = "Usage: alphalang [options] file.alpha\nUsage: alphalang -h for the help menu."
|
6
|
+
|
7
|
+
options = {}
|
8
|
+
OptionParser.new do |opts|
|
9
|
+
opts.banner = basic_error_msg
|
10
|
+
|
11
|
+
opts.on('-l', '--logger', 'Run program in a very verbose manner') do
|
12
|
+
options[:verbose] = true
|
13
|
+
end
|
14
|
+
|
15
|
+
opts.on('-v', '--verify', 'Run syntax verification. Does not require a file input.') do
|
16
|
+
options[:verify] = true
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on('--lang=LOCALE', 'Set the locale language for all program keywords. Available: en, sv, de') do |lang|
|
20
|
+
options[:lang] = lang
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on('--createlocale', 'Creates a new locale-file for all program keywords available.') do
|
24
|
+
options[:createlocale] = true
|
25
|
+
end
|
26
|
+
end.parse!
|
27
|
+
|
28
|
+
verbose = options[:verbose]
|
29
|
+
verify = options[:verify]
|
30
|
+
language = options[:lang] || 'en'
|
31
|
+
createlocale = options[:createlocale]
|
32
|
+
|
33
|
+
if createlocale
|
34
|
+
require_relative'../lib/lang_creator'
|
35
|
+
create()
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
raise OptionParser::MissingArgument, "No file provided.
|
40
|
+
Usage: alphalang my_file.alpha | alphalang -h" if ARGV.empty? unless verify
|
41
|
+
raise OptionParser::InvalidArgument, 'Too many files provided.
|
42
|
+
Did you mean to use an --[option]? | alphalang -h' if ARGV.length > 1
|
43
|
+
raise OptionParser::InvalidArgument, 'File must end with .alpha' unless verify or ARGV[0].end_with?('.alpha')
|
44
|
+
|
45
|
+
if verbose
|
46
|
+
require_relative '../lib/rdparse'
|
47
|
+
else
|
48
|
+
require_relative '../lib/rdparse_quiet'
|
49
|
+
end
|
50
|
+
|
51
|
+
if verify
|
52
|
+
if !ARGV.empty?
|
53
|
+
puts 'Flag for verification found. Ignoring input file.'
|
54
|
+
sleep 1
|
55
|
+
end
|
56
|
+
require_relative '../lib/tester/test_unit'
|
57
|
+
else
|
58
|
+
LangParser.new(language).parse_file(ARGV[0])
|
59
|
+
end
|
data/lib/alpha.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
require_relative './nodes/stmtnodes'
|
2
|
+
|
3
|
+
class LangParser
|
4
|
+
def initialize(locale='en')
|
5
|
+
@langParser = Parser.new('lang parser', locale) do
|
6
|
+
token(/while/) { |_| :WHILE }
|
7
|
+
token(/print/) { |_| :PRINT }
|
8
|
+
token(/pause/) { |_| :PAUSE }
|
9
|
+
token(/def/) { |_| :DEF }
|
10
|
+
token(/end/) { |_| :STOP }
|
11
|
+
token(/if/) { |_| :IF }
|
12
|
+
token(/elseif/) { |_| :ELSEIF }
|
13
|
+
token(/else/) { |_| :ELSE }
|
14
|
+
token(/(false|true)/) { |m| m }
|
15
|
+
token(/(==|<=|>=)/) { |m| m }
|
16
|
+
token(/(not|!)/) { |_| :NOT }
|
17
|
+
token(/(and|&&)/) { |_| :AND }
|
18
|
+
token(/(or|\|\|)/) { |_| :OR }
|
19
|
+
token(/\s+/)
|
20
|
+
token(/\d+/) { |m| m }
|
21
|
+
token(/\w+/) { |m| m }
|
22
|
+
token(/./) { |m| m }
|
23
|
+
|
24
|
+
start :program do
|
25
|
+
match(:comp_stmt) { |comp_stmt| comp_stmt }
|
26
|
+
match(:terminal)
|
27
|
+
end
|
28
|
+
|
29
|
+
rule :terminal do
|
30
|
+
match(/\n|;/)
|
31
|
+
end
|
32
|
+
|
33
|
+
rule :comp_stmt do
|
34
|
+
match(:stmt, :comp_stmt) { |a, b| CompStmtNode.new([a, b]) }
|
35
|
+
match(:stmt)
|
36
|
+
end
|
37
|
+
|
38
|
+
rule :stmt do
|
39
|
+
match(:if_comp_stmt)
|
40
|
+
match(:while_stmt)
|
41
|
+
match(:func_dec)
|
42
|
+
match(:ass_stmt)
|
43
|
+
match(:pause_stmt)
|
44
|
+
match(:expr_stmt)
|
45
|
+
end
|
46
|
+
|
47
|
+
rule :if_comp_stmt do
|
48
|
+
match(:if_stmt, :comp_elseif, :else_stmt, :STOP) { |a, b, c| IfCompStmtNode.new(a, b, c) }
|
49
|
+
match(:if_stmt, :else_stmt, :STOP) { |a, b| IfCompStmtNode.new(a, b) }
|
50
|
+
match(:if_stmt, :STOP) { |a| IfCompStmtNode.new(a) }
|
51
|
+
end
|
52
|
+
|
53
|
+
rule :comp_elseif do
|
54
|
+
match(:elseif_stmt, :comp_elseif) { |a, b| [a, b] }
|
55
|
+
match(:elseif_stmt)
|
56
|
+
end
|
57
|
+
|
58
|
+
rule :if_stmt do
|
59
|
+
match(:IF, :expr_stmt, :and, :expr_stmt, :comp_stmt) { |_, a, b, c, d| IfCompactNode.new(a, b, c, d) }
|
60
|
+
match(:IF, :expr_stmt, :comp_stmt) { |_, a, b| IfNode.new(a, b) }
|
61
|
+
end
|
62
|
+
|
63
|
+
rule :elseif_stmt do
|
64
|
+
match(:ELSEIF, :expr_stmt, :comp_stmt) { |_, a, b| ElseifNode.new(a, b) }
|
65
|
+
end
|
66
|
+
|
67
|
+
rule :else_stmt do
|
68
|
+
match(:ELSE, :comp_stmt) { |_, b| ElseNode.new(b) }
|
69
|
+
end
|
70
|
+
|
71
|
+
rule :while_stmt do
|
72
|
+
match(:WHILE, :expr_stmt, :comp_stmt, :STOP) { |_, a, b| WhileLoopNode.new(a, b) }
|
73
|
+
end
|
74
|
+
|
75
|
+
rule :func_dec do
|
76
|
+
match(:DEF, :member, :comp_stmt, :STOP) { |_, name, value, _| FunctionDecNode.new(name, value) }
|
77
|
+
end
|
78
|
+
|
79
|
+
rule :ass_stmt do
|
80
|
+
match(:member, '=', :expr) { |var, _, value, _| VariableDecNode.new(var, value) }
|
81
|
+
match(:member, '=', :array_stmt) { |var, _, value| VariableDecNode.new(var, value) }
|
82
|
+
end
|
83
|
+
|
84
|
+
#array inte klar kan assigna till vaiabel men inte kolla upp än
|
85
|
+
rule :array_stmt do
|
86
|
+
match('[', :arg_list, ']') { |_, array, _| array }
|
87
|
+
end
|
88
|
+
|
89
|
+
rule :pause_stmt do
|
90
|
+
match(:PAUSE, :expr) { |_, a| PauseNode.new(a) }
|
91
|
+
end
|
92
|
+
|
93
|
+
rule :expr_stmt do
|
94
|
+
match(:or_stmt)
|
95
|
+
match(:and_stmt)
|
96
|
+
match(:not_stmt)
|
97
|
+
match(:expr)
|
98
|
+
end
|
99
|
+
|
100
|
+
rule :or_stmt do
|
101
|
+
match(:expr, :OR, :expr_stmt) { |a, _, b| OrNode.new(a, b) }
|
102
|
+
end
|
103
|
+
|
104
|
+
rule :and_stmt do
|
105
|
+
match(:expr, :AND, :expr_stmt) { |a, _, b| AndNode.new(a, b) }
|
106
|
+
end
|
107
|
+
|
108
|
+
rule :not_stmt do
|
109
|
+
match(:NOT, :expr_stmt) { |_, b| NotNode.new(b) }
|
110
|
+
end
|
111
|
+
|
112
|
+
rule :expr do
|
113
|
+
match(:expr, /(<|>)/, :expr) { |a, op, b| CompareNode.new(a, op, b) }
|
114
|
+
match(/(<|>)/, :expr) { |op, b| CompareNode.new(nil, op, b) }
|
115
|
+
match(:expr, /(<=|>=)/, :expr) { |a, op, b| CompareNode.new(a, op, b) }
|
116
|
+
match(/(<=|>=)/, :expr) { |op, b| CompareNode.new(nil, op, b) }
|
117
|
+
match(:expr, '==', :expr) { |a, op, b| CompareNode.new(a, op, b) }
|
118
|
+
match(:expr, '+', :term) { |a, op, b| BinaryOperationNode.new(a, op, b) }
|
119
|
+
match(:expr, '-', :term) { |a, op, b| BinaryOperationNode.new(a, op, b) }
|
120
|
+
match(:term)
|
121
|
+
end
|
122
|
+
|
123
|
+
rule :term do
|
124
|
+
match(:term, '*', :atom) { |a, op, b| BinaryOperationNode.new(a, op, b) }
|
125
|
+
match(:term, '/', :atom) { |a, op, b| BinaryOperationNode.new(a, op, b) }
|
126
|
+
match(:atom)
|
127
|
+
end
|
128
|
+
|
129
|
+
rule :atom do
|
130
|
+
match('-', /\d+/, '.', /\d+/) { |neg, a, dot, b| NumberNode.new((neg+a+dot+b)) }
|
131
|
+
match(/\d+/, '.', /\d+/) { |a, dot, b| NumberNode.new((a+dot+b)) }
|
132
|
+
match('-', /\d+/) { |neg, a| NumberNode.new(neg + a) }
|
133
|
+
match(/\d+/) { |a| NumberNode.new(a) }
|
134
|
+
match(/(false|true)/) { |a| BoolNode.new(a) }
|
135
|
+
match(:PRINT, :member) { |_, a| PrintNode.new(a) }
|
136
|
+
match(:PRINT, :expr) { |_, a| PrintNode.new(a) }
|
137
|
+
match(:member)
|
138
|
+
match(:prio_stmt)
|
139
|
+
end
|
140
|
+
|
141
|
+
rule :member do
|
142
|
+
match(/[a-z]/, '(', :arg_list, ')') { |var, _, args, _| FuncCallNode.new(var, args) }
|
143
|
+
match(/[a-z]/, '(', ')') { |var, _, _| FuncCallNode.new(var, NilClass) }
|
144
|
+
match(/[a-z]/) { |var| VariableCallNode.new(var) }
|
145
|
+
end
|
146
|
+
|
147
|
+
rule :arg_list do
|
148
|
+
match(:expr, ',', :arg_list) { |a, _, b| ArgListNode.new(a, b) }
|
149
|
+
match(:expr) { |a| ArgListNode.new(a, NilClass) }
|
150
|
+
end
|
151
|
+
|
152
|
+
rule :prio_stmt do
|
153
|
+
match('(', :stmt, ')') { |_, a, _| a }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def parse_file(filename)
|
159
|
+
file = File.read(filename)
|
160
|
+
root = @langParser.parse file
|
161
|
+
root.evaluate
|
162
|
+
end
|
163
|
+
|
164
|
+
def calc_test(str)
|
165
|
+
root = @langParser.parse str
|
166
|
+
root.evaluate
|
167
|
+
end
|
168
|
+
end
|
data/lib/lang_creator.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Function to read user input for translation
|
4
|
+
def read_translation(line)
|
5
|
+
puts "Enter the translation for: '#{line}' <RET> to accept '#{line}'"
|
6
|
+
translation = gets.chomp
|
7
|
+
translation = line if translation.empty?
|
8
|
+
translation
|
9
|
+
end
|
10
|
+
|
11
|
+
def read_translation_true_false(line)
|
12
|
+
word1 = /false/.match(line)
|
13
|
+
word2 = /true/.match(line)
|
14
|
+
puts "Enter the translation for: '#{word1}' <RET> to accept '#{word1}'"
|
15
|
+
translation = '('
|
16
|
+
input = gets.chomp
|
17
|
+
if input.empty?
|
18
|
+
translation += word1.to_s
|
19
|
+
else
|
20
|
+
translation += input
|
21
|
+
end
|
22
|
+
translation += '|'
|
23
|
+
puts "Enter the translation for: '#{word2}' <RET> to accept '#{word2}'"
|
24
|
+
input2 = gets.chomp
|
25
|
+
if input2.empty?
|
26
|
+
translation += word2.to_s
|
27
|
+
else
|
28
|
+
translation += input2
|
29
|
+
end
|
30
|
+
translation += ')'
|
31
|
+
translation
|
32
|
+
end
|
33
|
+
|
34
|
+
def read_translation_not_and_or(line)
|
35
|
+
word = /\w+/.match(line)
|
36
|
+
puts "Enter the translation for: '#{word}' <RET> to accept '#{word}'"
|
37
|
+
translation = '('
|
38
|
+
input = gets.chomp
|
39
|
+
if input.empty?
|
40
|
+
translation += word.to_s
|
41
|
+
else
|
42
|
+
translation += input
|
43
|
+
end
|
44
|
+
translation += /\|.+/.match(line).to_s
|
45
|
+
translation
|
46
|
+
end
|
47
|
+
def create()
|
48
|
+
# Prompt the user to choose a name for the translation file
|
49
|
+
puts "Choose a name for your translation file:"
|
50
|
+
name = gets.chomp
|
51
|
+
|
52
|
+
# Create an empty file to store translations
|
53
|
+
File.open(name, 'w') {}
|
54
|
+
|
55
|
+
# Read each line from the input file
|
56
|
+
locale_path = File.join(__dir__, "locales", 'locale_template')
|
57
|
+
|
58
|
+
# Prompt the user to translate the line
|
59
|
+
counter = 0
|
60
|
+
locale_thingies = File.readlines(locale_path)
|
61
|
+
locale_thingies.each do |line|
|
62
|
+
|
63
|
+
counter += 1
|
64
|
+
break if counter == 14
|
65
|
+
if counter < 9
|
66
|
+
translation = read_translation(line.chomp)
|
67
|
+
|
68
|
+
# Save translation after the original line
|
69
|
+
File.open(name, 'a') { |f| f.puts "#{line.chomp} #{translation}" }
|
70
|
+
end
|
71
|
+
if counter == 9
|
72
|
+
translation = read_translation_true_false(line.chomp)
|
73
|
+
File.open(name, 'a') { |f| f.puts "#{line.chomp} #{translation}" }
|
74
|
+
end
|
75
|
+
if counter == 10
|
76
|
+
File.open(name, 'a') { |f| f.puts "#{line.chomp} (==|<=|>=)" }
|
77
|
+
end
|
78
|
+
if counter > 10
|
79
|
+
translation = read_translation_not_and_or(line.chomp)
|
80
|
+
File.open(name, 'a') { |f| f.puts "#{line.chomp} #{translation}" }
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
# Append additional translations
|
86
|
+
File.open(name, 'a') do |f|
|
87
|
+
f.puts '\s+ \s+'
|
88
|
+
f.puts '\d+ \d+'
|
89
|
+
f.puts '\w+ \w+'
|
90
|
+
f.puts '. .'
|
91
|
+
end
|
92
|
+
|
93
|
+
# Clear the screen
|
94
|
+
system("clear")
|
95
|
+
|
96
|
+
# Display the contents of the translation file
|
97
|
+
puts File.read(name)
|
98
|
+
|
99
|
+
# Ask user if the translation is correct
|
100
|
+
puts "Is this correct? [Y/n]"
|
101
|
+
answer = gets.chomp
|
102
|
+
|
103
|
+
if answer.downcase == /y|Y/ or answer.empty?
|
104
|
+
puts "Translation saved to #{name}"
|
105
|
+
|
106
|
+
# Move the translation file to the desired directory
|
107
|
+
ruby_version = "" + RUBY_VERSION.to_s
|
108
|
+
ruby_version[-1] = '0'
|
109
|
+
|
110
|
+
# Find the users installation directory and place the locale file there
|
111
|
+
if File.exist?("/home/#{ENV['USER']}/.local/share/gem/ruby/#{ruby_version}/gems/alphalang-0.1.0/lib/locales/")
|
112
|
+
File.rename(name, "/home/#{ENV['USER']}/.local/share/gem/ruby/#{ruby_version}/gems/alphalang-0.1.0/lib/locales/#{name}")
|
113
|
+
# elsif File.exist?("~/var/lib/gems/#{ruby_version}/gems/alphalang-0.1.0/lib/locales/")
|
114
|
+
# File.rename(name, "~/var/lib/gems/#{ruby_version}/gems/alphalang-0.1.0/lib/locales/#{name}")
|
115
|
+
else
|
116
|
+
raise ArgumentError, "Didn't find your .local/share/gem/ruby/<VERSION>/gems/alphalang-0.1.0
|
117
|
+
Tried Ruby <VERSION> = #{ruby_version} "
|
118
|
+
end
|
119
|
+
|
120
|
+
else
|
121
|
+
puts 'Translation removed'
|
122
|
+
File.delete(name)
|
123
|
+
end
|
124
|
+
end
|
data/lib/locales/de
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
while während
|
2
|
+
print drucken
|
3
|
+
pause pause
|
4
|
+
def def
|
5
|
+
end ende
|
6
|
+
if wenn
|
7
|
+
elseif andernfalls
|
8
|
+
else sonst
|
9
|
+
(false|true) (falsch|wahr)
|
10
|
+
(==|<=|>=) (==|<=|>=)
|
11
|
+
(not|!) (nicht|!)
|
12
|
+
(and|&&) (und|&&)
|
13
|
+
(or|\|\|) (oder|\|\|)
|
14
|
+
\s+ \s+
|
15
|
+
\d+ \d+
|
16
|
+
\w+ \w+
|
17
|
+
. .
|
data/lib/locales/en
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
while while
|
2
|
+
print print
|
3
|
+
pause pause
|
4
|
+
def def
|
5
|
+
end end
|
6
|
+
if if
|
7
|
+
elseif elseif
|
8
|
+
else else
|
9
|
+
(false|true) (false|true)
|
10
|
+
(==|<=|>=) (==|<=|>=)
|
11
|
+
(not|!) (not|!)
|
12
|
+
(and|&&) (and|&&)
|
13
|
+
(or|\|\|) (or|\|\|)
|
14
|
+
\s+ \s+
|
15
|
+
\d+ \d+
|
16
|
+
\w+ \w+
|
17
|
+
. .
|
data/lib/locales/sv
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
while medan
|
2
|
+
print skriv
|
3
|
+
pause vänta
|
4
|
+
def def
|
5
|
+
end slut
|
6
|
+
if om
|
7
|
+
elseif annarsom
|
8
|
+
else annars
|
9
|
+
(false|true) (falskt|sant)
|
10
|
+
(==|<=|>=) (==|<=|>=)
|
11
|
+
(not|!) (inte|!)
|
12
|
+
(and|&&) (och|&&)
|
13
|
+
(or|\|\|) (eller|\|\|)
|
14
|
+
\s+ \s+
|
15
|
+
\d+ \d+
|
16
|
+
\w+ \w+
|
17
|
+
. .
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require_relative 'basenodes'
|
2
|
+
|
3
|
+
####################################################
|
4
|
+
class VariableCallNode < Node
|
5
|
+
attr_accessor :name
|
6
|
+
|
7
|
+
def initialize(name)
|
8
|
+
@name = name
|
9
|
+
end
|
10
|
+
|
11
|
+
def lookup_var(name)
|
12
|
+
temp_scope_lvl = $scope_lvl
|
13
|
+
while temp_scope_lvl >= 0
|
14
|
+
if not $scopes[temp_scope_lvl].has_key?(name)
|
15
|
+
temp_scope_lvl -= 1
|
16
|
+
else
|
17
|
+
return $scopes[temp_scope_lvl][name]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def evaluate
|
23
|
+
return @value = lookup_var(@name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class VariableDecNode < Node
|
28
|
+
attr_accessor :name
|
29
|
+
|
30
|
+
def initialize(name, value)
|
31
|
+
super(value)
|
32
|
+
@name = name
|
33
|
+
end
|
34
|
+
|
35
|
+
def evaluate
|
36
|
+
$scopes[$scope_lvl][@name.name] = @value.evaluate
|
37
|
+
self
|
38
|
+
# return nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
####################################################
|
43
|
+
|
44
|
+
class FunctionDecNode < Node
|
45
|
+
def initialize(node, value)
|
46
|
+
super(value)
|
47
|
+
@name = node
|
48
|
+
@args = node.args
|
49
|
+
end
|
50
|
+
|
51
|
+
def evaluate
|
52
|
+
$scopes[0][@name.name] = [@value, @args]
|
53
|
+
return nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class FuncCallNode < Node
|
58
|
+
attr_accessor :name, :args
|
59
|
+
|
60
|
+
def initialize(name, args)
|
61
|
+
@name = name
|
62
|
+
@args = args
|
63
|
+
end
|
64
|
+
|
65
|
+
def lookup_var(name)
|
66
|
+
return $scopes[0][name]
|
67
|
+
end
|
68
|
+
|
69
|
+
def evaluate
|
70
|
+
$scopes.push({})
|
71
|
+
func = lookup_var(@name)
|
72
|
+
function_body = func[0]
|
73
|
+
function_param = func[1]
|
74
|
+
|
75
|
+
return nil if func.is_a?(NilClass)
|
76
|
+
|
77
|
+
$scope_lvl += 1
|
78
|
+
|
79
|
+
if function_param.is_a?(ArgListNode)
|
80
|
+
function_param.each do |val, index|
|
81
|
+
function_param[index] = VariableDecNode.new(function_param[index].name, @args[index])
|
82
|
+
function_param[index].evaluate
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
func_result = function_body.evaluate
|
87
|
+
old_scope_lvl = $scope_lvl
|
88
|
+
|
89
|
+
if func_result.is_a?(VariableDecNode)
|
90
|
+
$scope_lvl = 0
|
91
|
+
func_result.evaluate
|
92
|
+
$scope_lvl = old_scope_lvl
|
93
|
+
end
|
94
|
+
|
95
|
+
$scope_lvl -= 1
|
96
|
+
$scopes.pop
|
97
|
+
return func_result
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
####################################################
|
102
|
+
|
103
|
+
class IfNode < Node
|
104
|
+
attr_accessor :argument
|
105
|
+
|
106
|
+
def initialize(argument, node)
|
107
|
+
@argument, @node = argument, node
|
108
|
+
end
|
109
|
+
|
110
|
+
def evaluate
|
111
|
+
if @argument.evaluate
|
112
|
+
@value = @node.evaluate
|
113
|
+
else
|
114
|
+
@value = nil
|
115
|
+
end
|
116
|
+
@value
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class ElseifNode < Node
|
121
|
+
def initialize(argument, node)
|
122
|
+
@argument, @node = argument, node
|
123
|
+
end
|
124
|
+
def evaluate
|
125
|
+
if @argument.evaluate
|
126
|
+
@value = @node.evaluate
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class ElseNode < Node
|
132
|
+
def initialize(node)
|
133
|
+
@node = node
|
134
|
+
end
|
135
|
+
|
136
|
+
def evaluate
|
137
|
+
@value = @node.evaluate
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class IfCompStmtNode < Node
|
142
|
+
def initialize(*nodes)
|
143
|
+
@nodes = nodes
|
144
|
+
end
|
145
|
+
def evaluate
|
146
|
+
if @nodes[0].argument.evaluate
|
147
|
+
return @nodes[0].evaluate
|
148
|
+
else
|
149
|
+
return nil if @nodes[1] == nil # hmm??
|
150
|
+
return @nodes[1].evaluate
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
####################################################
|
156
|
+
|
157
|
+
class WhileLoopNode < Node
|
158
|
+
attr_accessor :condition
|
159
|
+
|
160
|
+
def initialize(condition, statement)
|
161
|
+
@condition = condition
|
162
|
+
super(statement)
|
163
|
+
end
|
164
|
+
|
165
|
+
def evaluate
|
166
|
+
while @condition.evaluate
|
167
|
+
@value.evaluate
|
168
|
+
end
|
169
|
+
self.class
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
####################################################
|
174
|
+
|
175
|
+
class PrintNode
|
176
|
+
attr_accessor :value
|
177
|
+
|
178
|
+
def initialize(value)
|
179
|
+
@value = value
|
180
|
+
end
|
181
|
+
|
182
|
+
def evaluate
|
183
|
+
puts @value.evaluate
|
184
|
+
self.class # detta kanske är trevligare än nil, åter igen den diskussionen.
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class PauseNode < Node
|
189
|
+
def initialize(value)
|
190
|
+
super(value)
|
191
|
+
end
|
192
|
+
|
193
|
+
def evaluate
|
194
|
+
sleep @value.evaluate
|
195
|
+
end
|
196
|
+
end
|