From 303875d65da3ce88e296ed6293fd40e8819b4950 Mon Sep 17 00:00:00 2001 From: Mike Lowis Date: Mon, 21 Oct 2024 16:29:20 -0400 Subject: [PATCH] change where module resolution happens. Now it is happening in the parser and is a bit simpler. Code generation still needs to handle outputiing the correct symbol names --- lib/ir.rb | 2 +- lib/parser.rb | 12 ++++++++++-- lib/type_checker.rb | 26 +++++++++++--------------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/lib/ir.rb b/lib/ir.rb index 23b5044..e8cb676 100644 --- a/lib/ir.rb +++ b/lib/ir.rb @@ -6,7 +6,7 @@ module IR Return = Struct.new(:loc, :type, :value) Assert = Struct.new(:loc, :type, :value) Const = Struct.new(:loc, :type, :value) - Var = Struct.new(:loc, :type, :name) + Var = Struct.new(:loc, :type, :name, :module) Def = Struct.new(:loc, :type, :name, :value) Set = Struct.new(:loc, :type, :name, :value) Op = Struct.new(:loc, :type, :op, :left, :right) diff --git a/lib/parser.rb b/lib/parser.rb index 0eabe9e..6ffacfe 100644 --- a/lib/parser.rb +++ b/lib/parser.rb @@ -452,9 +452,17 @@ class Parser elsif tok.type == :ident varname = IR::Var.new(tok.pos, nil, tok.text.to_sym) 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 tok = consume() - field = IR::Var.new(tok.pos, nil, tok.text.to_sym) - varname = make_binop(varname.loc, ".", varname, field) + sym = mod.type.exports[tok.text.to_sym] + if not sym + error("module or record has no such field '#{tok.text}'") + end + varname = IR::Var.new(tok.pos, sym[:type], tok.text.to_sym, varname.name) end varname else diff --git a/lib/type_checker.rb b/lib/type_checker.rb index d000f3f..78542ae 100644 --- a/lib/type_checker.rb +++ b/lib/type_checker.rb @@ -224,10 +224,17 @@ class TypeChecker end def infer_var(env, expr) - if env[expr.name].nil? - error(expr.loc, "symbol '#{expr.name}' not defined") + mod = expr.module + name = expr.name + if mod + expr.type = env[mod].type.exports[name][:type] + else + if env[expr.name].nil? + error(expr.loc, "symbol '#{expr.name}' not defined") + end + expr.type = env[expr.name][:type] end - expr.type = env[expr.name][:type] + expr.type end def infer_def(env, expr) @@ -333,12 +340,6 @@ class TypeChecker type = infer(env, expr.func) end - # Handle module references here - if expr.func.type.is_a? Value::Module - pp "MODULE!!!" - pp expr - end - error(expr.loc, "object being applied is not a function (has type: #{type.to_s})") if not type.is_a? Array error(expr.loc, "wrong number of arguments to function call") if (type.length - 1) != expr.args.length type[0..-2].each_with_index do |t,i| @@ -379,12 +380,7 @@ class TypeChecker end def check_binary(env, expr, vtype) - if expr.op == "." - left_type = infer(env, expr.left) - if not left_type.is_a? Value::Module - error(expr.loc, "left side of '.' is not a module or record") - end - elsif expr.op == "[" + if expr.op == "[" left_type = infer(env, expr.left) if (left_type.is_a? Value::Type) and left_type.form == :array check(env, expr.right, :int) -- 2.52.0