From cf839a0a289029e9cea2807a211855e60c3e01c5 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Fri, 26 Jun 2020 21:53:26 -0400 Subject: [PATCH] added symbol table to correctly handle scoping --- dyn.rb | 59 +++++++++++++++++++++++++++++++++++++++++---------------- dyn.src | 12 ++++-------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/dyn.rb b/dyn.rb index 56c0761..f286d3f 100755 --- a/dyn.rb +++ b/dyn.rb @@ -4,14 +4,53 @@ require 'strscan' $debug = true +def error(loc, msg) + lines = File.read(loc[0])[0..(loc[1])].split("\n") + $stderr.puts "#{loc[0]}:#{lines.length}: #{msg}" +# raise "" if $debug +# $stderr.puts "#{lines.last}" +# $stderr.puts (" " * lines.last.length) + "^" + exit 1 +end + class SymTable < Hash def initialize(parent = nil) - @parent = parent + @parent = (parent || {}) end def clone SymTable.new(self) end + + def [](key) + (super(key) || @parent[key]) + end + + def []=(key, value) + existing = method(:[]).super_method.call(key) + if (not existing.nil?) and existing[:set!] + error(value[:loc], "symbol '#{key}' is multiply defined in scope") + end + super(key,value) + end + + def local?(key) + (not method(:[]).super_method.call(key).nil?) + end + + def global?(key) + if @parent.class == Hash + local?(key) + elsif local? key + false + else + @parent.global? key + end + end + + def merge!(env) + env.each {|k,v| self[k] = v } + end end class Lexer @@ -409,15 +448,6 @@ module TypeChecker "|" => { int: [:int, :int, :int] }, } - def self.error(loc, msg) - lines = File.read(loc[0])[0..(loc[1])].split("\n") - $stderr.puts "#{loc[0]}:#{lines.length}: #{msg}" - raise "" if $debug -# $stderr.puts "#{lines.last}" -# $stderr.puts (" " * lines.last.length) + "^" - exit 1 - end - def self.check(env, expr, type) if (expr.is_a? Parser::IfExpr) check_ifexpr(env, expr, type) @@ -480,11 +510,11 @@ module TypeChecker end def self.infer_annotation(env, expr) - check(env, expr.expr, expr.type) + check(env, expr.expr, expr.type) end def self.infer_block(env, expr) - env = env.merge(expr.syms) + env.merge!(expr.syms) types = expr.exprs.map {|e| infer(env, e) } expr.type = types.last end @@ -535,13 +565,10 @@ module TypeChecker end block = Parser.new("dyn.src").toplevel -pp TypeChecker.infer({}, block) +pp TypeChecker.infer(SymTable.new, block) # TODO: # * Check for correct usage of void on function types and elsewhere... -# * refine rules for use of variables before definition and mutually recursive procedures... -# * Function args need to be defined in scope -# * Shadowing of arguments/globals is broken # * Add support for structs # * Add support for checked unions # * Add support for arrays diff --git a/dyn.src b/dyn.src index 88c4e10..2292eed 100644 --- a/dyn.src +++ b/dyn.src @@ -22,15 +22,11 @@ if (true) { 3 } -z = 42 foo1 : int -> int -foo1 = fun(y) { -# a : int -# a = 42 - b = z -# z =123 - -# a = 43 +foo1 = fun(z) { + a= 42 +# z = 1 +# b = z 42 } -- 2.52.0