Commit c02c336a authored by Yorick Peterse's avatar Yorick Peterse

Port over more logic from TIR::Builder

parent d013874e
......@@ -38,7 +38,7 @@ end
parser.parse!(ARGV)
if ARGV.empty?
puts 'You must specify at least one source file to compile'
puts 'You must specify a source file to compile'
abort(parser.to_s)
end
......@@ -53,7 +53,7 @@ config.create_directories
state = Inkoc::State.new(config)
compiler = Inkoc::Compiler.new(state)
ARGV.each { |path| compiler.compile(path) }
compiler.compile_main(Pathname.new(ARGV[0]))
if state.diagnostics?
state.display_diagnostics
......
......@@ -3,7 +3,7 @@
require 'sxdg'
require 'ansi'
require 'set'
require 'fileutils'
require 'pathname'
require 'inkoc/inspect'
require 'inkoc/source_file'
......@@ -13,6 +13,7 @@ require 'inkoc/lexer'
require 'inkoc/parser'
require 'inkoc/module_paths_cache'
require 'inkoc/visitor_methods'
require 'inkoc/ast/predicates'
require 'inkoc/ast/body'
require 'inkoc/ast/send'
require 'inkoc/ast/constant'
......@@ -55,7 +56,7 @@ require 'inkoc/define_type_parameters'
require 'inkoc/pass/path_to_source'
require 'inkoc/pass/source_to_ast'
require 'inkoc/pass/insert_implicit_imports'
require 'inkoc/pass/ast_to_module'
require 'inkoc/pass/track_module'
require 'inkoc/pass/compile_imported_modules'
require 'inkoc/pass/define_types'
require 'inkoc/pass/module_body'
......@@ -65,6 +66,7 @@ require 'inkoc/tir/module_config'
require 'inkoc/tir/builder'
require 'inkoc/tir/code_object'
require 'inkoc/tir/basic_block'
require 'inkoc/tir/instruction/predicates'
require 'inkoc/tir/instruction/get_array_prototype'
require 'inkoc/tir/instruction/get_attribute'
require 'inkoc/tir/instruction/get_block_prototype'
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Attribute
include Predicates
include Inspect
attr_reader :name, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Block
include Predicates
include Inspect
attr_reader :arguments, :body, :throws, :returns, :location,
......
......@@ -3,9 +3,11 @@
module Inkoc
module AST
class Body
include Predicates
include Inspect
attr_reader :expressions, :location
attr_reader :location
attr_accessor :expressions
# expr - The expressions of this body.
# location - The SourceLocation of this node.
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class CompilerOption
include Predicates
include Inspect
attr_reader :key, :value, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Constant
include Predicates
include Inspect
attr_reader :name, :location, :receiver
......@@ -21,6 +22,10 @@ module Inkoc
@optional = false
end
def constant?
true
end
def optional?
@optional
end
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class DefineArgument
include Predicates
include Inspect
attr_reader :name, :type, :default, :rest, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class DefineTypeParameter
include Predicates
include Inspect
attr_reader :name, :required_traits, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class DefineVariable
include Predicates
include Inspect
attr_reader :variable, :value, :value_type, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Float
include Predicates
include Inspect
attr_reader :value, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class GlobImport
include Predicates
include Inspect
attr_reader :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Global
include Predicates
include Inspect
attr_reader :name, :location, :receiver
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Identifier
include Predicates
include Inspect
attr_reader :name, :location
......@@ -14,6 +15,10 @@ module Inkoc
@location = location
end
def identifier?
true
end
def visitor_method
:on_identifier
end
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Implement
include Predicates
include Inspect
attr_reader :name, :renames, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Import
include Predicates
include Inspect
attr_reader :steps, :symbols, :location
......@@ -22,7 +23,7 @@ module Inkoc
def qualified_name
steps = @steps.each_with_object([]) do |step, array|
array << step.name if step.is_a?(Identifier)
array << step.name if step.identifier?
end
TIR::QualifiedName.new(steps)
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class ImportSymbol
include Predicates
include Inspect
attr_reader :symbol_name, :alias_name, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Integer
include Predicates
include Inspect
attr_reader :value, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class KeywordArgument
include Predicates
include Inspect
attr_reader :name, :value, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Method
include Predicates
include Inspect
attr_reader :name, :arguments, :type_parameters, :returns, :throws,
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Object
include Predicates
include Inspect
attr_reader :name, :type_parameters, :trait_implementations, :body,
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Pair
include Predicates
include Inspect
attr_reader :key, :value, :location
......
# frozen_string_literal: true
module Inkoc
module AST
module Predicates
def identifier?
false
end
def constant?
false
end
end
end
end
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class ReassignVariable
include Predicates
include Inspect
attr_reader :variable, :value, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Return
include Predicates
include Inspect
attr_reader :value, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Self
include Predicates
include Inspect
attr_reader :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Send
include Predicates
include Inspect
attr_reader :name, :receiver, :arguments, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class String
include Predicates
include Inspect
attr_reader :value, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Throw
include Predicates
include Inspect
attr_reader :value, :location
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Trait
include Predicates
include Inspect
attr_reader :name, :type_parameters, :body, :location,
......
......@@ -3,6 +3,7 @@
module Inkoc
module AST
class Try
include Predicates
include Inspect
attr_reader :expression, :else_argument, :else_body, :location
......
......@@ -6,8 +6,8 @@ module Inkoc
BASE_PASSES = [
Pass::PathToSource,
Pass::SourceToAst,
Pass::AstToModule,
Pass::ConfigureModule,
Pass::TrackModule,
Pass::InsertImplicitImports,
Pass::CompileImportedModules,
Pass::DefineTypes,
......@@ -18,13 +18,22 @@ module Inkoc
@state = state
end
# path - The absolute file path of the module to compile, as a String.
def compile(path)
out = passes.reduce([path]) do |input, klass|
out = klass.new(@state).run(*input)
def compile_main(path)
name = TIR::QualifiedName.new(%w[main])
compile(name, path)
end
# name - The QualifiedName of the module.
# path - The absolute file path of the module to compile, as a Pathname.
def compile(name, path)
mod = module_for_name_and_path(name, path)
out = passes.reduce([]) do |input, klass|
out = klass.new(mod, @state).run(*input)
out ? out : break
end
mod
end
def passes
......@@ -42,5 +51,11 @@ module Inkoc
def passes_for_release_mode
BASE_PASSES
end
def module_for_name_and_path(name, path)
location = SourceLocation.first_line(SourceFile.new(path))
TIR::Module.new(name, location)
end
end
end
......@@ -28,7 +28,7 @@ module Inkoc
HASH_MAP_BUILTIN = '_HashMap'
# The name of the constant to use as the receiver for raw instructions.
RAW_INSTRUCTION_RECEIVER = '__INKOC'
RAW_INSTRUCTION_RECEIVER = '_INKOC'
NEW_MESSAGE = 'new'
DEFINE_REQUIRED_METHOD_MESSAGE = 'define_required_method'
......@@ -42,13 +42,14 @@ module Inkoc
attr_reader :source_directories, :mode, :target
def initialize
@source_directories = []
@source_directories = Set.new
@mode = :debug
@target = File.join(SXDG::XDG_CACHE_HOME, PROGRAM_NAME, BYTECODE_DIR)
@target = Pathname
.new(File.join(SXDG::XDG_CACHE_HOME, PROGRAM_NAME, BYTECODE_DIR))
end
def target=(path)
@target = File.expand_path(path)
@target = Pathname.new(path).expand_path
end
def release_mode?
......@@ -60,11 +61,13 @@ module Inkoc
end
def add_source_directories(directories)
@source_directories |= directories
directories.each do |dir|
@source_directories << Pathname.new(File.expand_path(dir))
end
end
def create_directories
FileUtils.mkdir_p(@target)
@target.mkpath
end
end
end
......@@ -2,10 +2,10 @@
module Inkoc
module DefineTypeParameters
def define_type_parameters(arguments, type, mod)
def define_type_parameters(arguments, type)
arguments.each do |arg_node|
required_traits = arg_node.required_traits.map do |node|
type_for_constant(node, [type, mod])
type_for_constant(node, [type, self.module])
end
arg = Type::TypeParameter.new(arg_node.name, required_traits)
......
# frozen_string_literal: true
module Inkoc
module InferType
def type_of_node(node, self_type, mod)
case node
when AST::Integer
typedb.integer_type
when AST::Float
typedb.float_type
when AST::String
typedb.string_type
when AST::Array
Type::Array.new(typedb.array_prototype)
when AST::HashMap
Type::HashMap.new(typedb.hash_map_prototype)
when AST::Attribute
self_type.lookup_attribute(node.name).type
when AST::Identifier
name = node.name
self_type.lookup_type(name)
.or_else { mod.lookup_type(name) }
.type
.return_type
when AST::Send
rec_node = node.receiver
rec_type =
if rec_node
type_of_node(rec_node, self_type, mod)
else
self_type
end
rec_type
.lookup_method(node.name)
.type
.return_type
when AST::Constant
type_for_constant(node, [self_type, mod])
else
Type::Dynamic.new
end
end
end
end
......@@ -34,7 +34,7 @@ module Inkoc
# consume a peeked value.
NULL_TOKEN = NullToken.new.freeze
def initialize(input, file_path = nil)
def initialize(input, file_path = Pathname.new('(eval)'))
@input = input.chars
@position = 0
@line = 1
......
......@@ -13,9 +13,9 @@ module Inkoc
end
@config.source_directories.each do |dir|
full_path = File.expand_path(File.join(dir, path))
full_path = dir.join(path).expand_path
return @cache[path] = full_path if File.file?(full_path)
return @cache[path] = full_path if full_path.file?
end
nil
......
......@@ -113,7 +113,7 @@ module Inkoc
]
).freeze
def initialize(input, file_path = nil)
def initialize(input, file_path = Pathname.new('(eval)'))
@lexer = Lexer.new(input, file_path)
end
......
# frozen_string_literal: true
module Inkoc
module Pass
class AstToModule
def initialize(state)
@state = state
end
def run(ast)
qname = qualified_name_for_path(ast.location.file.path)
mod = TIR::Module.new(qname, ast.location)
@state.store_module(mod)
[ast, mod]
end
def qualified_name_for_path(path)
TIR::QualifiedName.new([module_name_for_path(path)])
end
# Returns the module name for a file path.
#
# Example:
#
# module_name_for_path('hello/world.inko') # => "world"
def module_name_for_path(path)
file = path.split(File::SEPARATOR).last
file ? file.split('.').first : '<anonymous-module>'
end
end
end
end
......@@ -5,14 +5,15 @@ module Inkoc
class CompileImportedModules
include VisitorMethods
def initialize(state)
def initialize(mod, state)
@module = mod
@state = state
end
def run(ast, mod)
def run(ast)
process_node(ast)
[ast, mod]
[ast]
end
def on_body(node)
......@@ -30,7 +31,7 @@ module Inkoc
rel_path = qname.source_path_with_extension
if (full_path = @state.find_module_path(rel_path))
Compiler.new(@state).compile(full_path)
Compiler.new(@state).compile(qname, full_path)
else
@state.diagnostics.module_not_found_error(qname.to_s, location)
end
......
......@@ -5,25 +5,26 @@ module Inkoc
class ConfigureModule
include VisitorMethods
def initialize(state)
def initialize(mod, state)
@module = mod
@state = state
end
def run(ast, mod)
process_node(ast, mod)
def run(ast)
process_node(ast)
[ast, mod]
[ast]
end
def on_body(node, mod)
process_nodes(node.expressions, mod)
def on_body(node)
process_nodes(node.expressions)
end
def on_compiler_option(node, mod)
def on_compiler_option(node)
key = node.key
if mod.config.valid_key?(key)
mod.config[key] = node.value
if @module.config.valid_key?(key)
@module.config[key] = node.value
else
diagnostics.invalid_compiler_option(key, node.location)
end
......
......@@ -7,9 +7,12 @@ module Inkoc
include DefineTypeParameters
include VisitorMethods
def initialize(state)
attr_reader :module
def initialize(mod, state)
@module = mod
@state = state
@type_inference = TypeInference.new(state)
@type_inference = TypeInference.new(mod, state)
end
def diagnostics
......@@ -20,51 +23,51 @@ module Inkoc
@state.typedb
end
def run(ast, mod)
process_node(ast, mod.type, mod)
def run(ast)
process_node(ast, @module.type)
[ast, mod]
[ast]
end
def on_body(node, self_type, mod)
def on_body(node, self_type)
node.expressions.each do |expr|
process_node(expr, self_type, mod)
process_node(expr, self_type)
end
end
def on_object(node, self_type, mod)
proto = type_of_global(Config::OBJECT_BUILTIN, node.location, mod)
def on_object(node, self_type)
proto = type_of_global(Config::OBJECT_BUILTIN, node.location)
name = node.name
type = Type::Object.new(name, proto)
define_type_parameters(node.type_parameters, type, mod)
implement_traits(node.trait_implementations, type, self_type, mod)
define_type_parameters(node.type_parameters, type)
implement_traits(node.trait_implementations, type, self_type)
store_type(type, self_type, mod)
store_type(type, self_type)
process_node(node.body, type, mod)
process_node(node.body, type)
end
def on_trait(node, self_type, mod)
proto = type_of_global(Config::TRAIT_BUILTIN, node.location, mod)
def on_trait(node, self_type)
proto = type_of_global(Config::TRAIT_BUILTIN, node.location)
name = node.name
type = Type::Trait.new(name, proto)
define_type_parameters(node.type_parameters, type, mod)
implement_traits(node.trait_implementations, type, self_type, mod)
define_type_parameters(node.type_parameters, type)
implement_traits(node.trait_implementations, type, self_type)
store_type(type, self_type, mod)
store_type(type, self_type)
process_node(node.body, type, mod)