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.
- checksums.yaml +7 -0
- data/bin/eleet +89 -0
- data/lib/eleetscript.rb +18 -0
- data/lib/engine/eleet_engine.rb +58 -0
- data/lib/engine/eleet_to_ruby_wrapper.rb +25 -0
- data/lib/engine/ruby_to_eleet_wrapper.rb +22 -0
- data/lib/engine/values.rb +55 -0
- data/lib/lang/grammar.y +350 -0
- data/lib/lang/interpreter.rb +400 -0
- data/lib/lang/lexer.rb +92 -0
- data/lib/lang/nodes.rb +197 -0
- data/lib/lang/parser.output +11953 -0
- data/lib/lang/parser.rb +2300 -0
- data/lib/lang/runtime/array.rb +23 -0
- data/lib/lang/runtime/base_classes.rb +31 -0
- data/lib/lang/runtime/bootstrap.rb +3 -0
- data/lib/lang/runtime/class.rb +113 -0
- data/lib/lang/runtime/class_instance.rb +53 -0
- data/lib/lang/runtime/class_skeleton.rb +57 -0
- data/lib/lang/runtime/context.rb +263 -0
- data/lib/lang/runtime/eleetscript/enumerable.es +36 -0
- data/lib/lang/runtime/eleetscript/falseclass.es +25 -0
- data/lib/lang/runtime/eleetscript/integer.es +11 -0
- data/lib/lang/runtime/eleetscript/list.es +44 -0
- data/lib/lang/runtime/eleetscript/nilclass.es +5 -0
- data/lib/lang/runtime/eleetscript/number.es +13 -0
- data/lib/lang/runtime/eleetscript/object.es +49 -0
- data/lib/lang/runtime/eleetscript/pair.es +12 -0
- data/lib/lang/runtime/eleetscript/que.es +13 -0
- data/lib/lang/runtime/eleetscript/stack.es +14 -0
- data/lib/lang/runtime/eleetscript/string.es +34 -0
- data/lib/lang/runtime/eleetscript/trueclass.es +25 -0
- data/lib/lang/runtime/memory.rb +553 -0
- data/lib/lang/runtime/method.rb +32 -0
- data/lib/lang/runtime/method_hash.rb +40 -0
- data/lib/util/processed_key_hash.rb +34 -0
- 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
|
data/lib/eleetscript.rb
ADDED
@@ -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
|
data/lib/lang/grammar.y
ADDED
@@ -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
|