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
|