]> git.mdlowis.com Git - proto/sclpl-rb.git/commitdiff
updated error messaging and inference of identifiers
authorMichael D. Lowis <mike@mdlowis.com>
Fri, 26 Jun 2020 01:59:16 +0000 (21:59 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Fri, 26 Jun 2020 01:59:16 +0000 (21:59 -0400)
dyn.rb
dyn.src

diff --git a/dyn.rb b/dyn.rb
index b593997ae608b761631bf97a0e75556495df59a9..058a8364e49ab638719aeaec645198afb58f142d 100755 (executable)
--- a/dyn.rb
+++ b/dyn.rb
@@ -100,6 +100,7 @@ class Parser
     :byte   => { prefix: :constant,   infix: nil,         level: :none    },
   }
 
+  Ident = Struct.new(:loc, :type, :name)
   Val    = Struct.new(:loc, :type, :value)
   Def    = Struct.new(:loc, :type, :name, :value)
   Func   = Struct.new(:loc, :type, :args, :body)
@@ -130,13 +131,13 @@ class Parser
       expr = expression()
       if expr.is_a? Def
         error("symbol '#{expr.name}' multiply defined in scope", expr.loc) if syms[expr.name] and syms[expr.name][:loc]
-        syms[expr.name] ||= {}
-        syms[expr.name][:loc] = expr.loc
+        syms[expr.name.name] ||= {}
+        syms[expr.name.name][:loc] = expr.loc
         exprs << Call.new(expr.loc, nil, :set!, [expr.name, expr.value])
-      elsif expr.is_a? Ann and expr.expr.class == Symbol
-        error("symbol '#{expr.expr}' multiply annotated in scope", expr.loc) if syms[expr.expr] and syms[expr.expr][:type]
-        syms[expr.expr] ||= {}
-        syms[expr.expr][:type] = expr.type
+      elsif expr.is_a? Ann and expr.expr.is_a? Ident
+        error("symbol '#{expr.expr.name}' multiply annotated in scope", expr.loc) if syms[expr.expr.name] and syms[expr.expr.name][:type]
+        syms[expr.expr.name] ||= {}
+        syms[expr.expr.name][:type] = expr.type
       else
         exprs << expr;
       end
@@ -185,11 +186,11 @@ class Parser
   end
 
   def variable()
-    @prev.text.to_sym
+    Ident.new(location(), nil, @prev.text.to_sym)
   end
 
   def definition(name)
-    error("invalid identifier for definition") if name.class != Symbol
+    error("invalid identifier for definition") if not name.is_a? Ident
     loc = location()
     expr = expression()
     Def.new(loc, nil, name, expr)
@@ -399,6 +400,14 @@ 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}"
+#    $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)
@@ -406,7 +415,7 @@ module TypeChecker
       check_func(env, expr, type)
     else
       etype = infer(env, expr)
-      raise "expected #{type}, recieved #{etype}" if type != etype
+      error(expr.loc, "expected #{type}, recieved #{etype}") if type != etype
     end
     type
   end
@@ -435,7 +444,7 @@ module TypeChecker
   def self.infer(env, expr)
     if expr.is_a? Parser::Val
       infer_value(env, expr)
-    elsif expr.is_a? Symbol
+    elsif expr.is_a? Parser::Ident
       infer_symbol(env, expr)
     elsif expr.is_a? Parser::Ann
       infer_annotation(env, expr)
@@ -446,7 +455,7 @@ module TypeChecker
     elsif expr.is_a? Parser::IfExpr
       infer_ifexpr(env, expr)
     else
-      raise "unable to infer type of expression"
+      error(expr.loc, "unable to infer type of expression")
     end
   end
 
@@ -455,13 +464,13 @@ module TypeChecker
   end
 
   def self.infer_symbol(env, expr)
-    raise "undefined symbol '#{expr}'" if env[expr].nil?
-    raise "symbol '#{expr}' has unknown type" if env[expr][:type].nil?
-    env[expr][:type]
+    error(expr.loc, "undefined symbol '#{expr.name}'") if env[expr.name].nil?
+    error(expr.loc, "symbol '#{expr.name}' has unknown type") if env[expr.name][:type].nil?
+    env[expr.name][:type]
   end
 
-  def infer_annotation(env, expr)
-    check(env, expr.expr, expr.type)
+  def self.infer_annotation(env, expr)
+      check(env, expr.expr, expr.type)
   end
 
   def self.infer_block(env, expr)
@@ -482,7 +491,7 @@ module TypeChecker
   end
 
   def self.infer_def(env, expr)
-    expr.type = env[expr.args[0]][:type]
+    expr.type = env[expr.args[0].name][:type]
     if (expr.type)
       check(env, expr.args[1], expr.type)
     else
@@ -494,14 +503,14 @@ module TypeChecker
     ltype = infer(env, expr.args[0])
     if expr.args.length == 1
       optype = UnaryOps[expr.func][ltype]
-      raise "unknown unary operation '#{expr.func}' for operand type #{ltype}" if not optype
+      error(expr.loc, "unknown unary operation '#{expr.func}' for operand type #{ltype}") if not optype
       check_call(env, expr, optype)
     elsif expr.args.length == 2
       optype = BinaryOps[expr.func][ltype]
-      raise "unknown binary operation '#{expr.func}' for operand type #{ltype}" if not optype
+      error(expr.loc, "unknown binary operation '#{expr.func}' for operand type #{ltype}") if not optype
       check_call(env, expr, optype)
     else
-      raise "too many operands for operator '#{expr.func}'"
+      error(expr.loc, "too many operands for operator '#{expr.func}'")
     end
   end
 
@@ -514,6 +523,11 @@ parse = Parser.new("dyn.src")
 block = Parser.new("dyn.src").toplevel
 pp TypeChecker.infer({}, block)
 
-
 # TODO:
-#   * refine rules for use of variables before definition and mutually recursive procedures...
\ No newline at end of file
+#   * refine rules for use of variables before definition and mutually recursive procedures...
+#   * Add support for structs
+#   * Add support for checked unions
+#   * Add support for arrays
+#   * Implement proper scoping and shadowing of identifiers
+#   * Implement module system for namespacing
+#   * Implement generic/template system for polymorphism
\ No newline at end of file
diff --git a/dyn.src b/dyn.src
index f672b7801470c19243b22d008f2f3fca79624a08..26e450d1da2278a45d759d7a8dd7613ce560761b 100644 (file)
--- a/dyn.src
+++ b/dyn.src
@@ -5,11 +5,9 @@ false
 123
 123.0
 "foo"
-#b = [1,2,3]
-#{ "foo": 123, foo: 24 }
 
 # operators
-a1 = (456 + 1)
+a = (456 + 1)
 b = (456 - 1)
 c = (456 * 1)
 d = (456 - 1)
@@ -18,23 +16,22 @@ f = (+1)
 
 # conditionals
 if (true) {
-  2
+  1
 } else if (true) {
-  21
+  2
 } else {
-    1
+  3
 }
 
-## functions and application
-##println("foo!")
-##print(1,2,3,4,5,6,7,8,9)
-#
 foo1 : int -> int
 foo1 = fun(a) {
-  b = 123
+  a = 42
+  a = 43
+  b = a
+  a = 42
 #  println("hi!")
 }
-#
-## TODO:
-##   * Get rid of end keyword
-##       * Replace with single or multi-expression blocks
+
+# TODO:
+#   * Get rid of end keyword
+#       * Replace with single or multi-expression blocks