From 0068a43049057c92799b5dc93b326d1422920c47 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Thu, 25 Jun 2020 21:59:16 -0400 Subject: [PATCH] updated error messaging and inference of identifiers --- dyn.rb | 58 +++++++++++++++++++++++++++++++++++---------------------- dyn.src | 27 ++++++++++++--------------- 2 files changed, 48 insertions(+), 37 deletions(-) diff --git a/dyn.rb b/dyn.rb index b593997..058a836 100755 --- 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 f672b78..26e450d 100644 --- 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 -- 2.52.0