108 lines
3.7 KiB
Text
108 lines
3.7 KiB
Text
/-
|
||
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Author: Sebastian Ullrich
|
||
-/
|
||
prelude
|
||
import init.lean.name init.lean.parser.parsec
|
||
|
||
namespace lean
|
||
namespace parser
|
||
|
||
/-- De Bruijn index relative to surrounding 'bind' macros -/
|
||
@[reducible] def var_offset := ℕ
|
||
@[reducible] def macro_scope_id := ℕ
|
||
|
||
--TODO(Sebastian): move
|
||
structure substring :=
|
||
(start : string.iterator)
|
||
(stop : string.iterator)
|
||
|
||
structure source_info :=
|
||
/- Will be inferred after parsing by `syntax.update_leading`. During parsing,
|
||
it is not at all clear what the preceding token was, especially with backtracking. -/
|
||
(leading : substring)
|
||
(pos : parsec.position)
|
||
(trailing : substring)
|
||
|
||
structure syntax_atom :=
|
||
(info : option source_info) (val : string)
|
||
|
||
/-- A simple wrapper that should remind you to use the static declaration instead
|
||
of hard-coding the node name. -/
|
||
structure syntax_node_kind :=
|
||
-- should be equal to the name of the declaration this structure instance was bound to
|
||
(name : name)
|
||
|
||
structure syntax_node (syntax : Type) :=
|
||
(kind : option syntax_node_kind) (args : list syntax)
|
||
|
||
inductive syntax
|
||
/- any non-ident atom -/
|
||
| atom (val : syntax_atom)
|
||
| node (val : syntax_node syntax)
|
||
| missing
|
||
|
||
instance : inhabited syntax :=
|
||
⟨syntax.missing⟩
|
||
|
||
instance coe_string_syntax : has_coe string syntax :=
|
||
⟨λ s, syntax.atom ⟨none, s⟩⟩
|
||
|
||
def substring.to_string (s : substring) : string :=
|
||
(s.start.extract s.stop).get_or_else ""
|
||
|
||
namespace syntax
|
||
open lean.format
|
||
|
||
protected mutual def to_format, to_format_lst
|
||
with to_format : syntax → format
|
||
| (atom ⟨_, s⟩) := to_fmt $ repr s
|
||
| (node {kind := none, args := args, ..}) :=
|
||
sbracket $ join_sep (to_format_lst args) line
|
||
| (node {kind := some kind, args := args, ..}) :=
|
||
paren $ join_sep (to_fmt (kind.name.replace_prefix `lean.parser name.anonymous) :: to_format_lst args) line
|
||
| missing := "<missing>"
|
||
with to_format_lst : list syntax → list format
|
||
| [] := []
|
||
| (s::ss) := to_format s :: to_format_lst ss
|
||
|
||
private mutual def update_leading_aux, update_leading_lst
|
||
with update_leading_aux : syntax → reader_t string (state string.iterator) syntax
|
||
| (atom a@{info := some info, ..}) := do
|
||
source ← read,
|
||
last ← get,
|
||
put info.trailing.stop,
|
||
pure $ atom {a with info := some {info with leading := ⟨last, source.mk_iterator.nextn info.pos⟩}}
|
||
| (node n) := do args ← update_leading_lst n.args, pure $ node {n with args := args}
|
||
| stx := pure stx
|
||
with update_leading_lst : list syntax → reader_t string (state string.iterator) (list syntax)
|
||
| [] := pure []
|
||
| (s::ss) := list.cons <$> update_leading_aux s <*> update_leading_lst ss
|
||
|
||
/-- Set `source_info.leading` according to the trailing stop of the preceding token.
|
||
The result is a round-tripping syntax tree IF, in the input syntax tree,
|
||
* all leading stops, atom contents, and trailing starts are correct
|
||
* trailing stops are between the trailing start and the next leading stop. -/
|
||
def update_leading (source : string) : syntax → syntax :=
|
||
λ stx, prod.fst $ ((update_leading_aux stx).run source).run source.mk_iterator
|
||
|
||
def reprint_with_info : option source_info → string → string
|
||
| (some info) inner := info.leading.to_string ++ inner ++ info.trailing.to_string
|
||
| none inner := inner
|
||
|
||
mutual def reprint, reprint_lst
|
||
with reprint : syntax → string
|
||
| (atom ⟨info, s⟩) := reprint_with_info info s
|
||
| (node n) := reprint_lst n.args
|
||
| missing := ""
|
||
with reprint_lst : list syntax → string
|
||
| [] := ""
|
||
| (s::ss) := reprint s ++ reprint_lst ss
|
||
end syntax
|
||
|
||
instance : has_to_format syntax := ⟨syntax.to_format⟩
|
||
instance : has_to_string syntax := ⟨to_string ∘ to_fmt⟩
|
||
|
||
end parser
|
||
end lean
|