@@ -184,7 +184,13 @@ Decl ::=
184184@
185185-}
186186decl :: SyntaxInfo -> IdrisParser [PDecl]
187−decl syn = do fc <- getFC
187+decl syn = try (externalDecl syn)
188+ <|> internalDecl syn
189+ <?> "declaration"
190+
191+internalDecl :: SyntaxInfo -> IdrisParser [PDecl]
192+internalDecl syn
193+ = do fc <- getFC
188194 -- if we're after maxline, stop here
189195 let continue = case maxline syn of
190196 Nothing -> True
@@ -235,6 +241,124 @@ decl' syn = fixity
235241 <|> runElabDecl syn
236242 <?> "declaration"
237243
244+externalDecl :: SyntaxInfo -> IdrisParser [PDecl]
245+externalDecl syn = do i <- get
246+ notEndBlock
247+ FC fn start _ <- getFC
248+ decls <- declExtensions syn (syntaxRulesList $ syntax_rules i)
249+ FC _ _ end <- getFC
250+ let outerFC = FC fn start end
251+ return decls
252+
253+declExtensions :: SyntaxInfo -> [Syntax] -> IdrisParser [PDecl]
254+declExtensions syn rules = declExtension syn [] (filter isDeclRule rules)
255+ <?> "user-defined declaration"
256+ where
257+ isDeclRule (DeclRule _ _) = True
258+ isDeclRule _ = False
259+
260+declExtension :: SyntaxInfo -> [Maybe (Name, SynMatch)] -> [Syntax]
261+ -> IdrisParser [PDecl]
262+declExtension syn ns rules =
263+ choice $ flip map (groupBy (ruleGroup `on` syntaxSymbols) rules) $ \rs ->
264+ case head rs of -- can never be []
265+ DeclRule (symb:_) _ -> try $ do
266+ n <- extSymbol symb
267+ declExtension syn (n : ns) [DeclRule ss t | (DeclRule (_:ss) t) <- rs]
268+ -- If we have more than one Rule in this bucket, our grammar is
269+ -- nondeterministic.
270+ DeclRule [] dec -> let r = map (update (mapMaybe id ns)) dec in
271+ return r
272+
273+ where
274+ update :: [(Name, SynMatch)] -> PDecl -> PDecl
275+ update ns = updateNs ns . fmap (updateRefs ns) . fmap (updateSynMatch ns)
276+
277+ updateRefs ns = mapPT newref
278+ where
279+ newref (PRef fc fcs n) = PRef fc fcs (updateB ns n)
280+ newref t = t
281+
282+ -- Below is a lot of tedious boilerplate which updates any top level
283+ -- names in the declaration. It will only change names which are bound in
284+ -- the declaration (including method names in classes and field names in
285+ -- record declarations, not including pattern variables)
286+ updateB :: [(Name, SynMatch)] -> Name -> Name
287+ updateB ns (NS n mods) = NS (updateB ns n) mods
288+ updateB ns n = case lookup n ns of
289+ Just (SynBind tfc t) -> t
290+ _ -> n
291+
292+ updateNs :: [(Name, SynMatch)] -> PDecl -> PDecl
293+ updateNs ns (PTy doc argdoc s fc o n fc' t)
294+ = PTy doc argdoc s fc o (updateB ns n) fc' t
295+ updateNs ns (PClauses fc o n cs)
296+ = PClauses fc o (updateB ns n) (map (updateClause ns) cs)
297+ updateNs ns (PCAF fc n t) = PCAF fc (updateB ns n) t
298+ updateNs ns (PData ds cds s fc o dat)
299+ = PData ds cds s fc o (updateData ns dat)
300+ updateNs ns (PParams fc ps ds) = PParams fc ps (map (updateNs ns) ds)
301+ updateNs ns (PNamespace s fc ds) = PNamespace s fc (map (updateNs ns) ds)
302+ updateNs ns (PRecord doc syn fc o n fc' ps pdocs fields cname cdoc s)
303+ = PRecord doc syn fc o (updateB ns n) fc' ps pdocs
304+ (map (updateField ns) fields)
305+ (updateRecCon ns cname)
306+ cdoc
307+ s
308+ updateNs ns (PClass docs s fc cs cn fc' ps pdocs pdets ds cname cdocs)
309+ = PClass docs s fc cs (updateB ns cn) fc' ps pdocs pdets
310+ (map (updateNs ns) ds)
311+ (updateRecCon ns cname)
312+ cdocs
313+ updateNs ns (PInstance docs pdocs s fc cs cn fc' ps ity ni ds)
314+ = PInstance docs pdocs s fc cs (updateB ns cn) fc'
315+ ps ity (fmap (updateB ns) ni)
316+ (map (updateNs ns) ds)
317+ updateNs ns (PMutual fc ds) = PMutual fc (map (updateNs ns) ds)
318+ updateNs ns (PProvider docs s fc fc' pw n)
319+ = PProvider docs s fc fc' pw (updateB ns n)
320+ updateNs ns d = d
321+
322+ updateRecCon ns Nothing = Nothing
323+ updateRecCon ns (Just (n, fc)) = Just (updateB ns n, fc)
324+
325+ updateField ns (m, p, t, doc) = (updateRecCon ns m, p, t, doc)
326+
327+ updateClause ns (PClause fc n t ts t' ds)
328+ = PClause fc (updateB ns n) t ts t' (map (update ns) ds)
329+ updateClause ns (PWith fc n t ts t' m ds)
330+ = PWith fc (updateB ns n) t ts t' m (map (update ns) ds)
331+ updateClause ns (PClauseR fc ts t ds)
332+ = PClauseR fc ts t (map (update ns) ds)
333+ updateClause ns (PWithR fc ts t m ds)
334+ = PWithR fc ts t m (map (update ns) ds)
335+
336+ updateData ns (PDatadecl n fc t cs)
337+ = PDatadecl (updateB ns n) fc t (map (updateCon ns) cs)
338+ updateData ns (PLaterdecl n fc t)
339+ = PLaterdecl (updateB ns n) fc t
340+
341+ updateCon ns (cd, ads, cn, fc, ty, fc', fns)
342+ = (cd, ads, updateB ns cn, fc, ty, fc', fns)
343+
344+ ruleGroup [] [] = True
345+ ruleGroup (s1:_) (s2:_) = s1 == s2
346+ ruleGroup _ _ = False
347+
348+ extSymbol :: SSymbol -> IdrisParser (Maybe (Name, SynMatch))
349+ extSymbol (Keyword n) = do fc <- reservedFC (show n)
350+ highlightP fc AnnKeyword
351+ return Nothing
352+ extSymbol (Expr n) = do tm <- expr syn
353+ return $ Just (n, SynTm tm)
354+ extSymbol (SimpleExpr n) = do tm <- simpleExpr syn
355+ return $ Just (n, SynTm tm)
356+ extSymbol (Binding n) = do (b, fc) <- name
357+ return $ Just (n, SynBind fc b)
358+ extSymbol (Symbol s) = do fc <- symbolFC s
359+ highlightP fc AnnKeyword
360+ return Nothing
361+
238362{- | Parses a syntax extension declaration (and adds the rule to parser state)
239363
240364@
@@ -303,6 +427,17 @@ syntaxRule syn
303427 tm <- typeExpr (allowImp syn) >>= uniquifyBinders [n | Binding n <- syms]
304428 terminator
305429 return (Rule (mkSimple syms) tm sty)
430+ <|> do reservedHL "decl"; reservedHL "syntax"
431+ syms <- some syntaxSym
432+ when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
433+ let ns = mapMaybe getName syms
434+ when (length ns /= length (nub ns))
435+ $ unexpected "repeated variable in syntax rule"
436+ lchar '='
437+ openBlock
438+ dec <- some (decl syn)
439+ closeBlock
440+ return (DeclRule (mkSimple syms) (concat dec))
306441 where
307442 isExpr (Expr _) = True
308443 isExpr _ = False
@@ -317,7 +452,7 @@ syntaxRule syn
317452 mkSimple es
318453 -- Can't parse a full expression followed by operator like characters due to ambiguity
319454 mkSimple' (Expr e : Symbol s : es)
320− | takeWhile (`elem` opChars) ts /= "" && ts `notElem` invalidOperators = SimpleExpr e : Symbol s : mkSimple' es
455+ | takeWhile (`elem` opChars) ts /= "" = SimpleExpr e : Symbol s : mkSimple' es
321456 where ts = dropWhile isSpace . dropWhileEnd isSpace $ s
322457 mkSimple' (e : es) = e : mkSimple' es
323458 mkSimple' [] = []