--- /dev/null
+#include <runtime.h>
+
+Value Foo_Bar();
+
+Value Foo_Bar() {
+ Value _t0 = MakeInt(42);
+ return _t0;
+}
+
--- /dev/null
+module Foo
+
+Bar() : int
+{
+ return 42
+}
\ No newline at end of file
#include <runtime.h>
+Value Foo_Bar();
+
Value Int_SumInts(Value a, Value b);
Value Int_SumInts(Value a, Value b) {
Value _t0 = OpAdd(a, b);
- return _t0;
+ Value _t1 = Foo_Bar();
+ Value _t2 = OpAdd(_t0, _t1);
+ return _t2;
}
module Int
+imports (
+ "Foo.m"
+)
+
+exports (SumInts)
+
SumInts(a : int, b : int) : int
{
- return a + b
+ return a + b + Foo.Bar()
}
require_relative 'lib/codegen'
require_relative 'lib/compiler'
-ARGV.each {|p| Compiler.compile(p) }
\ No newline at end of file
+ARGV.each {|p| Compiler.compile_and_link(p) }
\ No newline at end of file
@temp = 0
@indent = 1
@output = $stdout
-# @state = State.new(parser, 0, [], parser.syms, 0, 1)
end
def output(outpath)
@output = File.open(outpath, "wb")
puts "#include <runtime.h>\n\n"
+ (@parser.imported_modules || {}).values.each do |mod|
+ @syms[mod[:name]].type.exports.each do |name, val|
+ args = val.type[0..-2].map{|e| "Value" }.join(", ")
+ puts "Value #{symname(val)}(#{args});"
+ end
+ puts ""
+ end
+
@syms.each do |name, val|
args = val.value.args.map{|e| "Value #{e.name}" }.join(", ")
puts "Value #{symname(val)}(#{args});"
def lookup_func(func)
if func.is_a? IR::Var then
if func.module then
- mod = @syms[func.module]
- modsym = mod.type.exports[func.name]
- value = SymTable::Symbol.new(func.module, func.name, nil, modsym[:kind], modsym[:type], nil)
+ value = @syms[func.module].type.exports[func.name]
else
value = @syms[func.name]
end
]
def self.compile(path)
- out_path = path.sub(/\.[^.]+$/,'.c')
+ c_path = path.sub(/\.[^.]+$/,'.c')
+ o_path = path.sub(/\.[^.]+$/,'.o')
parser = Parser.new(path)
checker = TypeChecker.new(parser)
codegen = Codegen.new(parser)
- codegen.output(out_path)
- `gcc -c -I. -O1 -o cerise-c.o #{out_path}`
- Value::Module.new(parser.module, parser.symbols)
+ puts "Compiling #{path}"
+ codegen.output(c_path)
+ `gcc -c -I. -O1 -o #{o_path} #{c_path}`
+ Value::Module.new(parser.module, o_path, parser.imported_modules, parser.symbols)
end
def self.import(path)
PATH.each do |root|
p = "#{root}/#{path}"
- puts p
if File.exist?(p)
return Compiler.compile(p)
end
end
raise "could not find #{path} in search paths"
end
+
+ def self.dependency_list(imports)
+ imports.map {|k,v| dependency_list(v[:deps]) + [v[:out_path]] }
+ end
+
+ def self.compile_and_link(path)
+ mod = self.compile(path)
+ deps = dependency_list(mod.imports) + [mod.out_path]
+ deps = deps.flatten.map{|e| e.sub(/\.[^.]+$/, '.o') }
+ binname = File.basename(path).sub(/\.[^.]+$/, '')
+
+ if mod.exports[:Main]
+ # TODO: generate and compile a main here...
+ File.open("main.c", "wb") do |f|
+ f.puts '#include "runtime.h"'
+ f.puts "ENTRYPOINT(#{mod.name}_Main)"
+ end
+ `gcc -c -I. -O1 -o main.o main.c`
+ `gcc -I. -O1 -o #{binname} #{deps.join(" ")} main.o libruntime.a`
+ end
+ end
end
\ No newline at end of file
class Parser
attr_accessor :syms
attr_accessor :checker
+ attr_accessor :imported_modules
attr_reader :path
attr_reader :module
@path = path
@syms = SymTable.new
@checker = TypeChecker.new(self)
-
- syms.add_builtin(:bool, 0, :type, :bool)
-
-# syms.add_builtin(:void, 0, :type, :void)
-# syms.add_builtin(:int, 0, :type, :int)
-# syms.add_builtin(:string, 0, :type, :string)
-# syms.add_builtin(:float, 0, :type, :float)
-# syms.add_builtin(:Length, :func, nil, nil)
-# syms.add_builtin(:Error, :func, [:any, :void], nil)
-
parse_file(path)
end
def symbols()
- @syms.globals.map do |k,v|
- [k, {kind: v.kind, type: v.type}]
- end.to_h
+ syms = SymTable.new
+ syms.module_name = @module
+ @syms.globals.each do |k,v|
+ syms.add_sym(k, v.loc, v.kind, v.type, nil)
+ end
+ syms
end
def linenum(pos)
def toplevel
expect :module
@module = expect(:ident).text.to_sym
+ syms.module_name = @module
imports
exports
while !matches(:eof)
def imports
if accept(:imports)
- @imports = []
+ @imported_modules = {}
expect("(")
while !matches(")")
modpath = module_path()
mod,
nil
)
- @imports << modpath
+ @imported_modules[modpath] = {
+ name: mod.name,
+ out_path: mod.out_path,
+ deps: (mod.imports || {})
+ }
expect(",") if not matches(")")
end
expect(")")
expect(",") if not matches(")")
end
expect(")")
- pp @exports
end
end
elsif tok.type == :void
IR::Const.new(tok.pos, :void, :void)
elsif tok.type == :ident
- varname = IR::Var.new(tok.pos, nil, tok.text.to_sym)
+ varname = IR::Var.new(tok.pos, nil, tok.text.to_sym, nil)
if accept(".")
mod = syms[varname.name]
- pp mod
if mod.kind != :module
error("accessing field in object that is neither a record nor a module")
end
class SymTable
Symbol = Struct.new(:module, :name, :loc, :kind, :type, :value)
+ attr_accessor :module_name
+
def initialize()
@scopes = [{}, {}]
end
def add_builtin(name, kind, type, value)
@scopes[0][name] =
- Symbol.new(nil, name, 0, kind, type, value)
+ Symbol.new(@module_name, name, 0, kind, type, value)
end
def add_sym(name, loc, kind, type, value)
@scopes.last[name] =
- Symbol.new(nil, name, loc, kind, type, value)
+ Symbol.new(@module_name, name, loc, kind, type, value)
end
def each(&block)
Type = Struct.new(:form, :fields, :base, :size)
Field = Struct.new(:type, :offset)
- Module = Struct.new(:name, :exports)
+ Module = Struct.new(:name, :out_path, :imports, :exports)
# Base type definitions
Void = Type.new(:void, nil, nil, 0)