From 28cb6b33bce59b8e304a12702e49755c4b986466 Mon Sep 17 00:00:00 2001 From: Mike Lowis Date: Wed, 6 Nov 2024 15:51:06 -0500 Subject: [PATCH] added typedef validation and checking --- TODO.md | 32 +++++++++++++++++++ cerise-c.rb | 20 ------------ lib/codegen.rb | 7 +++- lib/type_checker.rb | 78 +++++++++++++++++++++++++++++++++++++-------- 4 files changed, 103 insertions(+), 34 deletions(-) create mode 100644 TODO.md diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..19ca776 --- /dev/null +++ b/TODO.md @@ -0,0 +1,32 @@ +# 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 diff --git a/cerise-c.rb b/cerise-c.rb index 4bf7db7..c68d736 100755 --- a/cerise-c.rb +++ b/cerise-c.rb @@ -1,26 +1,6 @@ #!/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' diff --git a/lib/codegen.rb b/lib/codegen.rb index 45a4fab..aa259d0 100644 --- a/lib/codegen.rb +++ b/lib/codegen.rb @@ -15,12 +15,17 @@ class Codegen end def type_to_s(type) + # TODO: lookup fully qualified type here or make sure it's a var? + + if type == :string "_string" elsif type.is_a? Symbol type - elsif type.is_a? IR::Var + elsif type.is_a? IR::Var and type.module "#{type.module || @parser.module}_#{type.name}" + elsif type.is_a? IR::Var and not type.module + "#{type.name}" elsif type.form == :array "_array" elsif type.form == :hash diff --git a/lib/type_checker.rb b/lib/type_checker.rb index 439bf50..899be5d 100644 --- a/lib/type_checker.rb +++ b/lib/type_checker.rb @@ -93,9 +93,17 @@ class TypeChecker 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 @@ -103,7 +111,42 @@ class TypeChecker @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) @@ -297,6 +340,23 @@ class TypeChecker # 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") @@ -308,7 +368,7 @@ class TypeChecker 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 @@ -319,7 +379,7 @@ class TypeChecker 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 @@ -327,7 +387,7 @@ class TypeChecker 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 @@ -385,14 +445,6 @@ class TypeChecker 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) -- 2.52.0