--- /dev/null
+# DOING
+
+# TODO
+
+* Fix type designation in symbol table
+* Add Import/Export statements
+* Add constant definitions
+* Add type definitions
+* Add/Sub for arrays
+* for/in statement for arrays
+* for/in statement for dictionaries
+
+* Implement sets
+* for/in statement for sets
+
+* Add unary operators for integers
+* Add type checking to operators on constants
+* Add optimization of constant operators
+* Add increment/decrement optimization
+* Implement tail call optimization?
+
+* add type checking for empty array literals
+
+
+# Compiler Stages
+
+* Parsing
+* Type validation, checking, inference
+* SSA-conversion
+* Reference counting or ownership checking
+* Optimization
+* code generation
\ No newline at end of file
#!/usr/bin/env ruby
# TODO:
-#
-# * Fix type designation in symbol table
-# * Add Import/Export statements
-# * Add constant definitions
-# * Add type definitions
-# * Add/Sub for arrays
-# * for/in statement for arrays
-# * for/in statement for dictionaries
-#
-# * Implement sets
-# * for/in statement for sets
-#
-# * Add unary operators for integers
-# * Add type checking to operators on constants
-# * Add optimization of constant operators
-# * Add increment/decrement optimization
-# * Implement tail call optimization?
-#
-# * add type checking for empty array literals
-
require 'stringio'
require 'strscan'
def initialize(parser)
@parser = parser
env = parser.syms
+
+ env.add_builtin(:int, :int, :int, nil)
+
parser.symbols.each do |sym, data|
- next if env[sym].kind == :type
- env[sym].type = infer(env, env[sym].value)
+ if env[sym].kind == :type
+ validate(env, env[sym].value)
+ elsif env[sym].type
+ check(env, env[sym].value, env[sym].type)
+ else
+ env[sym].type = infer(env, env[sym].value)
+ end
end
end
@parser.error(msg, loc)
end
+ def validate(env, type)
+ if type.is_a? IR::Var
+ if type.module.nil?
+ if env.global? type.name
+ type.module = @parser.module
+ elsif env.builtin? type.name
+ # leave it alone
+ else
+ error(type.loc, "unknown type '#{type.name}'")
+ end
+ else
+ if not env[type.module]
+ env.error(type.loc, "unknown module '#{type.module}'")
+ end
+ if not env[type.module].fields[type.name]
+ env.error(type.loc, "module '#{type.module}' has no exported symbol '#{type.name}'")
+ end
+ end
+ else
+ case type.form
+ when :alias
+ validate(env, type.base)
+ when :record
+ validate(env, type.base) if type.base
+ type.fields.each {|name,type| validate(env, type) }
+ else
+ raise "unimplemented"
+# pp type.form
+ end
+ end
+ end
+
def check(env, expr, type)
+# if type.is_a? IR::Var
+# type = typename(type)
+# end
if expr.is_a? IR::Const
check_const(env, expr, type)
elsif (expr.is_a? IR::Op)
# TYPE CHECKING
##
+ def types_equal(a,b)
+ a = typename(a) if a.is_a? IR::Var
+ b = typename(b) if b.is_a? IR::Var
+ a == b
+ end
+
+ def typename(var)
+ if var.is_a? Symbol
+ var
+ elsif var.module.nil?
+ var.name.to_sym
+ else
+ "#{var.module}_#{var.name}".to_sym
+ end
+ end
+
+
def check_func(env, expr, type)
raise "unimplemented"
error(expr.loc, "unimplemented")
end
def check_const(env, expr, type)
- if expr.type != type
+ if not types_equal(expr.type, type)
error(expr.loc, "expected #{type}, received #{expr.type}")
end
type
if (etype.class == String)
expr.type = type
env[expr.name].type = type
- elsif expr.type != type
+ elsif not types_equal(expr.type, type)
error(expr.loc, "expected #{type}, received #{etype}")
end
type
def check_op(env, expr, type)
expr.type = expr.type || infer(env, expr)
- if expr.type != type
+ if not types_equal(expr.type, type)
error(expr.loc, "expect #{type}, received #{expr.type}")
end
type
expr.type = optype[-1]
end
- def typename(var)
- if var.module.nil?
- var.name.to_sym
- else
- "#{var.module}_#{var.name}".to_sym
- end
- end
-
def check_binary(env, expr, vtype)
if expr.op == "["
left_type = infer(env, expr.left)