It is still broken since we apply attributes before we compile code. Recall that attributes such as `@[export]` and `@[extern]` must be applied before we compile code. On the other hand, any attribute `attrName` ``` @[attrName] def foo := ... ``` which creates auxiliary definitions that depend on `foo` must be applied AFTER we generate code for `foo`. Otherwise, we will fail to compile the auxiliary definition since we don't have code for `foo` yet. I will fix the issue above by allowing attributes to specify when they should be applied. I will start with only two options: before and after code compilation. In the future, we may need more options (e.g., before elaboration), but I don't see the need yet. cc @kha
66 lines
2.3 KiB
Text
66 lines
2.3 KiB
Text
/-
|
|
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Leonardo de Moura
|
|
-/
|
|
prelude
|
|
import init.lean.environment
|
|
import init.lean.attributes
|
|
|
|
namespace Lean
|
|
|
|
private def getIOTypeArg : Expr → Option Expr
|
|
| (Expr.app (Expr.const `IO _) arg) := some arg
|
|
| _ := none
|
|
|
|
private def isUnitType : Expr → Bool
|
|
| (Expr.const `Unit _) := true
|
|
| _ := false
|
|
|
|
private def isIOUnit (type : Expr) : Bool :=
|
|
match getIOTypeArg type with
|
|
| some type := isUnitType type
|
|
| _ := false
|
|
|
|
def mkInitAttr : IO (ParametricAttribute Name) :=
|
|
registerParametricAttribute `init "initialization procedure for global references" $ λ env declName stx,
|
|
match env.find declName with
|
|
| none := Except.error "unknown declaration"
|
|
| some decl :=
|
|
match stx with
|
|
| Syntax.ident _ _ initFnName _ _ :=
|
|
match env.find initFnName with
|
|
| none := Except.error ("unknown initialization function '" ++ toString initFnName ++ "'")
|
|
| some initDecl :=
|
|
match getIOTypeArg initDecl.type with
|
|
| none := Except.error ("initialization function '" ++ toString initFnName ++ "' must have type of the form `IO <type>`")
|
|
| some initTypeArg :=
|
|
if decl.type == initTypeArg then Except.ok initFnName
|
|
else Except.error ("initialization function '" ++ toString initFnName ++ "' type mismatch")
|
|
| Syntax.missing :=
|
|
if isIOUnit decl.type then Except.ok Name.anonymous
|
|
else Except.error "initialization function must have type `IO Unit`"
|
|
| _ := Except.error "unexpected kind of argument"
|
|
|
|
@[init mkInitAttr]
|
|
constant initAttr : ParametricAttribute Name := default _
|
|
|
|
def isIOUnitInitFn (env : Environment) (fn : Name) : Bool :=
|
|
match initAttr.getParam env fn with
|
|
| some Name.anonymous := true
|
|
| _ := false
|
|
|
|
@[export lean.get_init_fn_name_for_core]
|
|
def getInitFnNameFor (env : Environment) (fn : Name) : Option Name :=
|
|
match initAttr.getParam env fn with
|
|
| some Name.anonymous := none
|
|
| some n := some n
|
|
| _ := none
|
|
|
|
def hasInitAttr (env : Environment) (fn : Name) : Bool :=
|
|
(getInitFnNameFor env fn).isSome
|
|
|
|
def setInitAttr (env : Environment) (declName : Name) (initFnName : Name := Name.anonymous) : Except String Environment :=
|
|
initAttr.setParam env declName initFnName
|
|
|
|
end Lean
|