From: Michael D. Lowis Date: Thu, 15 Oct 2020 02:49:46 +0000 (-0400) Subject: corrected generation of globals X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=3dddbc4cf6ebdbfd62814ec02ac9050e52ca5edd;p=proto%2Fsclpl-rb.git corrected generation of globals --- diff --git a/lib/dyn.rb b/lib/dyn.rb index b7f9699..34d06ec 100755 --- a/lib/dyn.rb +++ b/lib/dyn.rb @@ -1,6 +1,5 @@ #!/usr/bin/env ruby # TODO: -# * Implement expression block syntax # * Add support for structs # * Add support for checked unions # * Add support for arrays @@ -38,7 +37,7 @@ class SymTable < Hash def initialize(parent = nil) @parent = (parent || {}) - @freevars = [] + @freevars = {} end def clone(type = :block) @@ -245,7 +244,7 @@ class Parser :byte => { prefix: :constant, infix: nil, level: :none }, } - Ident = Struct.new(:loc, :type, :name) + Ident = Struct.new(:loc, :type, :name, :isfree) Val = Struct.new(:loc, :type, :value) Def = Struct.new(:loc, :type, :name, :value) Func = Struct.new(:loc, :type, :args, :body, :freevars) @@ -329,8 +328,8 @@ class Parser LVLNAMES[index + 1] end - def variable() - Ident.new(location(), nil, @prev.text.to_sym) + def variable(isfree = false) + Ident.new(location(), nil, @prev.text.to_sym, isfree) end def definition(name) @@ -346,7 +345,7 @@ class Parser exprs = [] expect("(") while (!matches(")")) - args << Ident.new(loc, nil, expect(:ident).text.to_sym) + args << Ident.new(loc, nil, expect(:ident).text.to_sym, false) expect(",") if not matches(")") end expect(")") @@ -616,7 +615,10 @@ module TypeChecker def self.infer_symbol(env, expr) error(expr.loc, "undefined symbol '#{expr.name}'") if not env.defined_ever? expr.name - env.freevars << expr.name if env.free? expr.name + if env.free? expr.name + env.freevars[expr.name] = expr.type + expr.isfree = true + end expr.type = env[expr.name][:type] end @@ -651,7 +653,7 @@ module TypeChecker infer(newenv, e) end end - env.freevars = (env.freevars + newenv.freevars).uniq + env.freevars = env.freevars.merge(newenv.freevars) types.last end @@ -713,13 +715,32 @@ class Codegen end end + def emit_global(out, name, type, val = nil) + if type.is_a? Symbol or type.is_a? String + val = emit(out, val) + @protos.puts "#{type.to_s} #{name};" + out.puts "#{name}" +(val ? " = #{val}" : "") + ";" + elsif type.is_a? Array + @protos.puts "#{type.last} #{name}(#{type[0..-2].join(",")});" + emit_func(@funcs, val, name) + else + raise "unsupported var" + end + name + end + + def emit_toplevel(block) out = StringIO.new out.puts "void toplevel(void)" lastexpr = nil out.puts "{" block.exprs.each do |e| - lastexpr = emit(out, e) unless e.is_a? Parser::Ann + if e.is_a? Parser::Def + lastexpr = emit_global(out, e.name.name, e.value.type, e.value) + elsif not e.is_a? Parser::Ann + lastexpr = emit(out, e) + end end out.puts "}" out.string @@ -754,7 +775,7 @@ class Codegen elsif e.is_a? Parser::Func val = emit_func(out, e) elsif e.is_a? Parser::Ident - val = e.name + val = (e.isfree ? "__env->" : "") + e.name.to_s else raise "unsupported expression" end @@ -825,15 +846,22 @@ class Codegen var end - def emit_func(out, e) + def emit_func(out, e, var = nil) newout = StringIO.new - var = mkfunc() + var ||= mkfunc() args = [] e.type[0..-2].each_with_index do |t,i| args << type_to_s(t, e.args[i].name) end @protos.puts "#{e.type.last} #{var}(#{args.join(", ")});" newout.puts "#{e.type.last} #{var}(#{args.join(", ")}) {" + if e.freevars.length > 0 + newout.puts "struct {" + e.freevars.each do |k,v| + newout.puts type_to_s(v, k) + ";" + end + newout.puts "}* __env = Env;" + end exprs = e.body.exprs.map do |e| emit(newout, e) unless e.is_a? Parser::Ann end @@ -841,7 +869,7 @@ class Codegen newout.puts "}\n\n" @funcs.puts newout.string if e.freevars.length > 0 then - "MKCLOSURE(#{var},#{e.freevars.length},#{e.freevars.join(", ")})" + "MKCLOSURE(#{var},#{e.freevars.length},#{e.freevars.keys.join(", ")})" else var end @@ -900,7 +928,7 @@ puts <<-eos #include typedef struct string { - size_t offset; \ + size_t offset; size_t nelems; char* elems; }* string; @@ -910,9 +938,18 @@ static inline void* MKCLOSURE(void* fn, int nfree, ...) return NULL; } -#define STRINGLIT(str) \ +#define STRINGLIT(str) \\ &(struct string){ .offset = 0, .nelems = sizeof(str)-1, .elems = str } +void* Env; + +int main(int argc, char** argv) +{ + extern void toplevel(void); + toplevel(); + return 0; +} + eos puts Codegen.new(tree)