eleetscript 0.0.2a

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.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/bin/eleet +89 -0
  3. data/lib/eleetscript.rb +18 -0
  4. data/lib/engine/eleet_engine.rb +58 -0
  5. data/lib/engine/eleet_to_ruby_wrapper.rb +25 -0
  6. data/lib/engine/ruby_to_eleet_wrapper.rb +22 -0
  7. data/lib/engine/values.rb +55 -0
  8. data/lib/lang/grammar.y +350 -0
  9. data/lib/lang/interpreter.rb +400 -0
  10. data/lib/lang/lexer.rb +92 -0
  11. data/lib/lang/nodes.rb +197 -0
  12. data/lib/lang/parser.output +11953 -0
  13. data/lib/lang/parser.rb +2300 -0
  14. data/lib/lang/runtime/array.rb +23 -0
  15. data/lib/lang/runtime/base_classes.rb +31 -0
  16. data/lib/lang/runtime/bootstrap.rb +3 -0
  17. data/lib/lang/runtime/class.rb +113 -0
  18. data/lib/lang/runtime/class_instance.rb +53 -0
  19. data/lib/lang/runtime/class_skeleton.rb +57 -0
  20. data/lib/lang/runtime/context.rb +263 -0
  21. data/lib/lang/runtime/eleetscript/enumerable.es +36 -0
  22. data/lib/lang/runtime/eleetscript/falseclass.es +25 -0
  23. data/lib/lang/runtime/eleetscript/integer.es +11 -0
  24. data/lib/lang/runtime/eleetscript/list.es +44 -0
  25. data/lib/lang/runtime/eleetscript/nilclass.es +5 -0
  26. data/lib/lang/runtime/eleetscript/number.es +13 -0
  27. data/lib/lang/runtime/eleetscript/object.es +49 -0
  28. data/lib/lang/runtime/eleetscript/pair.es +12 -0
  29. data/lib/lang/runtime/eleetscript/que.es +13 -0
  30. data/lib/lang/runtime/eleetscript/stack.es +14 -0
  31. data/lib/lang/runtime/eleetscript/string.es +34 -0
  32. data/lib/lang/runtime/eleetscript/trueclass.es +25 -0
  33. data/lib/lang/runtime/memory.rb +553 -0
  34. data/lib/lang/runtime/method.rb +32 -0
  35. data/lib/lang/runtime/method_hash.rb +40 -0
  36. data/lib/util/processed_key_hash.rb +34 -0
  37. metadata +79 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e792bada3731aaa44a090f809417bdecadce8872
4
+ data.tar.gz: aef6dd9deb080c59562f72ad574fed5d9bb7a345
5
+ SHA512:
6
+ metadata.gz: c519caee6985956c60165f6d5f35f9c07c336249483c49ad46e171c50c5ffafcdc11780fe1ac2b8371e40608f11a4c9f1dcbde0dde28fbcd04684edcf2ab9935
7
+ data.tar.gz: b2c6387ce4f580c955a778d2810a755eb5ca2b4bd454b68976ef9723e421c649aeebf46d7457b96df62a1a29226a32fe38e8008c2d3e23cc34e78280172441dc
data/bin/eleet ADDED
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env ruby
2
+ require "readline"
3
+
4
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
5
+ require "lang/interpreter"
6
+
7
+ def exit_repl
8
+ puts "\n\nExiting EleetScript REPL"
9
+ exit
10
+ end
11
+
12
+ Signal.trap("INT") do
13
+ exit_repl
14
+ end
15
+
16
+ interp = ES::Interpreter.new
17
+ @lexer = ES::Lexer.new
18
+
19
+ if ARGV.empty?
20
+ show_nodes = false
21
+ interp.memory.root_namespace["Object"].def :__repl_show_nodes do |receiver, arguments|
22
+ bool = !!arguments.first.ruby_value
23
+ show_nodes = bool
24
+ arguments.first
25
+ end
26
+
27
+ interp.memory.root_namespace["Object"].def :exit do |receiver, arguments|
28
+ exit_repl
29
+ end
30
+
31
+ def depth(code)
32
+ begin
33
+ tokens = @lexer.tokenize(code)
34
+ rescue
35
+ return 0
36
+ end
37
+ depth = 0
38
+ tokens.each do |token|
39
+ depth += 1 if ["class", "do", "while", "if", "(", "namespace", "{"].include?(token[1])
40
+ depth -= 1 if ["end", ")", "}"].include?(token[1])
41
+ end
42
+ depth
43
+ end
44
+
45
+ line = 1
46
+ line_depth = 0
47
+ code = ""
48
+
49
+ while true
50
+ prompt = if line_depth > 0
51
+ spaces = " " * line_depth
52
+ stars = line.to_s.gsub(/./, "*")
53
+ "#{stars} >> #{spaces}"
54
+ else
55
+ "#{line} >> "
56
+ end
57
+ input = Readline.readline(prompt, true)
58
+ if code.length > 0
59
+ input = code + "\n" + input
60
+ end
61
+ if depth(input) == 0
62
+ begin
63
+ value = interp.eval(input, show_nodes)
64
+ rescue => e
65
+ puts "Error: #{e.message}"
66
+ next
67
+ end
68
+ if value.kind_of?(ES::EleetScriptClass) || value.kind_of?(ES::EleetScriptClassInstance)
69
+ if ["Integer", "Float", "String", "TrueClass", "FalseClass", "NilClass"].include?(value.class_name)
70
+ puts " => #{value.ruby_value.inspect}"
71
+ else
72
+ puts " => #{value.call(:inspect).ruby_value}"
73
+ end
74
+ else
75
+ puts "Improper value returned"
76
+ p value
77
+ end
78
+ line_depth = 0
79
+ code = ""
80
+ else
81
+ line_depth = depth(input)
82
+ line_depth = 0 if line_depth < 0
83
+ code = input
84
+ end
85
+ line += 1
86
+ end
87
+ elsif File.exists?(ARGV[0])
88
+ interp.eval(File.read(ARGV[0]))
89
+ end
@@ -0,0 +1,18 @@
1
+ module EleetScript
2
+ class LexicalError < RuntimeError
3
+ def initialize(char, line)
4
+ @char = char
5
+ @line = line
6
+ end
7
+
8
+ def message
9
+ "Unknown character encountered '#{@char}' on line ##{@line}"
10
+ end
11
+ end
12
+
13
+ class ParseError < RuntimeError; end
14
+ end
15
+
16
+ ES = EleetScript
17
+
18
+ require "lang/interpreter"
@@ -0,0 +1,58 @@
1
+ require "lang/runtime/memory"
2
+ require "lang/interpreter"
3
+ require "engine/values"
4
+
5
+ module EleetScript
6
+ class Engine
7
+ def initialize
8
+ @memory = Memory.new
9
+ @interpreter = Interpreter.new(@memory)
10
+ end
11
+
12
+ def execute(code)
13
+ to_ruby_value(@interpreter.eval(code))
14
+ end
15
+
16
+ def call(method, *args)
17
+ # TODO: Finish
18
+ to_ruby_value(@interpreter.eval("#{method.to_s}"))
19
+ end
20
+
21
+ def get(var, raw = false)
22
+ value = @memory.root_namespace[var]
23
+ if raw
24
+ value
25
+ else
26
+ to_ruby_value(value)
27
+ end
28
+ end
29
+
30
+ def set(var, value)
31
+ nesting = var.split("::")
32
+ ns = @memory.root_namespace
33
+ var = nesting.pop
34
+ nesting.each do |new_ns|
35
+ ns = ns.namespace(new_ns)
36
+ end
37
+ if var[0] =~ /[A-Z]/
38
+ if ns.constants.has_key?(var)
39
+ @memory.root_namespace["Errors"].call("<", [@memory.root_namespace["String"].new_with_value("Cannot reassign constant via the Engine.")])
40
+ return false
41
+ else
42
+ ns[var] = to_eleet_value(value)
43
+ end
44
+ else
45
+ ns[var] = to_eleet_value(value)
46
+ end
47
+ true
48
+ end
49
+
50
+ def to_eleet_value(value)
51
+ Values.to_eleet_value(value, self)
52
+ end
53
+
54
+ def to_ruby_value(value)
55
+ Values.to_ruby_value(value, self)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,25 @@
1
+ module EleetScript
2
+ class EleetToRubyWrapper
3
+ def initialize(eleet_obj, engine)
4
+ @eleet_obj = eleet_obj
5
+ @engine = engine
6
+ end
7
+
8
+ def call(method, *args)
9
+ eleet_args = args.map { |a| Values.to_eleet_value(a, @engine) }
10
+ Values.to_ruby_value(@eleet_obj.call(method, eleet_args), @engine)
11
+ end
12
+
13
+ def method_missing(name, *args)
14
+ if args && args.length > 0
15
+ call(name, *args)
16
+ else
17
+ call(name)
18
+ end
19
+ end
20
+
21
+ def raw
22
+ @eleet_obj
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ module EleetScript
2
+ class RubyToEleetWrapper
3
+ def initialize(ruby_obj, engine)
4
+ @ruby_obj = ruby_obj
5
+ @engine = engine
6
+ end
7
+
8
+ def call(method_name, args)
9
+ binding.pry
10
+ ruby_args = args.map { |arg| Values.to_ruby_value(arg, @engine) }
11
+ if @ruby_obj.respond_to?(method_name)
12
+ Values.to_eleet_value(@ruby_obj.send(method_name, *ruby_args), @engine)
13
+ else
14
+ Values.to_eleet_value(@engine.get("nil"), @engine)
15
+ end
16
+ end
17
+
18
+ def raw
19
+ @ruby_obj
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,55 @@
1
+ require "bigdecimal"
2
+ require "engine/eleet_to_ruby_wrapper"
3
+ require "engine/ruby_to_eleet_wrapper"
4
+
5
+ module EleetScript
6
+ module Values
7
+ class << self
8
+ def to_eleet_value(ruby_obj, engine)
9
+ memory = if engine.kind_of?(Memory)
10
+ engine
11
+ else
12
+ engine.instance_variable_get("@memory")
13
+ end
14
+ if ruby_obj.kind_of?(EleetToRubyWrapper)
15
+ ruby_obj.instance_variable_get("@eleet_obj")
16
+ elsif ruby_obj.kind_of?(String)
17
+ memory.root_namespace["String"].new_with_value(ruby_obj)
18
+ elsif ruby_obj.kind_of?(Fixnum)
19
+ memory.root_namespace["Integer"].new_with_value(ruby_obj)
20
+ elsif ruby_obj.kind_of?(Float)
21
+ memory.root_namespace["Float"].new_with_value(ruby_obj)
22
+ elsif ruby_obj.kind_of?(BigDecimal)
23
+ memory.root_namespace["Integer"].new_with_value(ruby_obj.to_i)
24
+ elsif ruby_obj.kind_of?(Array)
25
+ eleet_arr = ruby_obj.map { |v| to_eleet_value(v, memory) }
26
+ memory.root_namespace["List"].new_with_value(eleet_arr)
27
+ elsif ruby_obj.kind_of?(Hash)
28
+ eleet_arr = ruby_obj.map do |k, v|
29
+ memory.root_namespace["Pair"].call(:new, to_eleet_value(k, memory), to_eleet_value(v, memory))
30
+ end
31
+ memory.root_namespace["List"].new_with_value(eleet_arr)
32
+ elsif ruby_obj.nil?
33
+ memory.root_namespace["nil"]
34
+ elsif ruby_obj == true
35
+ memory.root_namesapce["true"]
36
+ elsif ruby_obj == false
37
+ memory.root_namesapce["false"]
38
+ else
39
+ RubyToEleetWrapper.new(ruby_obj, engine)
40
+ end
41
+ end
42
+
43
+ def to_ruby_value(eleet_obj, engine)
44
+ ruby_values = ["TrueClass", "FalseClass", "NilClass", "String", "Integer", "Float"]
45
+ if eleet_obj.kind_of?(RubyToEleetWrapper)
46
+ eleet_obj.instance_variable_get("@ruby_obj")
47
+ elsif ruby_values.include?(eleet_obj.class_name)
48
+ eleet_obj.ruby_value
49
+ else
50
+ EleetToRubyWrapper.new(eleet_obj, engine)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,350 @@
1
+ class Parser
2
+
3
+ token DO END CLASS LOAD IF WHILE NAMESPACE ELSE ELSIF RETURN BREAK NEXT TRUE
4
+ token YES ON FALSE NO OFF NIL SELF DEFINED PROPERTY RETURN
5
+ token CONSTANT GLOBAL CLASS_IDENTIFIER INSTANCE_IDENTIFIER IDENTIFIER
6
+ token FLOAT NUMBER STRING TERMINATOR EOF
7
+
8
+ prechigh
9
+ left '.'
10
+ left '**'
11
+ left '*' '/' '%'
12
+ left '+' '-'
13
+ right '-'
14
+ left '>' '<' '>=' '<='
15
+ left 'is' 'isnt'
16
+ right 'not'
17
+ left 'and'
18
+ left 'or'
19
+ right '=' '*=' '/=' '%=' '+=' '-=' '**='
20
+ preclow
21
+
22
+ rule
23
+ Program:
24
+ /* nothing */ { result = Nodes.new([]) }
25
+ | Expressions EOF { result = val[0] }
26
+ ;
27
+
28
+ Expressions:
29
+ Expression { result = Nodes.new(val) }
30
+ | Expressions Terminator Expression { result = val[0] << val[2] }
31
+ | Expressions Terminator { result = val[0] }
32
+ | Terminator { result = Nodes.new([]) }
33
+ ;
34
+
35
+ Terminator:
36
+ TERMINATOR Terminator
37
+ | TERMINATOR
38
+ ;
39
+
40
+ Expression:
41
+ Literal
42
+ | AssignmentFunction
43
+ | Call
44
+ | SELF { result = SelfNode.new }
45
+ | NEXT { result = NextNode.new }
46
+ | KeyValExpression
47
+ | ListExpression
48
+ | NamespaceAccess
49
+ | Defined
50
+ | DefMethod
51
+ | Operation
52
+ | SetVariable
53
+ | GetVariable
54
+ | Namespace
55
+ | Class
56
+ | If
57
+ | While
58
+ | Return
59
+ | Property
60
+ | Lambda
61
+ | '(' Expression ')' { result = val[1] }
62
+ ;
63
+
64
+ GetVariable:
65
+ CONSTANT { result = GetConstantNode.new(val[0]) }
66
+ | GLOBAL { result = GetGlobalNode.new(val[0]) }
67
+ | CLASS_IDENTIFIER { result = GetClassVarNode.new(val[0]) }
68
+ | INSTANCE_IDENTIFIER { result = GetInstanceVarNode.new(val[0]) }
69
+ | IDENTIFIER { result = GetLocalNode.new(val[0]) }
70
+ ;
71
+
72
+ Literal:
73
+ NUMBER { result = IntegerNode.new(val[0].to_i) }
74
+ | FLOAT { result = FloatNode.new(val[0].to_f) }
75
+ | STRING { result = StringNode.new(val[0]) }
76
+ | True { result = TrueNode.new }
77
+ | False { result = FalseNode.new }
78
+ | NIL { result = NilNode.new }
79
+ ;
80
+
81
+ ListExpression:
82
+ List
83
+ | Expression '[' Expression ']' '=' Expression { result = CallNode.new(val[0], "[]=", [val[2], val[5]], nil) }
84
+ | Expression '[' Expression ']' { result = CallNode.new(val[0], "[]", [val[2]], nil) }
85
+ ;
86
+
87
+ List:
88
+ '[' ']' { result = CallNode.new(GetConstantNode.new("List"), "new", [], nil) }
89
+ | '[' Terminator ExpressionList ']' { result = CallNode.new(GetConstantNode.new("List"), "new", val[2], nil) }
90
+ | '[' Terminator ExpressionList Terminator ']' { result = CallNode.new(GetConstantNode.new("List"), "new", val[2], nil) }
91
+ | '[' ExpressionList ']' { result = CallNode.new(GetConstantNode.new("List"), "new", val[1], nil) }
92
+ ;
93
+
94
+ ExpressionList:
95
+ Expression { result = val }
96
+ | ExpressionList ',' Terminator Expression { result = val[0] << val[3] }
97
+ | ExpressionList Terminator ',' Expression { result = val[0] << val[3] }
98
+ | ExpressionList ',' Expression { result = val[0] << val[2] }
99
+ ;
100
+
101
+ KeyValExpression:
102
+ Expression '=>' Expression { result = CallNode.new(GetConstantNode.new("Pair"), "new", [val[0], val[2]], nil) }
103
+ ;
104
+
105
+ True:
106
+ TRUE
107
+ | YES
108
+ | ON
109
+ ;
110
+
111
+ False:
112
+ FALSE
113
+ | NO
114
+ | OFF
115
+ ;
116
+
117
+ AssignmentFunction
118
+ Expression '.' IDENTIFIER '=' Expression { result = CallNode.new(val[0], "#{val[2]}=", [val[4]], nil) }
119
+ ;
120
+
121
+ Call:
122
+ IDENTIFIER Lambda { result = CallNode.new(nil, val[0], [], val[1]) }
123
+ | IDENTIFIER Arguments Lambda { result = CallNode.new(nil, val[0], val[1], val[2]) }
124
+ | IDENTIFIER Arguments { result = CallNode.new(nil, val[0], val[1], nil) }
125
+ | Expression '.' IDENTIFIER Arguments Lambda { result = CallNode.new(val[0], val[2], val[3], val[4]) }
126
+ | Expression '.' IDENTIFIER Arguments { result = CallNode.new(val[0], val[2], val[3], nil) }
127
+ | Expression '.' IDENTIFIER Lambda { result = CallNode.new(val[0], val[2], [], val[3]) }
128
+ | Expression '.' IDENTIFIER { result = CallNode.new(val[0], val[2], [], nil) }
129
+ | Expression '.' Operator Arguments { result = CallNode.new(val[0], val[2], val[3], nil) }
130
+ | Expression '.' 'not' { result = CallNode.new(val[0], val[2], [], nil) }
131
+ ;
132
+
133
+ Arguments:
134
+ '(' ')' { result = [] }
135
+ | '(' ArgList ')' { result = val[1] }
136
+ ;
137
+
138
+ ArgList:
139
+ Expression { result = val }
140
+ | ArgList ',' Expression { result = val[0] << val[2] }
141
+ ;
142
+
143
+ Lambda:
144
+ '->' '{' Parameters Expressions '}' { result = LambdaNode.new(val[2], val[3]) }
145
+ ;
146
+
147
+ Defined:
148
+ DEFINED '(' GetVariable ')' { result = DefinedNode.new(val[2]) }
149
+ ;
150
+
151
+ NamespaceAccess:
152
+ CONSTANT '::' Expression { result = NamespaceAccessNode.new(val[0], val[2]) }
153
+ | '::' Expression { result = NamespaceAccessNode.new(nil, val[1]) }
154
+ ;
155
+
156
+ Operation:
157
+ Expression '+' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
158
+ | Expression '-' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
159
+ | '-' Expression { result = CallNode.new(val[1], "negate", [], nil) }
160
+ | Expression '*' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
161
+ | Expression '**' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
162
+ | Expression '/' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
163
+ | Expression '%' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
164
+ | Expression '>' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
165
+ | Expression '>=' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
166
+ | Expression '<' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
167
+ | Expression '<=' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
168
+ | OperatorAssignment
169
+ | 'not' Expression { result = CallNode.new(val[1], val[0], [], nil) }
170
+ | Expression 'and' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
171
+ | Expression 'or' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
172
+ | Expression 'is' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
173
+ | Expression 'isnt' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
174
+ ;
175
+
176
+ OperatorAssignment:
177
+ CONSTANT '+=' Expression { result = SetConstantNode.new(val[0], CallNode.new(GetConstantNode.new(val[0]), "+", [val[2]], nil)) }
178
+ | GLOBAL '+=' Expression { result = SetGlobalNode.new(val[0], CallNode.new(GetGlobalNode.new(val[0]), "+", [val[2]], nil)) }
179
+ | CLASS_IDENTIFIER '+=' Expression { result = SetClassVarNode.new(val[0], CallNode.new(GetClassVarNode.new(val[0]), "+", [val[2]], nil)) }
180
+ | INSTANCE_IDENTIFIER '+=' Expression { result = SetInstanceVarNode.new(val[0], CallNode.new(GetInstanceVarNode.new(val[0]), "+", [val[2]], nil)) }
181
+ | IDENTIFIER '+=' Expression { result = SetLocalNode.new(val[0], CallNode.new(GetLocalNode.new(val[0]), "+", [val[2]], nil)) }
182
+ | CONSTANT '-=' Expression { result = SetConstantNode.new(val[0], CallNode.new(GetConstantNode.new(val[0]), "-", [val[2]], nil)) }
183
+ | GLOBAL '-=' Expression { result = SetGlobalNode.new(val[0], CallNode.new(GetGlobalNode.new(val[0]), "-", [val[2]], nil)) }
184
+ | CLASS_IDENTIFIER '-=' Expression { result = SetClassVarNode.new(val[0], CallNode.new(GetClassVarNode.new(val[0]), "-", [val[2]], nil)) }
185
+ | INSTANCE_IDENTIFIER '-=' Expression { result = SetInstanceVarNode.new(val[0], CallNode.new(GetInstanceVarNode.new(val[0]), "-", [val[2]], nil)) }
186
+ | IDENTIFIER '-=' Expression { result = SetLocalNode.new(val[0], CallNode.new(GetLocalNode.new(val[0]), "-", [val[2]], nil)) }
187
+ | CONSTANT '*=' Expression { result = SetConstantNode.new(val[0], CallNode.new(GetConstantNode.new(val[0]), "*", [val[2]], nil)) }
188
+ | GLOBAL '*=' Expression { result = SetGlobalNode.new(val[0], CallNode.new(GetGlobalNode.new(val[0]), "*", [val[2]], nil)) }
189
+ | CLASS_IDENTIFIER '*=' Expression { result = SetClassVarNode.new(val[0], CallNode.new(GetClassVarNode.new(val[0]), "*", [val[2]], nil)) }
190
+ | INSTANCE_IDENTIFIER '*=' Expression { result = SetInstanceVarNode.new(val[0], CallNode.new(GetInstanceVarNode.new(val[0]), "*", [val[2]], nil)) }
191
+ | IDENTIFIER '*=' Expression { result = SetLocalNode.new(val[0], CallNode.new(GetLocalNode.new(val[0]), "*", [val[2]], nil)) }
192
+ | CONSTANT '/=' Expression { result = SetConstantNode.new(val[0], CallNode.new(GetConstantNode.new(val[0]), "/", [val[2]], nil)) }
193
+ | GLOBAL '/=' Expression { result = SetGlobalNode.new(val[0], CallNode.new(GetGlobalNode.new(val[0]), "/", [val[2]], nil)) }
194
+ | CLASS_IDENTIFIER '/=' Expression { result = SetClassVarNode.new(val[0], CallNode.new(GetClassVarNode.new(val[0]), "/", [val[2]], nil)) }
195
+ | INSTANCE_IDENTIFIER '/=' Expression { result = SetInstanceVarNode.new(val[0], CallNode.new(GetInstanceVarNode.new(val[0]), "/", [val[2]], nil)) }
196
+ | IDENTIFIER '/=' Expression { result = SetLocalNode.new(val[0], CallNode.new(GetLocalNode.new(val[0]), "/", [val[2]], nil)) }
197
+ | CONSTANT '%=' Expression { result = SetConstantNode.new(val[0], CallNode.new(GetConstantNode.new(val[0]), "%", [val[2]], nil)) }
198
+ | GLOBAL '%=' Expression { result = SetGlobalNode.new(val[0], CallNode.new(GetGlobalNode.new(val[0]), "%", [val[2]], nil)) }
199
+ | CLASS_IDENTIFIER '%=' Expression { result = SetClassVarNode.new(val[0], CallNode.new(GetClassVarNode.new(val[0]), "%", [val[2]], nil)) }
200
+ | INSTANCE_IDENTIFIER '%=' Expression { result = SetInstanceVarNode.new(val[0], CallNode.new(GetInstanceVarNode.new(val[0]), "%", [val[2]], nil)) }
201
+ | IDENTIFIER '%=' Expression { result = SetLocalNode.new(val[0], CallNode.new(GetLocalNode.new(val[0]), "%", [val[2]], nil)) }
202
+ | CONSTANT '**=' Expression { result = SetConstantNode.new(val[0], CallNode.new(GetConstantNode.new(val[0]), "**", [val[2]], nil)) }
203
+ | GLOBAL '**=' Expression { result = SetGlobalNode.new(val[0], CallNode.new(GetGlobalNode.new(val[0]), "**", [val[2]], nil)) }
204
+ | CLASS_IDENTIFIER '**=' Expression { result = SetClassVarNode.new(val[0], CallNode.new(GetClassVarNode.new(val[0]), "**", [val[2]], nil)) }
205
+ | INSTANCE_IDENTIFIER '**=' Expression { result = SetInstanceVarNode.new(val[0], CallNode.new(GetInstanceVarNode.new(val[0]), "**", [val[2]], nil)) }
206
+ | IDENTIFIER '**=' Expression { result = SetLocalNode.new(val[0], CallNode.new(GetLocalNode.new(val[0]), "**", [val[2]], nil)) }
207
+ | IDENTIFIER '.=' IDENTIFIER Arguments Lambda { result = SetLocalNode.new(val[0], CallNode.new(GetLocalNode.new(val[0]), val[2], val[3], val[4])) }
208
+ | IDENTIFIER '.=' IDENTIFIER Arguments { result = SetLocalNode.new(val[0], CallNode.new(GetLocalNode.new(val[0]), val[2], val[3], nil)) }
209
+ | IDENTIFIER '.=' IDENTIFIER { result = SetLocalNode.new(val[0], CallNode.new(GetLocalNode.new(val[0]), val[2], [], nil)) }
210
+ ;
211
+
212
+ SetVariable:
213
+ CONSTANT '=' Literal { result = SetConstantNode.new(val[0], val[2]) }
214
+ | GLOBAL '=' Expression { result = SetGlobalNode.new(val[0], val[2]) }
215
+ | CLASS_IDENTIFIER '=' Expression { result = SetClassVarNode.new(val[0], val[2]) }
216
+ | INSTANCE_IDENTIFIER '=' Expression { result = SetInstanceVarNode.new(val[0], val[2]) }
217
+ | IDENTIFIER '=' Expression { result = SetLocalNode.new(val[0], val[2]) }
218
+ ;
219
+
220
+ DefMethod:
221
+ IDENTIFIER MethodBlock { result = DefMethodNode.new(val[0], val[1]) }
222
+ | CLASS_IDENTIFIER MethodBlock { result = DefMethodNode.new(val[0], val[1]) }
223
+ | Operator MethodBlock { result = DefMethodNode.new(val[0], val[1]) }
224
+ | '[' ']' '=' MethodBlock { result = DefMethodNode.new("[]=", val[3]) }
225
+ | '[' ']' MethodBlock { result = DefMethodNode.new("[]", val[2]) }
226
+ ;
227
+
228
+ MethodBlock:
229
+ DO Parameters Expressions END { result = MethodNode.new(val[1], val[2]) }
230
+ | DO Parameters END { result = MethodNode.new(val[1], Nodes.new([])) }
231
+ ;
232
+
233
+ Operator:
234
+ '+'
235
+ | '-'
236
+ | '*'
237
+ | '/'
238
+ | '%'
239
+ | '**'
240
+ | '[]'
241
+ | '[]='
242
+ | 'and'
243
+ | 'or'
244
+ | 'not'
245
+ | 'is'
246
+ | 'isnt'
247
+ | '>'
248
+ | '>='
249
+ | '<='
250
+ | '<'
251
+ ;
252
+
253
+
254
+
255
+ Parameters:
256
+ /* nothing */ { result = [] }
257
+ | Terminator { result = [] }
258
+ | '|' ParamList '|' Terminator { result = val[1] }
259
+ | '|' ParamList '|' { result = val[1] }
260
+ ;
261
+
262
+ ParamList:
263
+ Parameter { result = val }
264
+ | ParamList ',' Parameter { result = val[0] << val[2] }
265
+ ;
266
+
267
+ Parameter:
268
+ IDENTIFIER { result = val[0] }
269
+ | INSTANCE_IDENTIFIER { result = val[0] }
270
+ | CLASS_IDENTIFIER { result = val[0] }
271
+ ;
272
+
273
+ Namespace:
274
+ NAMESPACE CONSTANT Expressions END { result = NamespaceNode.new(val[1], val[2]) }
275
+ | NAMESPACE CONSTANT Terminator Expressions END { result = NamespaceNode.new(val[1], val[3]) }
276
+ | NAMESPACE CONSTANT END { result = NamespaceNode.new(val[1], Nodes.new([])) }
277
+ ;
278
+
279
+ Class:
280
+ CLASS CONSTANT Expressions END { result = ClassNode.new(val[1], nil, val[2]) }
281
+ | CLASS CONSTANT Terminator Expressions END { result = ClassNode.new(val[1], nil, val[3]) }
282
+ | CLASS CONSTANT END { result = ClassNode.new(val[1], nil, Nodes.new([])) }
283
+ | CLASS CONSTANT Terminator END { result = ClassNode.new(val[1], nil, Nodes.new([])) }
284
+ | CLASS CONSTANT '<' CONSTANT Expressions END { result = ClassNode.new(val[1], val[3], val[4]) }
285
+ | CLASS CONSTANT '<' CONSTANT Terminator Expressions END { result = ClassNode.new(val[1], val[3], val[5]) }
286
+ | CLASS CONSTANT '<' CONSTANT END { result = ClassNode.new(val[1], val[3], Nodes.new([])) }
287
+ | CLASS CONSTANT '<' CONSTANT Terminator END { result = ClassNode.new(val[1], val[3], Nodes.new([])) }
288
+ ;
289
+
290
+ If:
291
+ IF Expression Terminator Expressions END { result = IfNode.new(val[1], val[3], nil) }
292
+ | IF Expression Terminator Expressions Else { result = IfNode.new(val[1], val[3], val[4]) }
293
+ ;
294
+
295
+ Else:
296
+ ELSE Terminator Expression Terminator END { result = ElseNode.new(val[2]) }
297
+ | ELSE Terminator Expressions END { result = ElseNode.new(val[2]) }
298
+ | ElseIf
299
+ ;
300
+
301
+ ElseIf:
302
+ ELSIF Expression Terminator Expressions END { result = ElseNode.new(IfNode.new(val[1], val[3], nil)) }
303
+ | ELSIF Expression Terminator Expressions Else { result = ElseNode.new(IfNode.new(val[1], val[3], val[4])) }
304
+ ;
305
+
306
+ While:
307
+ WHILE Expression Terminator Expressions END { result = WhileNode.new(val[1], val[3]) }
308
+ ;
309
+
310
+ Return:
311
+ RETURN Expression { result = ReturnNode.new(val[1]) }
312
+ | RETURN { result = ReturnNode.new(nil) }
313
+ ;
314
+
315
+ Property:
316
+ PROPERTY IDENTIFIER { result = PropertyNode.new([val[1]]) }
317
+ | PROPERTY PropertyList { result = PropertyNode.new(val[1]) }
318
+ ;
319
+
320
+ PropertyList:
321
+ IDENTIFIER IDENTIFIER { result = [val[0], val[1]] }
322
+ | PropertyList IDENTIFIER { result = val[0] << val[1] }
323
+ ;
324
+
325
+ end
326
+
327
+ ---- header
328
+ require "lang/lexer"
329
+ require "lang/nodes"
330
+
331
+ module EleetScript
332
+
333
+ ---- inner
334
+ def debug
335
+ @yydebug = true
336
+ end
337
+
338
+ def parse(code, show_tokens = false)
339
+ debug
340
+ @tokens = Lexer.new.tokenize(code)
341
+ p @tokens if show_tokens
342
+ do_parse
343
+ end
344
+
345
+ def next_token
346
+ @tokens.shift
347
+ end
348
+
349
+ ---- footer
350
+ end # module EleetScript