citrus-compiler 0.8.0 → 0.8.1

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/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