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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c38fdc6bb79014d5728e6669aa12387778e621fc
4
- data.tar.gz: d27623562a61626be0b329b81859a889cb0023e9
3
+ metadata.gz: 80494963cad281aa36e4530787500857c16eec5f
4
+ data.tar.gz: 5249123133018b889fe3b94a39e5d43a22123dd3
5
5
  SHA512:
6
- metadata.gz: 4b9ddaa1b4cef7e92e97359907c8f932d0e1c7e2eb5c2440e826a7bd831a3ada3bddad7317c72e4740fdcaa191e210a64f8e2427c90e3b3fcf09cc98abcd145a
7
- data.tar.gz: 223caee593a8b8cc9a0003aca620026f132b0f1b9cb2974e2cb70cf45854691e87eaf776768f110f56dc2693e99ef0acc7901bd51904fbfe87b79cccee2bd476
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
- Values.to_ruby_value(@eleet_obj.call(:to_string), @engine)
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 Engine
18
+ class BaseEngine
10
19
  def initialize
11
- @memory = Memory.new
12
- @interpreter = Interpreter.new(@memory)
20
+ raise CannotInstantiateBaseEngine.new
13
21
  end
14
22
 
15
- def execute(code)
23
+ def evaluate(code)
16
24
  begin
17
- to_ruby_value(@interpreter.eval(code))
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
- throw CannotCallInstanceOrClassMethodsException.new("You cannot call a class or instance method using EleetScript::Engine.call")
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
- value = @memory.root_namespace[var]
66
+ val = self[var]
42
67
  if raw
43
- value
68
+ val.eleet_obj
44
69
  else
45
- to_ruby_value(value)
70
+ val
46
71
  end
47
72
  end
48
73
 
49
74
  def set(var, value)
50
- nesting = var.split("::")
51
- ns = @memory.root_namespace
52
- var = nesting.pop
53
- nesting.each do |new_ns|
54
- ns = ns.namespace(new_ns)
55
- end
56
- if var[0] =~ /[A-Z]/
57
- if ns.constants.has_key?(var)
58
- @memory.root_namespace["Errors"].call("<", [@memory.root_namespace["String"].new_with_value("Cannot reassign constant via the Engine.")])
59
- return false
60
- else
61
- ns[var] = to_eleet_value(value)
62
- end
63
- else
64
- ns[var] = to_eleet_value(value)
65
- end
66
- true
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.name)
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.instance_variable_get("@memory")
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 Expression Terminator END { result = ElseNode.new(val[2]) }
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
  ;
@@ -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
- INTERPOLATE_RX = /[\\]?%(?:@|@@|\$)?[\w]+?(?=\W|$)/
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
- def interpolate(context)
108
- new_val = value.dup
109
- matches = value.scan(INTERPOLATE_RX)
110
- matches.each do |match|
111
- next if match.nil? || match == "%" || match == ""
112
- if match.start_with?("\\")
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(->|=>|[.+\-\*\/%<>=!]=|\*\*=|\*\*|[+\-\*\/%=><]|or|and|not|isnt|is|\||\(|\)|\[|\]|\{|\}|::|[.,])/,
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)