]> git.mdlowis.com Git - proto/sclpl-rb.git/commitdiff
checkpoint commit
authorMichael D. Lowis <mike.lowis@gentex.com>
Fri, 26 Jun 2020 21:08:06 +0000 (17:08 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Fri, 26 Jun 2020 21:08:06 +0000 (17:08 -0400)
dyn.rb
dyn.src

diff --git a/dyn.rb b/dyn.rb
index 058a8364e49ab638719aeaec645198afb58f142d..56c07617eaf70c4afab1713ebeeb0bdc795534b3 100755 (executable)
--- 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 26e450d1da2278a45d759d7a8dd7613ce560761b..88c4e10cb231d53b272fe640a02768f8f0f4f0ca 100644 (file)
--- 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