-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathRakefile
103 lines (91 loc) · 3.27 KB
/
Rakefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
$:.unshift File.dirname(__FILE__) + '/lib'
require 'ometa'
module Bootstrap
class BootstrapError < StandardError
end
BOOTSTRAP_GRAMMARS = %w[
null_opt.ometa
andor_opt.ometa
ometa_opt.ometa
bsruby_parser.ometa
bsruby_translator.ometa
ometa_parser.ometa
ometa_translator.ometa
]
module_function
class V0 < Object
end
def single root=V0, quiet=false
puts "bootstrapping ometa using #{root.inspect}" unless quiet
all = ''
BOOTSTRAP_GRAMMARS.each do |filename|
puts " - #{filename}" unless quiet
grammar = File.read(File.dirname(__FILE__) + '/ometa/' + filename)
ast = root.const_get('OMetaParser').matchAllwith(grammar, 'grammar')
ast = root.const_get('OMetaOptimizer').matchwith(ast, 'optimizeGrammar')
str = root.const_get('RubyOMetaTranslator').matchwith(ast, 'trans')
# this hack remains at the moment...
str.gsub! /initialize/, 'initialize_hook'
# test its evaluable
obj = eval(str)
# that gives us its name
name = obj.instance_variable_get :@name
all << "#{name} = " << str << "\n\n"
end
all
end
# we could also check for AST equivalence, but for now source equivalence will do.
# note that we create the bootstrapped objects within the Bootstrap module, not as
# anonymous objects as they refer to each other by name. anonymous module didn't
# seem to work, but maybe i was doing something wrong...
def bootstrap
v1 = single
eval "module V1; #{v1}; end"
v2 = single V1
eval "module V2; #{v2}; end"
v3 = single V2
eval "module V3; #{v3}; end"
raise BootstrapError, 'second and third builds not equivalent' unless v2 == v3
v3
end
end
desc 'rebuild bootstrap.rb from the core ometa grammar files'
task :bootstrap do
# this is kind of like make bootstrap in gcc. the idea is to go through
# the whole "compilation" of ometa -> rb 3 times, and ensure that the
# 2nd and 3rd produce the same results. then we replace with our new
# bootstrap code.
begin
str = Bootstrap.bootstrap
rescue Bootstrap::BootstrapError
puts "unable to bootstrap - #{$!}"
exit 1
end
puts 'bootstrap successful!'
open File.dirname(__FILE__) + '/lib/ometa/bootstrap.rb', 'w' do |f|
f.puts <<-end
#
# this file was automatically generated by `rake bootstrap' at #{Time.now}.
# do not modify
#
end
f.puts str
end
end
desc 'Simple benchmark'
task :bench do
# all we do is run the complete bootstrap 3 times.
# this currently takes about 44-48 seconds currently on my laptop (~1.4Ghz single core).
# they're pretty simple grammars, so ideally this'd take more like a few seconds...
# ok after using _x* variant functions which use blocks instead of procs, and removing
# some other unnecessary procs, we get this down to 30 s. this also has the nice side
# effect of reducing the size of bootstrap.rb from 13kb down to 10kb.
# can get it down to 28 with a bit more of that. will now try inlining _or() alternations
# to avoid the only remaining need for procs. if that doesn't have an appreciable impact,
# (eg > 5s), i'll revert it and focus on runtime.rb, which is probably where the slowness
# is - implementation of streams, memoization, the _apply function etc.
# just tested it on ruby1.9, and the speed was the same.
t = Time.now
3.times { Bootstrap.single Bootstrap::V0, true }
puts "3 bootstraps took #{Time.now - t} seconds"
end