nudge 0.1.3 → 0.2.0
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.
- data/VERSION +1 -1
- data/lib/instructions/infrastructure.rb +8 -1
- data/lib/interpreter/interpreter.rb +9 -1
- data/lib/interpreter/nudge_program.rb +2 -10
- data/lib/nudge.rb +0 -12
- data/readme.md +5 -3
- data/spec/instructions/instruction_class_spec.rb +13 -1
- data/spec/instructions/int/int_power_spec.rb +1 -0
- data/spec/interpreter/interpreter_spec.rb +26 -1
- data/spec/interpreter/nudge_program_spec.rb +0 -1
- data/spec/spec_helper.rb +1 -1
- metadata +4 -13
- data/lib/interpreter/grammars/nudge_codeblock.treetop +0 -17
- data/lib/interpreter/grammars/nudge_codeblock_helpers.rb +0 -19
- data/lib/interpreter/grammars/nudge_common.treetop +0 -15
- data/lib/interpreter/grammars/nudge_instruction.treetop +0 -14
- data/lib/interpreter/grammars/nudge_instruction_helpers.rb +0 -14
- data/lib/interpreter/grammars/nudge_reference.treetop +0 -9
- data/lib/interpreter/grammars/nudge_reference_helpers.rb +0 -14
- data/lib/interpreter/grammars/nudge_value.treetop +0 -14
- data/lib/interpreter/grammars/nudge_value_helpers.rb +0 -19
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -28,6 +28,10 @@ class Instruction
|
|
28
28
|
class MissingInstructionError < RuntimeError
|
29
29
|
end
|
30
30
|
|
31
|
+
class CodeOversizeError < ArgumentError
|
32
|
+
end
|
33
|
+
|
34
|
+
|
31
35
|
def initialize(context)
|
32
36
|
@context = context
|
33
37
|
end
|
@@ -51,6 +55,9 @@ class Instruction
|
|
51
55
|
|
52
56
|
|
53
57
|
def pushes(stackName, literal)
|
58
|
+
if (stackName.to_s == "code") && (literal.value.length > self.context.code_char_limit)
|
59
|
+
raise(CodeOversizeError, ":code cannot have more than #{self.context.code_char_limit} chars")
|
60
|
+
end
|
54
61
|
@context.stacks[stackName].push literal
|
55
62
|
end
|
56
63
|
|
@@ -62,7 +69,7 @@ class Instruction
|
|
62
69
|
self.cleanup
|
63
70
|
end
|
64
71
|
rescue NotEnoughStackItems, MissingInstructionError,
|
65
|
-
InstructionMethodError, NaNResultError, FloatDomainError => exc
|
72
|
+
InstructionMethodError, NaNResultError, FloatDomainError, CodeOversizeError => exc
|
66
73
|
msg = ValuePoint.new("error", exc.message)
|
67
74
|
pushes :error, msg
|
68
75
|
end
|
@@ -17,6 +17,8 @@ module Nudge
|
|
17
17
|
attr_accessor :stacks, :instructions_library, :variables, :names, :types
|
18
18
|
attr_accessor :last_name, :evaluate_references
|
19
19
|
attr_accessor :sensors
|
20
|
+
attr_accessor :code_char_limit
|
21
|
+
attr_accessor :start_time, :time_limit
|
20
22
|
|
21
23
|
|
22
24
|
# A program to be interpreted can be passed in as an optional parameter
|
@@ -25,6 +27,8 @@ module Nudge
|
|
25
27
|
@program = initialProgram
|
26
28
|
@types = params[:types] || NudgeType.all_types
|
27
29
|
@step_limit = params[:step_limit] || 3000
|
30
|
+
@time_limit = params[:time_limit] || 60.0 # seconds
|
31
|
+
@code_char_limit = params[:code_char_limit] || 2000
|
28
32
|
@sensors = Hash.new
|
29
33
|
|
30
34
|
instructions = params[:instructions] || Instruction.all_instructions
|
@@ -61,6 +65,7 @@ module Nudge
|
|
61
65
|
@stacks[:exec].push(NudgeProgram.new(program).linked_code)
|
62
66
|
end
|
63
67
|
@steps = 0
|
68
|
+
@start_time = Time.now
|
64
69
|
@evaluate_references = true
|
65
70
|
end
|
66
71
|
|
@@ -107,7 +112,9 @@ module Nudge
|
|
107
112
|
# 1. Is the <b>:exec</b> stack empty?
|
108
113
|
# 2. Are the number of steps greater than self.step_limit?
|
109
114
|
def notDone?
|
110
|
-
@stacks[:exec].depth > 0 &&
|
115
|
+
@stacks[:exec].depth > 0 &&
|
116
|
+
@steps < @step_limit &&
|
117
|
+
(Time.now-@start_time)<@time_limit
|
111
118
|
end
|
112
119
|
|
113
120
|
|
@@ -132,6 +139,7 @@ module Nudge
|
|
132
139
|
|
133
140
|
# invoke self.step() until a termination condition is true
|
134
141
|
def run
|
142
|
+
@start_time = Time.now
|
135
143
|
while notDone?
|
136
144
|
self.step
|
137
145
|
end
|
@@ -1,7 +1,4 @@
|
|
1
1
|
#encoding: utf-8
|
2
|
-
require 'treetop'
|
3
|
-
Treetop.load(File.join(File.dirname(__FILE__),'grammars', "nudge_codeblock.treetop"))
|
4
|
-
|
5
2
|
|
6
3
|
module Nudge
|
7
4
|
class NudgeProgram
|
@@ -22,14 +19,10 @@ module Nudge
|
|
22
19
|
raise(ArgumentError, "NudgeProgram.new should be passed a string") unless sourcecode.kind_of?(String)
|
23
20
|
@raw_code = sourcecode
|
24
21
|
|
25
|
-
# snipped out:
|
26
|
-
# program_split!
|
27
22
|
split_at_first_guillemet=@raw_code.partition( /^(?=«)/ )
|
28
23
|
@code_section = split_at_first_guillemet[0].strip
|
29
24
|
@footnote_section = split_at_first_guillemet[2].strip
|
30
25
|
|
31
|
-
#snipped out:
|
32
|
-
#relink_code!
|
33
26
|
parsed_code = NudgeTree.from(@raw_code)
|
34
27
|
@linked_code = parsed_code[:tree]
|
35
28
|
@footnotes = parsed_code[:unused]
|
@@ -152,14 +145,13 @@ module Nudge
|
|
152
145
|
|
153
146
|
|
154
147
|
def parses?(program_blueprint = @code_section)
|
155
|
-
|
148
|
+
!NudgeTree.from(program_blueprint)[:tree].kind_of?(NilPoint)
|
156
149
|
end
|
157
150
|
|
158
151
|
|
159
152
|
|
160
153
|
def tidy
|
161
|
-
|
162
|
-
framework ? framework.tidy : ""
|
154
|
+
NudgeTree.from(@raw_code)[:tree].tidy
|
163
155
|
end
|
164
156
|
|
165
157
|
|
data/lib/nudge.rb
CHANGED
@@ -1,22 +1,10 @@
|
|
1
1
|
$: << File.join(File.dirname(__FILE__), "/../lib")
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
|
-
require 'treetop'
|
5
4
|
require 'active_support'
|
6
5
|
|
7
6
|
require 'interpreter/parse.tab'
|
8
7
|
|
9
|
-
require 'interpreter/grammars/nudge_common'
|
10
|
-
|
11
|
-
require 'interpreter/grammars/nudge_value_helpers'
|
12
|
-
require 'interpreter/grammars/nudge_reference_helpers'
|
13
|
-
require 'interpreter/grammars/nudge_instruction_helpers'
|
14
|
-
require 'interpreter/grammars/nudge_codeblock_helpers'
|
15
|
-
require 'interpreter/grammars/nudge_reference'
|
16
|
-
require 'interpreter/grammars/nudge_instruction'
|
17
|
-
require 'interpreter/grammars/nudge_value'
|
18
|
-
require 'interpreter/grammars/nudge_codeblock'
|
19
|
-
|
20
8
|
require 'interpreter/nudge_program'
|
21
9
|
|
22
10
|
require 'cli/runner'
|
data/readme.md
CHANGED
@@ -58,7 +58,9 @@ The interpreter code relies heavily on functional programming features of Ruby 1
|
|
58
58
|
|
59
59
|
The following gems need to be present to run the code:
|
60
60
|
|
61
|
-
* [
|
62
|
-
|
61
|
+
* [activesupport](http://as.rubyonrails.org/) (`gem install activesupport`)
|
62
|
+
|
63
|
+
To use the fancypants command line generators we're building, you'll need thor:
|
64
|
+
* [thor](http://github.com/wycats/thor/) (`gem install thor`)
|
63
65
|
|
64
|
-
and you will want [rspec](http://rspec.info/) to be able to run the specs and confirm the codebase works on your system
|
66
|
+
and you will definitely want [rspec](http://rspec.info/) to be able to run the specs and confirm the codebase works on your system: `gem install rspec`.
|
@@ -15,6 +15,7 @@ describe "Instruction has a master list" do
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
|
18
19
|
describe "capturing errors" do
|
19
20
|
describe "NotEnoughStackItems" do
|
20
21
|
describe "#preconditions?" do
|
@@ -36,5 +37,16 @@ describe "capturing errors" do
|
|
36
37
|
context.stacks[:error].peek.blueprint.should include "needs IntAddInstruction"
|
37
38
|
end
|
38
39
|
end
|
39
|
-
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
describe ":code stack has a special rule" do
|
44
|
+
it "should be impossible to use #pushes to push a :code item that is too large for the context" do
|
45
|
+
small_box = Interpreter.new("block {}", code_char_limit:20)
|
46
|
+
small_code = ValuePoint.new("code","block { do a }")
|
47
|
+
long_code = ValuePoint.new("code","block { do a do b do c do d do e do f do g }")
|
48
|
+
throwaway = IntAddInstruction.new(small_box)
|
49
|
+
lambda{throwaway.pushes(:code, long_code)}.should raise_error(Instruction::CodeOversizeError)
|
50
|
+
lambda{throwaway.pushes(:code, small_code)}.should_not raise_error(Instruction::CodeOversizeError)
|
51
|
+
end
|
40
52
|
end
|
@@ -45,12 +45,30 @@ describe "initialization" do
|
|
45
45
|
@ii.steps.should == 0
|
46
46
|
end
|
47
47
|
|
48
|
+
it "#reset should reset the start_time counter to 0" do
|
49
|
+
@ii.start_time = 999999999999
|
50
|
+
@ii.reset
|
51
|
+
@ii.start_time.should be_a_kind_of(Time)
|
52
|
+
end
|
53
|
+
|
48
54
|
it "#reset should reset the #sensors Hash" do
|
49
55
|
@ii.register_sensor("z") {1201}
|
50
56
|
@ii.reset
|
51
57
|
@ii.sensors["z"].should == nil
|
52
58
|
end
|
53
59
|
|
60
|
+
it "should have a code_char_limit" do
|
61
|
+
lambda{@ii.code_char_limit}.should_not raise_error
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should have a default code_char_limit of 2000 characters" do
|
65
|
+
@ii.code_char_limit.should == 2000
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should be possible to set code_char_limit with an option" do
|
69
|
+
Interpreter.new("block {}",code_char_limit:171).code_char_limit.should == 171
|
70
|
+
end
|
71
|
+
|
54
72
|
|
55
73
|
it "should load a complex CodeBlock as a single item on the exec stack" do
|
56
74
|
myCode = "block {\ndo foo\n do bar\n block {\ndo baz}}"
|
@@ -421,6 +439,13 @@ describe "stepping" do
|
|
421
439
|
@ii.steps.should == 20
|
422
440
|
end
|
423
441
|
|
442
|
+
it "should step only until its time_limit is reached or exceeded" do
|
443
|
+
@ii.reset("block {}")
|
444
|
+
@ii.start_time = (Time.now - 10000)
|
445
|
+
@ii.run
|
446
|
+
@ii.steps.should == 1
|
447
|
+
end
|
448
|
+
|
424
449
|
end
|
425
450
|
|
426
451
|
describe "running" do
|
@@ -489,7 +514,7 @@ describe "resetting" do
|
|
489
514
|
end
|
490
515
|
|
491
516
|
it "should not affect variable bindings" do
|
492
|
-
ii = Interpreter.new
|
517
|
+
ii = Interpreter.new("block {}")
|
493
518
|
ii.bind_variable("a", ValuePoint.new("int",3))
|
494
519
|
ii.variables.keys.should == ["a"]
|
495
520
|
ii.reset
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Bill Tozier
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-04-
|
19
|
+
date: 2010-04-08 00:00:00 -04:00
|
20
20
|
default_executable: nudge
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -216,15 +216,6 @@ files:
|
|
216
216
|
- lib/instructions/name/name_unbind.rb
|
217
217
|
- lib/instructions/name/name_yank.rb
|
218
218
|
- lib/instructions/name/name_yankdup.rb
|
219
|
-
- lib/interpreter/grammars/nudge_codeblock.treetop
|
220
|
-
- lib/interpreter/grammars/nudge_codeblock_helpers.rb
|
221
|
-
- lib/interpreter/grammars/nudge_common.treetop
|
222
|
-
- lib/interpreter/grammars/nudge_instruction.treetop
|
223
|
-
- lib/interpreter/grammars/nudge_instruction_helpers.rb
|
224
|
-
- lib/interpreter/grammars/nudge_reference.treetop
|
225
|
-
- lib/interpreter/grammars/nudge_reference_helpers.rb
|
226
|
-
- lib/interpreter/grammars/nudge_value.treetop
|
227
|
-
- lib/interpreter/grammars/nudge_value_helpers.rb
|
228
219
|
- lib/interpreter/interpreter.rb
|
229
220
|
- lib/interpreter/nudge_program.rb
|
230
221
|
- lib/interpreter/parse.tab.rb
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'nudge'
|
2
|
-
|
3
|
-
|
4
|
-
grammar NudgeCodeblock
|
5
|
-
include NudgeCommon
|
6
|
-
include NudgeReference
|
7
|
-
include NudgeInstruction
|
8
|
-
include NudgeValue
|
9
|
-
|
10
|
-
rule codesection
|
11
|
-
value / instruction / reference / (block_statement <CodeblockParseNode>)
|
12
|
-
end
|
13
|
-
|
14
|
-
rule block_statement
|
15
|
-
'block' spcs? '{' spcs? block_contents:(codesection spcs?)* '}'
|
16
|
-
end
|
17
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
module CodeblockParseNode
|
3
|
-
def contents
|
4
|
-
block_contents.elements.collect {|e| e.elements[0]}
|
5
|
-
end
|
6
|
-
|
7
|
-
def tidy(level=1)
|
8
|
-
tt = "block {"
|
9
|
-
indent = level*2
|
10
|
-
contents.each {|item| tt += ("\n" + (" "*indent) + item.tidy(level+1))}
|
11
|
-
tt += "}"
|
12
|
-
return tt
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_point
|
16
|
-
c = CodeblockPoint.new(contents.collect {|e| e.to_point})
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
class InstructionParseNode < Treetop::Runtime::SyntaxNode
|
3
|
-
def instruction_name
|
4
|
-
opcode.text_value
|
5
|
-
end
|
6
|
-
|
7
|
-
def tidy(level=1)
|
8
|
-
"do #{instruction_name}"
|
9
|
-
end
|
10
|
-
|
11
|
-
def to_point
|
12
|
-
InstructionPoint.new(instruction_name)
|
13
|
-
end
|
14
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
class ValueParseNode < Treetop::Runtime::SyntaxNode
|
3
|
-
def type=(new_type)
|
4
|
-
@type = new_type
|
5
|
-
end
|
6
|
-
|
7
|
-
def type
|
8
|
-
@type ||= footnote_type.text_value
|
9
|
-
end
|
10
|
-
|
11
|
-
def tidy(level=1)
|
12
|
-
"value «#{type}»"
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_point
|
16
|
-
return ValuePoint.new(type)
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|