eleetscript 0.0.8a → 0.0.9a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/engine/eleet_to_ruby_wrapper.rb +9 -1
- data/lib/engine/engine.rb +111 -32
- data/lib/engine/ruby_to_eleet_wrapper.rb +9 -1
- data/lib/engine/values.rb +6 -2
- data/lib/lang/grammar.y +10 -4
- data/lib/lang/interpreter.rb +32 -14
- data/lib/lang/lexer.rb +9 -1
- data/lib/lang/nodes.rb +6 -0
- data/lib/lang/parser.output +10851 -10574
- data/lib/lang/parser.rb +1242 -1153
- data/lib/lang/runtime/base_classes.rb +43 -0
- data/lib/lang/runtime/eleetscript/object.es +4 -0
- data/lib/lang/runtime/eleetscript/regex.es +11 -0
- data/lib/lang/runtime/eleetscript/string.es +22 -0
- data/lib/lang/runtime/memory.rb +148 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80494963cad281aa36e4530787500857c16eec5f
|
4
|
+
data.tar.gz: 5249123133018b889fe3b94a39e5d43a22123dd3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca03d69c5ebd3650e643ffdb612d7b0456914af4559437fac911f236522ee52a5f2bef242c221be7fe5c6961aa662c7e31d343c169b8eb2ddb1e3eb7adf9ac7a
|
7
|
+
data.tar.gz: 2e9d01a9470ec764f56713ab7825650c498acaabcc28166d90d76adb606c717b8332b706266247344627847c323c3a22b4366d80f8d4177f40f3c0d40a97802b
|
@@ -23,8 +23,16 @@ module EleetScript
|
|
23
23
|
@eleet_obj
|
24
24
|
end
|
25
25
|
|
26
|
+
def class(orig = false)
|
27
|
+
if orig
|
28
|
+
super
|
29
|
+
else
|
30
|
+
call(:class)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
26
34
|
def to_s
|
27
|
-
|
35
|
+
call(:to_string)
|
28
36
|
end
|
29
37
|
end
|
30
38
|
end
|
data/lib/engine/engine.rb
CHANGED
@@ -3,67 +3,94 @@ require "lang/interpreter"
|
|
3
3
|
require "engine/values"
|
4
4
|
|
5
5
|
module EleetScript
|
6
|
+
class CannotInstantiateBaseEngine < Exception
|
7
|
+
def initialize
|
8
|
+
super("You cannot instantiate BaseEngine, use SharedEngine or StandaloneEngine")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
6
12
|
class CannotCallInstanceOrClassMethodsExcpetion < Exception
|
13
|
+
def initialize
|
14
|
+
super("You cannot call a class or instance method using EleetScript::Engine.call")
|
15
|
+
end
|
7
16
|
end
|
8
17
|
|
9
|
-
class
|
18
|
+
class BaseEngine
|
10
19
|
def initialize
|
11
|
-
|
12
|
-
@interpreter = Interpreter.new(@memory)
|
20
|
+
raise CannotInstantiateBaseEngine.new
|
13
21
|
end
|
14
22
|
|
15
|
-
def
|
23
|
+
def evaluate(code)
|
16
24
|
begin
|
17
|
-
to_ruby_value(
|
25
|
+
to_ruby_value(eval(code))
|
18
26
|
rescue Exception => e
|
19
27
|
false
|
20
28
|
end
|
21
29
|
end
|
22
30
|
|
31
|
+
def execute(code)
|
32
|
+
evaluate(code)
|
33
|
+
end
|
34
|
+
|
23
35
|
def call(method_name, *args)
|
24
36
|
method_name = method_name.to_s
|
25
37
|
if method_name =~ /\./
|
26
|
-
|
27
|
-
end
|
28
|
-
nesting = method_name.split("::")
|
29
|
-
ns = @memory.root_namespace
|
30
|
-
method_name = nesting.pop
|
31
|
-
nesting.each do |new_ns|
|
32
|
-
ns = ns.namespace(new_ns)
|
38
|
+
raise CannotCallInstanceOrClassMethodsException.new
|
33
39
|
end
|
40
|
+
method_name, ns = unnest(method_name)
|
34
41
|
eleet_args = args.map do |arg|
|
35
42
|
to_eleet_value(arg)
|
36
43
|
end
|
37
44
|
to_ruby_value(ns.current_self.call(method_name, eleet_args))
|
38
45
|
end
|
39
46
|
|
47
|
+
def [](name)
|
48
|
+
load
|
49
|
+
var, ns = unnest(name)
|
50
|
+
to_ruby_value(ns[name])
|
51
|
+
end
|
52
|
+
|
53
|
+
def []=(name, value)
|
54
|
+
load
|
55
|
+
var, ns = unnest(name)
|
56
|
+
if var[0] =~ /[A-Z]/ && ns.constants.has_key?(var)
|
57
|
+
memory.root_namespace["Errors"].call("<", [memory.root_namespace["String"].new_with_value("Cannot reassign constant via the Engine.")])
|
58
|
+
return false
|
59
|
+
else
|
60
|
+
ns[var] = to_eleet_value(value)
|
61
|
+
end
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
40
65
|
def get(var, raw = false)
|
41
|
-
|
66
|
+
val = self[var]
|
42
67
|
if raw
|
43
|
-
|
68
|
+
val.eleet_obj
|
44
69
|
else
|
45
|
-
|
70
|
+
val
|
46
71
|
end
|
47
72
|
end
|
48
73
|
|
49
74
|
def set(var, value)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
75
|
+
self[var] = value
|
76
|
+
end
|
77
|
+
|
78
|
+
def memory
|
79
|
+
@memory ||= Memory.new
|
80
|
+
end
|
81
|
+
|
82
|
+
protected
|
83
|
+
|
84
|
+
def load
|
85
|
+
interpreter unless @interpreter
|
86
|
+
end
|
87
|
+
|
88
|
+
def eval(code)
|
89
|
+
interpreter.eval(code)
|
90
|
+
end
|
91
|
+
|
92
|
+
def interpreter
|
93
|
+
@interpreter ||= Interpreter.new(memory)
|
67
94
|
end
|
68
95
|
|
69
96
|
def to_eleet_value(value)
|
@@ -73,5 +100,57 @@ module EleetScript
|
|
73
100
|
def to_ruby_value(value)
|
74
101
|
Values.to_ruby_value(value, self)
|
75
102
|
end
|
103
|
+
|
104
|
+
def engine_root_ns
|
105
|
+
memory.root_namespace
|
106
|
+
end
|
107
|
+
|
108
|
+
def unnest(name)
|
109
|
+
if name.start_with?("::")
|
110
|
+
name = name[2..-1]
|
111
|
+
ns = memory.root_namespace
|
112
|
+
else
|
113
|
+
ns = engine_root_ns
|
114
|
+
end
|
115
|
+
nesting = name.split("::")
|
116
|
+
var = nesting.pop
|
117
|
+
nesting.each do |new_ns|
|
118
|
+
ns = ns.namespace(new_ns)
|
119
|
+
end
|
120
|
+
[var, ns]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class SharedEngine < BaseEngine
|
125
|
+
def initialize; end
|
126
|
+
|
127
|
+
def memory
|
128
|
+
@@memory ||= Memory.new
|
129
|
+
end
|
130
|
+
|
131
|
+
protected
|
132
|
+
|
133
|
+
def eval(code)
|
134
|
+
interpreter.eval_with_context(code, context)
|
135
|
+
end
|
136
|
+
|
137
|
+
def context
|
138
|
+
@context ||= memory.root_namespace.new_namespace_context
|
139
|
+
end
|
140
|
+
|
141
|
+
def engine_root_ns
|
142
|
+
context
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class Engine < SharedEngine
|
147
|
+
def initialize
|
148
|
+
super
|
149
|
+
puts "WARNING: EleetScript::Engine has been deprecated, please use EleetScript::SharedEngine or EleetScript::StandaloneEngine."
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class StandaloneEngine < BaseEngine
|
154
|
+
def initialize; end
|
76
155
|
end
|
77
156
|
end
|
@@ -51,13 +51,21 @@ module EleetScript
|
|
51
51
|
!class?
|
52
52
|
end
|
53
53
|
|
54
|
+
def name
|
55
|
+
if @ruby_obj.class == Class
|
56
|
+
@ruby_obj.name
|
57
|
+
else
|
58
|
+
@ruby_obj.class.name
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
54
62
|
def runtime_class
|
55
63
|
cls = if @ruby_obj.class == Class
|
56
64
|
@ruby_obj
|
57
65
|
else
|
58
66
|
@ruby_obj.class
|
59
67
|
end
|
60
|
-
Values.to_eleet_value(cls
|
68
|
+
Values.to_eleet_value(cls)
|
61
69
|
end
|
62
70
|
end
|
63
71
|
end
|
data/lib/engine/values.rb
CHANGED
@@ -11,7 +11,7 @@ module EleetScript
|
|
11
11
|
memory = if engine.kind_of?(Memory)
|
12
12
|
engine
|
13
13
|
else
|
14
|
-
engine.
|
14
|
+
engine.memory
|
15
15
|
end
|
16
16
|
if ruby_obj.kind_of?(EleetToRubyWrapper)
|
17
17
|
ruby_obj.instance_variable_get("@eleet_obj")
|
@@ -27,6 +27,10 @@ module EleetScript
|
|
27
27
|
memory.root_namespace["Lambda"].new_with_value(ESProc.new(ruby_obj, engine))
|
28
28
|
elsif ruby_obj.kind_of?(RubyLambda)
|
29
29
|
ruby_obj.es_lambda
|
30
|
+
elsif ruby_obj.kind_of?(Regexp)
|
31
|
+
memory.root_namespace["Regex"].new_with_value(ESRegex.from_regex(ruby_obj))
|
32
|
+
elsif ruby_obj.kind_of?(ESRegex)
|
33
|
+
memory.root_namespace["Regex"].new_with_value(ruby_obj)
|
30
34
|
elsif ruby_obj.nil?
|
31
35
|
memory.root_namespace["nil"]
|
32
36
|
elsif ruby_obj == true
|
@@ -39,7 +43,7 @@ module EleetScript
|
|
39
43
|
end
|
40
44
|
|
41
45
|
def to_ruby_value(eleet_obj, engine)
|
42
|
-
ruby_values = ["TrueClass", "FalseClass", "NilClass", "String", "Integer", "Float"]
|
46
|
+
ruby_values = ["TrueClass", "FalseClass", "NilClass", "String", "Integer", "Float", "Regex"]
|
43
47
|
if eleet_obj.kind_of?(RubyToEleetWrapper)
|
44
48
|
eleet_obj.instance_variable_get("@ruby_obj")
|
45
49
|
elsif eleet_obj.class_name == "Lambda"
|
data/lib/lang/grammar.y
CHANGED
@@ -3,7 +3,7 @@ class Parser
|
|
3
3
|
token DO END CLASS LOAD IF WHILE NAMESPACE ELSE ELSIF RETURN BREAK NEXT TRUE
|
4
4
|
token YES ON FALSE NO OFF NIL SELF DEFINED PROPERTY RETURN
|
5
5
|
token CONSTANT GLOBAL CLASS_IDENTIFIER INSTANCE_IDENTIFIER IDENTIFIER
|
6
|
-
token FLOAT NUMBER STRING TERMINATOR EOF
|
6
|
+
token FLOAT NUMBER STRING TERMINATOR EOF REGEX REGEX_FLAGS
|
7
7
|
|
8
8
|
prechigh
|
9
9
|
left '.'
|
@@ -76,6 +76,12 @@ rule
|
|
76
76
|
| True { result = TrueNode.new }
|
77
77
|
| False { result = FalseNode.new }
|
78
78
|
| NIL { result = NilNode.new }
|
79
|
+
| Regex
|
80
|
+
;
|
81
|
+
|
82
|
+
Regex:
|
83
|
+
REGEX REGEX_FLAGS { result = RegexNode.new(val[0], val[1]) }
|
84
|
+
| REGEX { result = RegexNode.new(val[0], "") }
|
79
85
|
;
|
80
86
|
|
81
87
|
ListExpression:
|
@@ -171,6 +177,7 @@ rule
|
|
171
177
|
| Expression 'or' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
|
172
178
|
| Expression 'is' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
|
173
179
|
| Expression 'isnt' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
|
180
|
+
| Expression '=~' Expression { result = CallNode.new(val[0], val[1], [val[2]], nil) }
|
174
181
|
;
|
175
182
|
|
176
183
|
OperatorAssignment:
|
@@ -248,10 +255,9 @@ rule
|
|
248
255
|
| '>='
|
249
256
|
| '<='
|
250
257
|
| '<'
|
258
|
+
| '=~'
|
251
259
|
;
|
252
260
|
|
253
|
-
|
254
|
-
|
255
261
|
Parameters:
|
256
262
|
/* nothing */ { result = [] }
|
257
263
|
| Terminator { result = [] }
|
@@ -293,7 +299,7 @@ rule
|
|
293
299
|
;
|
294
300
|
|
295
301
|
Else:
|
296
|
-
ELSE Terminator
|
302
|
+
ELSE Terminator Expressions Terminator END { result = ElseNode.new(val[2]) }
|
297
303
|
| ELSE Terminator Expressions END { result = ElseNode.new(val[2]) }
|
298
304
|
| ElseIf
|
299
305
|
;
|
data/lib/lang/interpreter.rb
CHANGED
@@ -16,6 +16,11 @@ module EleetScript
|
|
16
16
|
nodes.eval(@memory.root_namespace)
|
17
17
|
end
|
18
18
|
|
19
|
+
def eval_with_context(code, context)
|
20
|
+
nodes = @parser.parse(code)
|
21
|
+
nodes.eval(context)
|
22
|
+
end
|
23
|
+
|
19
24
|
def load(file_name)
|
20
25
|
if File.exists?(file_name)
|
21
26
|
eval(File.read(file_name))
|
@@ -57,6 +62,24 @@ module EleetScript
|
|
57
62
|
end
|
58
63
|
end
|
59
64
|
|
65
|
+
module Interpolatable
|
66
|
+
INTERPOLATE_RX = /[\\]?%(?:@|@@|\$)?[\w]+?(?=\W|$)/
|
67
|
+
|
68
|
+
def interpolate(str, context)
|
69
|
+
new_val = str.dup
|
70
|
+
matches = str.scan(INTERPOLATE_RX)
|
71
|
+
matches.each do |match|
|
72
|
+
next if match.nil? || match == "%" || match == ""
|
73
|
+
if match.start_with?("\\")
|
74
|
+
next new_val.sub!(match, match[1..-1])
|
75
|
+
end
|
76
|
+
var = match[1..-1]
|
77
|
+
new_val.sub!(match, context[var].call(:to_string).ruby_value)
|
78
|
+
end
|
79
|
+
new_val
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
60
83
|
module NodeMethods
|
61
84
|
def returnable?
|
62
85
|
self.class.included_modules.include?(Returnable)
|
@@ -98,24 +121,19 @@ module EleetScript
|
|
98
121
|
end
|
99
122
|
|
100
123
|
class StringNode
|
101
|
-
|
124
|
+
include Interpolatable
|
102
125
|
|
103
126
|
def eval(context)
|
104
|
-
context["String"].new_with_value(interpolate(context))
|
127
|
+
context["String"].new_with_value(interpolate(value, context))
|
105
128
|
end
|
129
|
+
end
|
106
130
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
next new_val.sub!(match, match[1..-1])
|
114
|
-
end
|
115
|
-
var = match[1..-1]
|
116
|
-
new_val.sub!(match, context[var].call(:to_string).ruby_value)
|
117
|
-
end
|
118
|
-
new_val
|
131
|
+
class RegexNode
|
132
|
+
include Interpolatable
|
133
|
+
|
134
|
+
def eval(context)
|
135
|
+
f_arg = flags.length == 0 ? nil : flags
|
136
|
+
context["Regex"].new_with_value(ESRegex.new(interpolate(pattern, context), f_arg))
|
119
137
|
end
|
120
138
|
end
|
121
139
|
|
data/lib/lang/lexer.rb
CHANGED
@@ -19,12 +19,13 @@ module EleetScript
|
|
19
19
|
globals: /\A(\$[a-z][\w\d]*[?!]?)/i,
|
20
20
|
class_var: /\A(\@\@[a-z][\w\d]*[!?]?)/i,
|
21
21
|
instance_var: /\A(\@[a-z][\w\d]*[!?]?)/i,
|
22
|
-
operator: /\A(->|=>|[.+\-\*\/%<>=!]
|
22
|
+
operator: /\A(->|=>|[.+\-\*\/%<>=!]=|=~|\*\*=|\*\*|[+\-\*\/%=><]|or|and|not|isnt|is|\||\(|\)|\[|\]|\{|\}|::|[.,])/,
|
23
23
|
whitespace: /\A([ \t]+)/,
|
24
24
|
terminator: /\A([;\n])/,
|
25
25
|
integer: /\A([\d_]+)/,
|
26
26
|
float: /\A([\d_]*?\.[\d_]+)/,
|
27
27
|
string: /\A\"(.*?)(?<!\\)\"/m,
|
28
|
+
regex: /\Ar\"(.*?)(?<!\\)\"([gim]*)/,
|
28
29
|
comment: /\A#.*?(?=\n|$)/m
|
29
30
|
}
|
30
31
|
|
@@ -52,6 +53,13 @@ module EleetScript
|
|
52
53
|
elsif instance_var = chunk[TOKEN_RX[:instance_var]]
|
53
54
|
tokens << [:INSTANCE_IDENTIFIER, $1]
|
54
55
|
i += instance_var.length
|
56
|
+
elsif regex = chunk[TOKEN_RX[:regex]]
|
57
|
+
pattern, flags = $1, $2
|
58
|
+
tokens << [:REGEX, pattern.gsub('\"', '"')]
|
59
|
+
if flags && flags.length > 0
|
60
|
+
tokens << [:REGEX_FLAGS, flags]
|
61
|
+
end
|
62
|
+
i += regex.length
|
55
63
|
elsif identifier = chunk[TOKEN_RX[:identifiers]]
|
56
64
|
if KEYWORDS.include? identifier
|
57
65
|
tokens << [identifier.upcase.gsub(/\?\!/, "").to_sym, identifier]
|
data/lib/lang/nodes.rb
CHANGED
@@ -66,6 +66,12 @@ module EleetScript
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
class RegexNode < Node.new(:pattern, :flags)
|
70
|
+
def to_s(level = 0)
|
71
|
+
"#{spaces(level)}<RegexNode patter=#{pattern} flags=#{flags}>"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
69
75
|
class CallNode < Node.new(:receiver, :method_name, :arguments, :lambda)
|
70
76
|
def to_s(level = 0)
|
71
77
|
tabs = spaces(level)
|