From: Michael D. Lowis Date: Fri, 26 Jun 2020 21:08:06 +0000 (-0400) Subject: checkpoint commit X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=6e1ae38de51ab61799a715aaa1f15f936937b6be;p=proto%2Fsclpl-rb.git checkpoint commit --- diff --git a/dyn.rb b/dyn.rb index 058a836..56c0761 100755 --- a/dyn.rb +++ b/dyn.rb @@ -2,6 +2,18 @@ require 'strscan' +$debug = true + +class SymTable < Hash + def initialize(parent = nil) + @parent = parent + end + + def clone + SymTable.new(self) + end +end + class Lexer Tok = Struct.new(:text, :file, :pos, :type) SPACE = /([ \t\v\n\r]+|#.*\n)/ @@ -11,7 +23,6 @@ class Lexer NUMBER = /[0-9]+(\.[0-9]+)?/ STRING = /"(\\"|[^"])*"/ ID_TYPES = { - "nil" => :nil, "true" => :bool, "false" => :bool, "if" => :if, @@ -92,7 +103,6 @@ class Parser :ident => { prefix: :variable, infix: nil, level: :none }, "[" => { prefix: :constant, infix: :subscript, level: :call }, "{" => { prefix: :constant, infix: nil, level: :none }, - :nil => { prefix: :constant, infix: nil, level: :none }, :bool => { prefix: :constant, infix: nil, level: :none }, :int => { prefix: :constant, infix: nil, level: :none }, :string => { prefix: :constant, infix: nil, level: :none }, @@ -202,7 +212,7 @@ class Parser exprs = [] expect("(") while (!matches(")")) - args << expect(:ident).text + args << Ident.new(loc, nil, expect(:ident).text.to_sym) expect(",") if not matches(")") end expect(")") @@ -214,8 +224,6 @@ class Parser Val.new(location(), :int, @prev.text.to_f) elsif (@prev.type == :string) Val.new(location(), :string, @prev.text) - elsif (@prev.type == :nil) - Val.new(location(), :nil, nil) elsif (@prev.type == :bool) Val.new(location(), :bool, (@prev.text == "true")) else @@ -279,6 +287,7 @@ class Parser def error(str, loc = nil) file, pos = (loc ? loc : [@lex.file, (@next || @prev).pos]) puts "#{file}:#{@lex.linenum(pos)}: #{str}" + raise "" if $debug exit 1 end @@ -403,6 +412,7 @@ module TypeChecker 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 @@ -429,7 +439,7 @@ module TypeChecker def self.check_func(env, expr, type) env = env.clone type[0..-2].each_with_index do |t, i| - env[expr.args[i]] = { type: t } + env[expr.args[i].name] = { :loc => expr.loc, :type => t, :set! => true } end check(env, expr.body, type.last) end @@ -455,7 +465,7 @@ module TypeChecker elsif expr.is_a? Parser::IfExpr infer_ifexpr(env, expr) else - error(expr.loc, "unable to infer type of expression") + error(expr.loc, "unable to determine type of expression") end end @@ -464,7 +474,7 @@ module TypeChecker end def self.infer_symbol(env, expr) - error(expr.loc, "undefined symbol '#{expr.name}'") if env[expr.name].nil? + error(expr.loc, "undefined symbol '#{expr.name}'") if env[expr.name].nil? or not env[expr.name][:set!] error(expr.loc, "symbol '#{expr.name}' has unknown type") if env[expr.name][:type].nil? env[expr.name][:type] end @@ -491,12 +501,17 @@ module TypeChecker end def self.infer_def(env, expr) - expr.type = env[expr.args[0].name][:type] + name = expr.args[0].name + expr.type = env[name][:type] if (expr.type) + error(expr.loc, "symbol '#{name}' is multiply defined in scope") if env[name][:set!] check(env, expr.args[1], expr.type) else expr.type = infer(env, expr.args[1]) + env[name][:type] = expr.type end + env[name][:set!] = true + :void end def self.infer_opcall(env, expr) @@ -519,12 +534,14 @@ module TypeChecker end end -parse = Parser.new("dyn.src") block = Parser.new("dyn.src").toplevel pp TypeChecker.infer({}, 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 26e450d..88c4e10 100644 --- a/dyn.src +++ b/dyn.src @@ -1,5 +1,4 @@ # constants -nil true false 123 @@ -23,15 +22,22 @@ if (true) { 3 } +z = 42 foo1 : int -> int -foo1 = fun(a) { - a = 42 - a = 43 - b = a - a = 42 -# println("hi!") +foo1 = fun(y) { +# a : int +# a = 42 + b = z +# z =123 + +# a = 43 + 42 } -# TODO: -# * Get rid of end keyword -# * Replace with single or multi-expression blocks +#add : int -> int +#add = fun(a,b) { +# a + b +#} +## OR: +#add : int -> int +#add = fun(a,b) -> a + b