Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] View of /branches/vis15/src/compiler/typechecker/env.sml
ViewVC logotype

View of /branches/vis15/src/compiler/typechecker/env.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3463 - (download) (annotate)
Sun Nov 29 15:07:26 2015 UTC (3 years, 11 months ago) by jhr
File size: 9397 byte(s)
working on global reductions in merge
(* env.sml
 *
 * Environments and contexts to support typechecking.
 *
 * This code is part of the Diderot Project (http://diderot-language.cs.uchicago.edu)
 *
 * COPYRIGHT (c) 2015 The University of Chicago
 * All rights reserved.
 *)

structure Env : sig

    type t

  (* create a new environment at global scope that includes the basis environment *)
    val new : unit -> t

    type context = Error.err_stream * Error.span

    datatype scope
      = GlobalScope				(* global declarations *)
      | FunctionScope of Types.ty * Atom.atom	(* inside a function definition *)
      | StrandScope				(* inside a strand definition *)
      | MethodScope of StrandUtil.method_name	(* inside a strand method definition *)
      | InitScope				(* inside global initialization *)
      | CreateScope				(* inside initial strand creation *)
      | UpdateScope				(* inside global update *)

  (* string representation of scope *)
    val scopeToString : scope -> string

  (* return the current scope *)
    val currentScope : t -> scope

  (* are we currently in a strand method scope? *)
    val inMethod : t -> bool

  (* are we currently in a strand scope? *)
    val inStrand : t -> bool

  (* are we currently in the global initialization block? *)
    val inGlobalInit : t -> bool

  (* are we currently in the global update block? *)
    val inGlobalUpdate : t -> bool

  (* start a new function scope *)
    val functionScope : t * Types.ty * Atom.atom -> t
  (* start a new strand scope *)
    val strandScope : t -> t
  (* start a new strand scope *)
    val methodScope : t * StrandUtil.method_name -> t
  (* start a new global initialization scope *)
    val initScope : t -> t
  (* start a new initial-strand creation scope *)
    val createScope : t -> t
  (* start a new global update scope *)
    val updateScope : t -> t
  (* start a new block scope *)
    val blockScope : t -> t

  (* functions are either user-defined or pre-defined *)
    datatype fun_def
      = PrimFun of AST.var list                 (* possibly overloaded builtin function *)
      | UserFun of AST.var                      (* user-defined function *)

  (* insert a global variable into the environment (includes constants and inputs) *)
    val insertGlobal : t * context * Atom.atom * AST.var -> t

  (* insert a user function into the environment *)
    val insertFunc : t * context * Atom.atom * AST.var -> t

  (* insert a strand into the environment *)
    val insertStrand : t * context * StrandEnv.t -> t

  (* insert a local variable into the environment *)
    val insertLocal : t * context * Atom.atom * AST.var -> t

    val findStrand : t * Atom.atom -> StrandEnv.t option
    val findFunc : t * Atom.atom -> fun_def
    val findVar : t * Atom.atom -> AST.var option

  (* find the strand-set function with the given name *)
    val findSetFn : t * Atom.atom -> AST.var option

  (* unwrap a parse-tree location marker and update the context with the span *)
    val withContext : context * 'a Error.mark -> (context * 'a)

  (* same as `withContext`, but includes the environment too *)
    val withEnvAndContext : t * context * 'a Error.mark -> (t * context * 'a)

  (* check for redefinition of an identifier in the same scope *)
    val checkForRedef : t * context * Atom.atom -> unit

  (* tracking program features *)
    val recordProp : t * Properties.t -> unit
    val properties : t -> Properties.t list

  end = struct

    structure GE = GlobalEnv
    structure Ty = Types
    structure AMap = AtomMap

    datatype fun_def = datatype GE.fun_def

    datatype scope
      = GlobalScope				(* global declarations *)
      | FunctionScope of Ty.ty * Atom.atom	(* inside a function definition *)
      | StrandScope				(* inside a strand definition *)
      | MethodScope of StrandUtil.method_name	(* inside a strand method definition *)
      | InitScope				(* inside global initialization *)
      | CreateScope				(* inside initial strand creation *)
      | UpdateScope				(* inside global update *)

    fun scopeToString GlobalScope = "global scope"
      | scopeToString (FunctionScope(_, f)) = "function " ^ Atom.toString f
      | scopeToString StrandScope = "strand initialization"
      | scopeToString (MethodScope m) = "method " ^ StrandUtil.nameToString m
      | scopeToString InitScope = "global initialization"
      | scopeToString CreateScope = "strand creation"
      | scopeToString UpdateScope = "global update"

    datatype t = E of {
        scope : scope,                          (* current scope *)
(* NOTE: since we added location info to variables, we probably don't need this anymore! *)
        bindings : Error.location AMap.map,     (* map from atoms to innermost binding location *)
        gEnv : GE.t,				(* global environment *)
        vEnv : AST.var AMap.map			(* variables defined in inner scopes *)
      }

    type context = Error.err_stream * Error.span

  (* create a fresh environment with global scope from a global environment *)
    fun new () = E{
	    scope = GlobalScope,
	    bindings = AMap.empty,
	    gEnv = Basis.env(),
	    vEnv = AMap.empty
	  }

  (* start a new scope *)
    fun functionScope (E{scope, bindings, gEnv, vEnv}, ty, f) =
          E{scope=FunctionScope(ty, f), bindings=AtomMap.empty, gEnv=gEnv, vEnv=AMap.empty}
    fun strandScope (E{scope, bindings, gEnv, vEnv}) =
          E{scope=StrandScope, bindings=AtomMap.empty, gEnv=gEnv, vEnv=AMap.empty}
    fun methodScope (E{scope, bindings, gEnv, vEnv}, name) =
          E{scope=MethodScope name, bindings=AtomMap.empty, gEnv=gEnv, vEnv=vEnv}
    fun initScope (E{scope, bindings, gEnv, vEnv}) =
          E{scope=InitScope, bindings=AtomMap.empty, gEnv=gEnv, vEnv=AMap.empty}
    fun createScope (E{scope, bindings, gEnv, vEnv}) =
          E{scope=CreateScope, bindings=AtomMap.empty, gEnv=gEnv, vEnv=AMap.empty}
    fun updateScope (E{scope, bindings, gEnv, vEnv}) =
          E{scope=UpdateScope, bindings=AtomMap.empty, gEnv=gEnv, vEnv=AMap.empty}
    fun blockScope (E{scope, bindings, gEnv, vEnv}) =
          E{scope=scope, bindings=AtomMap.empty, gEnv=gEnv, vEnv=vEnv}

    fun currentScope (E{scope, ...}) = scope

    fun inMethod (E{scope=MethodScope _, ...}) = true
      | inMethod _ = false

    fun inStrand (E{scope=StrandScope, ...}) = true
      | inStrand (E{scope=MethodScope _, ...}) = true
      | inStrand _ = false

    fun inGlobalInit (E{scope=InitScope, ...}) = true
      | inGlobalInit _ = false

    fun inGlobalUpdate (E{scope=UpdateScope, ...}) = true
      | inGlobalUpdate _ = false

    fun findStrand (E{gEnv, ...}, s) = GE.findStrand(gEnv, s)
    fun findFunc (E{gEnv, ...}, f) = GE.findFunc(gEnv, f)
    fun findVar (E{gEnv, vEnv, ...}, x) = (case AMap.find(vEnv, x)
	   of NONE => GE.findVar (gEnv, x)
	    | someVar => someVar
	  (* end case *))

  (* find the strand-set function with the given name; we do this by brute force
   * for now.
   *)
    fun findSetFn (_, name) =
	  if Atom.same(name, BasisNames.set_active) then SOME BasisVars.set_active
	  else if Atom.same(name, BasisNames.set_all) then SOME BasisVars.set_all
	  else if Atom.same(name, BasisNames.set_stable) then SOME BasisVars.set_stable
	  else NONE

    fun insertGlobal (E{scope, bindings, gEnv, vEnv}, cxt, x, x') = let
          val loc = Error.location cxt
          in
(*            setLoc(x', loc);*)
	    GE.insertVar (gEnv, x, x');
            E{
              scope = scope,
              bindings = AtomMap.insert(bindings, x, loc),
              gEnv = gEnv,
	      vEnv = vEnv
            }
          end

    fun insertFunc (E{scope, bindings, gEnv, vEnv}, cxt, f, f') =  let
          val loc = Error.location cxt
          in
(*            setLoc(f', loc);*)
	    GE.insertFunc(gEnv, f, GE.UserFun f');
            E{
              scope = scope,
              bindings = AtomMap.insert(bindings, f, loc),
              gEnv = gEnv,
	      vEnv = vEnv
            }
          end

    fun insertStrand (E{scope, bindings, gEnv, vEnv}, cxt, sEnv) = let
	  val () = GE.insertStrand(gEnv, sEnv)
	  val env = E{
		  scope=scope,
		  bindings = AtomMap.insert(bindings, StrandEnv.strandName sEnv, Error.location cxt),
		  gEnv = gEnv,
		  vEnv = vEnv
		}
	  in
	    env
	  end

    fun insertLocal (E{scope, bindings, gEnv, vEnv}, cxt, x, x') = let
          val loc = Error.location cxt
          in
(*            setLoc(x', loc);*)
            E{
              scope = scope,
              bindings = AtomMap.insert(bindings, x, loc),
	      gEnv = gEnv,
              vEnv = AMap.insert(vEnv, x, x')
            }
          end

    fun withContext ((errStrm, _), {span, tree}) =
          ((errStrm, span), tree)
    fun withEnvAndContext (env, (errStrm, _), {span, tree}) =
          (env, (errStrm, span), tree)

  (* check for redefinition of an identifier in the same scope *)
(* TODO: check for shadowing too? *)
    fun checkForRedef (E{bindings, ...}, cxt : context, x) = (case AtomMap.find(bindings, x)
           of SOME loc => TypeError.error (cxt, [
                  TypeError.S "redefinition of ", TypeError.A x,
		  TypeError.S(Error.fmt (", previous definition at line %l", "") loc)
                ])
            | NONE => ()
          (* end case *))

  (* tracking program features *)
    fun recordProp (E{gEnv, ...}, p) = GE.recordProp (gEnv, p)
    fun properties (E{gEnv, ...}) = GE.properties gEnv

  end

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0