citrus-compiler 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Author:: Mac Malone
4
4
  License:: See LICENSE
5
- Copyright:: Copyright (c) 2010 Mac Malone
5
+ Copyright:: Copyright (c) 2011 Mac Malone
6
6
 
7
7
  Citrus is a simple dynamically typed linear language written in Ruby, Treetop, and LLVM. It is meant to be an example of how to write a basic compiler.
8
8
 
@@ -10,7 +10,7 @@ Being linear, it could be called very c-like, but it has been written to have a
10
10
 
11
11
  * Dynamically typed
12
12
  * Extremely ruby-like syntax
13
- * Integer, Float, String, Boolean, and Array types
13
+ * Integer, Float, String, Boolean, Array, and Range types
14
14
  * Easy integration of C functions into the API
15
15
 
16
16
  It's prime examples are in the example directory, but here is an excerpt from factorial.ct:
@@ -37,9 +37,9 @@ Citrus requires the following libraries:
37
37
  * On Linux, there are usually pre-compiled packages
38
38
  * Ruby
39
39
  * Treetop
40
- * Ruby LLVM 2.9.1
40
+ * Ruby LLVM (currently building the source from Jeremy's next branch is required)
41
41
 
42
- Everything except LLVM is installed when running `gem install citrus`
42
+ Everything except LLVM is installed when running `gem install citrus-compiler`
43
43
 
44
44
  == Running
45
45
 
data/example/simple.ct CHANGED
@@ -39,6 +39,10 @@ def iterate
39
39
  printf("%s ", iteration)
40
40
  end
41
41
  puts("")
42
+ for iteration in 1..5
43
+ printf("%d ", iteration)
44
+ end
45
+ puts("")
42
46
  end
43
47
 
44
48
  def handle(err)
@@ -1,4 +1,5 @@
1
1
  require "citrus/compiler/generator"
2
+ require "citrus/compiler/array"
2
3
  require "citrus/compiler/block"
3
4
  require "citrus/compiler/function"
4
5
  require "citrus/compiler/variable"
@@ -0,0 +1,29 @@
1
+ module Citrus
2
+ class Array
3
+
4
+ attr_accessor :pointer
5
+
6
+ def self.create(values, builder)
7
+ ary = builder.alloca(LLVM::Array(LLVM::Type(values.first), values.size))
8
+ for index in 0...values.size
9
+ ptr = builder.gep(ary, [INT.from_i(0), INT.from_i(index)])
10
+ builder.store(values[index], ptr)
11
+ end
12
+ self.new(ary)
13
+ end
14
+
15
+ def initialize(pointer, props={})
16
+ @pointer = pointer
17
+ @length = props[:length]
18
+ end
19
+
20
+ def length
21
+ unless @length.nil?
22
+ return @length
23
+ else
24
+ return INT.from_i(LLVM::C.LLVMGetArrayLength(LLVM::Type(@pointer).element_type))
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -18,12 +18,26 @@ module Citrus
18
18
  end
19
19
 
20
20
  def array(values)
21
- ary = @builder.alloca(LLVM::Array(LLVM::Type(values.first), values.size))
22
- for index in 0...values.size
23
- ptr = @builder.gep(ary, [INT.from_i(0), INT.from_i(index)])
24
- @builder.store(values[index], ptr)
21
+ return Array.create(values, @builder)
22
+ end
23
+
24
+ def range(first, last, full)
25
+ ival = INT.from_i(-1)
26
+ ary = @builder.alloca(LLVM::Array(INT, 0))
27
+ iteration = builder.alloca(INT)
28
+ builder.store(first, iteration)
29
+ index = builder.alloca(INT)
30
+ builder.store(INT.from_i(0), index)
31
+ self.preploop(:while)
32
+ self.while(self.compare(full ? :<= : :<, @builder.load(iteration), last)) do |gw|
33
+ ival = gw.builder.load(index)
34
+ val = gw.builder.load(iteration)
35
+ ptr = gw.builder.gep(ary, [INT.from_i(0), ival])
36
+ gw.builder.store(val, ptr)
37
+ gw.builder.store(gw.equate(:+, val, gw.number(1)), iteration)
38
+ gw.builder.store(gw.equate(:+, ival, gw.number(1)), index)
25
39
  end
26
- return ary
40
+ return Array.new(ary, :length => self.equate(:+, ival, self.number(1)))
27
41
  end
28
42
 
29
43
  def string(value)
@@ -102,7 +116,7 @@ module Citrus
102
116
  end
103
117
 
104
118
  def assign_index(name, index, value)
105
- ary = @locals[name].value(@builder)
119
+ ary = self.load(name).pointer
106
120
  ptr = @builder.gep(ary, [INT.from_i(0), index])
107
121
  @builder.store(value, ptr)
108
122
  end
@@ -163,11 +177,11 @@ module Citrus
163
177
  end
164
178
 
165
179
  def load_index(ary, index)
166
- @builder.load(@builder.gep(ary, [INT.from_i(0), index]))
180
+ @builder.load(@builder.gep(ary.pointer, [INT.from_i(0), index]))
167
181
  end
168
182
 
169
183
  def function(name, args)
170
- GlobalFunctions.add(name, args) { |g| yield g }
184
+ return GlobalFunctions.add(name, args) { |g| yield g }
171
185
  end
172
186
 
173
187
  def declare(name, args, ret, varargs = false)
@@ -177,7 +191,7 @@ module Citrus
177
191
  end
178
192
 
179
193
  def block
180
- Block.new(@module, @function, self) { |g| yield g if block_given? }
194
+ return Block.new(@module, @function, self) { |g| yield g if block_given? }
181
195
  end
182
196
 
183
197
  def condition(cond, thenblock, elseblock, elsifs=[])
@@ -276,8 +290,7 @@ module Citrus
276
290
  @builder.position_at_end(@basic_block)
277
291
  self.resolve_conflict("for", generator, self)
278
292
  @basic_block = self.block.bb
279
- size = LLVM::C.LLVMGetArrayLength(LLVM::Type(indices).element_type)
280
- cond = self.compare(:<, self.load("for"), self.number(size))
293
+ cond = self.compare(:<, self.load("for"), indices.length)
281
294
  @builder.cond(cond, generator.basic_block, @basic_block)
282
295
  @builder.position_at_end(@basic_block)
283
296
  end
@@ -2,15 +2,48 @@ module Citrus
2
2
  class Variable
3
3
 
4
4
  attr_reader :type
5
- attr_reader :pointer
5
+ #attr_reader :pointer
6
6
 
7
7
  def initialize(value, builder)
8
- @type = LLVM::Type(value)
8
+ @value = nil
9
+ if value.is_a?(Citrus::Array)
10
+ @value = value
11
+ @type = LLVM::Type(value.pointer)
12
+ else
13
+ @type = LLVM::Type(value)
14
+ end
15
+ build_initialize(value, builder)
16
+ end
17
+
18
+ def assign(value, builder)
19
+ if value.is_a?(Citrus::Array)
20
+ @value = value
21
+ @type = LLVM::Type(value.pointer)
22
+ end
23
+ build_assign(value, builder)
24
+ end
25
+
26
+ def value(builder)
27
+ val = build_load(builder)
28
+ return @value.nil? ? val : @value
29
+ end
30
+
31
+ private
32
+
33
+ def build_initialize(value, builder)
34
+ if value.is_a?(Citrus::Array)
35
+ @pointer = value.pointer
36
+ return
37
+ end
9
38
  @pointer = builder.alloca(@type)
10
39
  builder.store(value, @pointer)
11
40
  end
12
41
 
13
- def assign(value, builder)
42
+ def build_assign(value, builder)
43
+ if value.is_a?(Citrus::Array)
44
+ @pointer = value.pointer
45
+ return
46
+ end
14
47
  type = LLVM::Type(value)
15
48
  unless type == @type
16
49
  @type = type
@@ -19,7 +52,7 @@ module Citrus
19
52
  builder.store(value, @pointer)
20
53
  end
21
54
 
22
- def value(builder)
55
+ def build_load(builder)
23
56
  builder.load(@pointer)
24
57
  end
25
58
 
@@ -30,17 +63,30 @@ module Citrus
30
63
  def initialize(name, value, mod, builder)
31
64
  @name = name
32
65
  @module = mod
33
- @type = LLVM::Type(value)
66
+ super(value, builder)
67
+ end
68
+
69
+ private
70
+
71
+ def build_initialize(value, builder)
34
72
  @pointer = @module.globals.add(@type, @name)
35
- @pointer.initializer = value
73
+ if value.is_a?(Citrus::Array)
74
+ @pointer.initializer = value.pointer
75
+ else
76
+ @pointer.initializer = value
77
+ end
36
78
  end
37
79
 
38
- def assign(value, builder)
39
- @type = LLVM::Type(value)
40
- builder.store(value, @pointer)
80
+ def build_assign(value, builder)
81
+ if value.is_a?(Citrus::Array)
82
+ builder.store(value.pointer, @pointer)
83
+ else
84
+ @type = LLVM::Type(value)
85
+ builder.store(value, @pointer)
86
+ end
41
87
  end
42
88
 
43
- def value(builder)
89
+ def build_load(builder)
44
90
  builder.load(@module.globals.named(@name))
45
91
  end
46
92
 
data/lib/citrus/core.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  require "rubygems"
2
2
 
3
- =begin # Custom LLVM Loading (for me only)
3
+ if File.directory?("#{File.dirname(__FILE__)}/../llvm-2.9") # Custom LLVM Loading (for me only)
4
4
  require "llvm/load"
5
5
  LLVM.load("#{File.dirname(__FILE__)}/../llvm-2.9")
6
- =end
6
+ end
7
7
 
8
8
  require 'llvm/core'
9
9
  require 'llvm/execution_engine'
data/lib/citrus/nodes.rb CHANGED
@@ -206,6 +206,12 @@ module Citrus
206
206
  end
207
207
  end
208
208
 
209
+ class RangeNode < Node
210
+ def codegen(g)
211
+ g.range(first.codegen(g), last.codegen(g).last, self.full?)
212
+ end
213
+ end
214
+
209
215
  class StringNode < Node
210
216
  def codegen(g)
211
217
  g.string(value)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: citrus-compiler
3
3
  version: !ruby/object:Gem::Version
4
- hash: 63
4
+ hash: 61
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 8
9
- - 0
10
- version: 0.8.0
9
+ - 1
10
+ version: 0.8.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Mac Malone
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-05-02 00:00:00 Z
18
+ date: 2011-05-03 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: treetop
@@ -33,22 +33,6 @@ dependencies:
33
33
  version: 1.4.9
34
34
  type: :runtime
35
35
  version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: ruby-llvm
38
- prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- hash: 41
45
- segments:
46
- - 2
47
- - 9
48
- - 1
49
- version: 2.9.1
50
- type: :runtime
51
- version_requirements: *id002
52
36
  description:
53
37
  email:
54
38
  executables: []
@@ -59,6 +43,7 @@ extra_rdoc_files:
59
43
  - README.rdoc
60
44
  - LICENSE
61
45
  files:
46
+ - lib/citrus/compiler/array.rb
62
47
  - lib/citrus/compiler/block.rb
63
48
  - lib/citrus/compiler/function.rb
64
49
  - lib/citrus/compiler/generator.rb