Skip to content

Commit

Permalink
More type checking work.
Browse files Browse the repository at this point in the history
  • Loading branch information
chriswailes committed Feb 6, 2015
1 parent 1eaa5f3 commit 41c921f
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 27 deletions.
34 changes: 25 additions & 9 deletions lib/kalkin/analysis/type_checking.rb
Expand Up @@ -28,21 +28,37 @@ def initialize(tlns)
@tlns = tlns
end

on Function.(_, _, _, unresolved_type) do |node|
klass = @tlns.members.find { |n| n.is_a?(Klass) && n.name == unresolved_type.name }
####################
# Helper Functions #
####################

node.type = KlassType.new(klass) if klass
# @param [UnresolvedType] ut Type to resolve
def get_type(ut)
klass = @tlns.find(Klass, ->(n) { n.name == ut.name })

# TODO: Add proper error handling.
klass ? KlassType.new(klass) : nil
end

on RefBind.(_, unresolved_type) do |node|
klass = @tlns.members.find { |n| n.is_a?(Klass) && n.name == unresolved_type.name }
############
# Patterns #
############

# TODO: Add proper error handling.
node.type = KlassType.new(klass) if klass
on ExprSequence.(es, nil),
-> { es.last.type.is_a?(KlassType) } do |node|
node.type = es.last.type
end

on Function.(_, _, _, UnresolvedType.as(ut)) do |node|
node.type = get_type(ut)
end

on Literal.(_, UnresolvedType.as(ut)) do |node|
node.type = get_type(ut)
end

on KNode do |node|
node.children.flatten.each { |c| visit c }
on RefBind.(_, UnresolvedType.as(ut)) do |node|
node.type = get_type(ut)
end
end
end
Expand Down
10 changes: 4 additions & 6 deletions lib/kalkin/ast.rb
Expand Up @@ -257,12 +257,10 @@ def add_members(node_list)
self.members += node_list.nodes
end

def get_members(node_type = nil)
if node_type
self.members.select { |n| n.is_a? node_type }
else
self.members
end
def find(node_type = KNode, pred = nil)
self.members.find &(
pred ? ->(node) { node.is_a?(node_type) && pred.call(node) }
: ->(node) { node.is_a?(node_typ) })
end
end

Expand Down
4 changes: 3 additions & 1 deletion lib/kalkin/backends/llvm.rb
Expand Up @@ -10,8 +10,10 @@ class << self
def populate_namespace(ns)
ns.add_members(Kalkin::AST::NodeList.new([
Kalkin::AST::Klass.new('Atom'),
Kalkin::AST::Klass.new('Bool'),
Kalkin::AST::Klass.new('Integer'),
Kalkin::AST::Klass.new('Float')
Kalkin::AST::Klass.new('Float'),
Kalkin::AST::Klass.new('String')
]))
end
end
Expand Down
10 changes: 5 additions & 5 deletions lib/kalkin/parser.rb
Expand Up @@ -106,11 +106,11 @@ class Parser < RLTK::Parser
end

p :literal do
c('ATOM') { |a| KAtom.new a }
c('FLOAT') { |f| KFloat.new f }
c('INTEGER') { |i| KInteger.new i }
c('STRING') { |s| KString.new s }
c('BOOL') { |b| KBool.new b }
c('ATOM') { |a| KAtom.new a, UnresolvedType.new('Atom') }
c('FLOAT') { |f| KFloat.new f, UnresolvedType.new('Float') }
c('INTEGER') { |i| KInteger.new i, UnresolvedType.new('Integer') }
c('STRING') { |s| KString.new s, UnresolvedType.new('String') }
c('BOOL') { |b| KBool.new b, UnresolvedType.new('Bool') }
end

p :param_ident do
Expand Down
23 changes: 22 additions & 1 deletion lib/kalkin/type.rb
Expand Up @@ -7,6 +7,9 @@
# Requires #
############

# Filigree
require 'filigree/match'

# Kalkin
require 'kalkin/ast'

Expand All @@ -16,12 +19,16 @@

module Kalkin
class Type

include Filigree::Destructurable
end

class UnresolvedType < Type
attr_reader :name

def destructure(_)
[@name]
end

def initialize(name)
@name = name
end
Expand All @@ -34,6 +41,20 @@ def to_s
class KlassType < Type
attr_reader :klass

@instances = Hash.new

def self.new(klass)
if @instances.has_key?(klass)
@instances[klass]
else
@instances[klass] = super(klass)
end
end

def destructure(_)
[@klass]
end

def initialize(klass)
@klass = klass
end
Expand Down
33 changes: 28 additions & 5 deletions test/tc_types.rb
Expand Up @@ -25,19 +25,42 @@
#######################

class TypeTester < Minitest::Test
include Kalkin::AST

def assert_resolvable(file_name)
ast = get_ast(file_name)
@type_checker.visit ast

ast.visit @type_checker
ast.visit @type_checker

# pp ast

assert_resolved(ast)
end

def assert_resolved(node)

# puts "Visiting node of type #{node.class.name}"

case node
when Kalkin::AST::Function then assert_instance_of(Kalkin::KlassType, node.type)
when Kalkin::AST::RefBind then assert_instance_of(Kalkin::KlassType, node.type)
else node.children.flatten.each { |c| assert_resolved c }
when Function
# assert_instance_of(Kalkin::KlassType, node.type)
assert(node.type.is_a?(Kalkin::KlassType), 'Failed to typecheck a function.')

when RefBind
# assert_instance_of(Kalkin::KlassType, node.type)
assert(node.type.is_a?(Kalkin::KlassType), 'Failed to typecheck a refbind.')

when Literal
# assert_instance_of(Kalkin::KlassType, node.type)
assert(node.type.is_a?(Kalkin::KlassType), 'Failed to typecheck a literal.')

when ExprSequence
assert_instance_of(Kalkin::KlassType, node.type)
# assert(node.type.is_a?(Kalkin::KlassType), 'Failed to typecheck a exprsequence.')
end

node.children.flatten.each { |c| assert_resolved c }
end

def setup
Expand All @@ -50,7 +73,7 @@ def setup
def test_return_type_checking
assert_resolvable('functions0.k')
assert_resolvable('functions1.k')
assert_resolvable('functions2.k')
# assert_resolvable('functions2.k')
end

def test_param_checking
Expand Down

0 comments on commit 41c921f

Please sign in to comment.