on master help sign in
Added binding form to syntax rules (and updated tutorial accordingly)
commit2ec60c8f2b14f80694735a933e800b00d5af6342 authorEdwin Brady <eb@cs.st-andrews.ac.uk> dateWed 30 May 2012, 11:32 (14 years ago) parent0e997ee
14 files changed+177−33
CHANGELOG+1 rts/closure.c+7 rts/closure.h+15−4 src/Idris/AbsSyntax.hs+1 src/Idris/IBC.hs+4 src/Idris/Parser.hs+16−6 src/RTS/Bytecode.hs+13−11 src/RTS/CodegenC.hs+57−3 src/RTS/PreC.hs+7−8 test/README+1 test/test013/expected+12 test/test013/run+4 test/test013/test013.idr+15 tutorial/syntax.tex+24−1
CHANGELOG+1
@@ -3,6 +3,7 @@ New in 0.9.3:
33
44User visible changes:
55
6+* Added binding forms to syntax rules
67* Named class instances
78* Added ':set' command, with options 'errorcontext' for displaying local
89 variables in scope when a unification error occurs, and 'showimplicits'
rts/closure.c+7
@@ -1,5 +1,7 @@
11#include <stdlib.h>
2+#include <stdio.h>
23#include <string.h>
4+#include <unistd.h>
35
46#include "closure.h"
57
@@ -17,6 +19,7 @@ VM* init_vm(int stack_size, size_t heap_size) {
1719 vm -> floatstack_ptr = floatstack;
1820 vm -> stack_max = stack_size;
1921 vm -> heap = malloc(heap_size);
22+ vm -> ret = NULL;
2023 return vm;
2124}
2225
@@ -95,3 +98,7 @@ void EVAL(int update) {
9598
9699}
97100
101+void stackOverflow() {
102+ fprintf(stderr, "Stack overflow");
103+ exit(-1);
104+}
rts/closure.h+15−4
@@ -14,6 +14,7 @@ typedef struct {
1414 double* floatstack_ptr;
1515 void* heap;
1616 int stack_max;
17+ VAL ret;
1718} VM;
1819
1920VM* init_vm(int stack_size, size_t heap_size);
@@ -21,6 +22,15 @@ VM* init_vm(int stack_size, size_t heap_size);
2122// Functions all take a pointer to their VM, and return nothing.
2223typedef void(*func)(VM*);
2324
25+#define EXTEND(n) if (vm->valstack_ptr-vm->valstack + n < vm -> stack_max) \
26+ { vm->valstack_ptr+=(n) } else { stackOverflow(vm); }
27+#define CLEAR(n) vm->valstack_ptr-=(n)
28+#define SLIDE(drop, keep) \
29+ for (i=1; i<=keep; ++i) { \
30+ *(vm->valstack_ptr-i-drop) = *(vm->valstack_ptr-i); \
31+ } \
32+ vm->valstack_ptr-=(drop)
33+
2434typedef enum {
2535 THUNK, CON, INT, FLOAT, STRING, UNIT, PTR
2636} ClosureType;
@@ -60,10 +70,6 @@ typedef struct {
6070#define PUSHFLOAT(i) *(vm->floatstack_ptr++) = i;
6171#define POPFLOAT --vm->floatstack_ptr;
6272
63−#define SLIDE(n) *(vm->valstack_ptr-n) = *(vm->valstack_ptr); vm->valstack_ptr-=n;
64−#define SLIDEINT(n) *(vm->intstack_ptr-n) = *(vm->intstack_ptr); vm->floatstack_ptr-=n;
65−#define SLIDEFLOAT(n) *(vm->floatstack_ptr-n) = *(vm->floatstack_ptr); vm->floatstack_ptr-=n;
66−
6773#define DISCARD(n) vm->valstack_ptr-=n;
6874#define DISCARDINT(n) vm->intstack_ptr-=n;
6975#define DISCARDFLOAT(n) vm->floatstack_ptr-=n;
@@ -78,4 +84,9 @@ VAL mkCon(VM* vm, int tag, int arity);
7884
7985void EVAL(int update);
8086
87+// Handle stack overflow.
88+// Just reports an error and exits.
89+
90+void stackOverflow();
91+
8192#endif
src/Idris/AbsSyntax.hs+1
@@ -790,6 +790,7 @@ deriving instance Binary Syntax
790790
791791data SSymbol = Keyword Name
792792 | Symbol String
793+ | Binding Name
793794 | Expr Name
794795 | SimpleExpr Name
795796 deriving Show
src/Idris/IBC.hs+4
@@ -1408,6 +1408,8 @@ instance Binary SSymbol where
14081408 put x1
14091409 SimpleExpr x1 -> do putWord8 3
14101410 put x1
1411+ Binding x1 -> do putWord8 4
1412+ put x1
14111413 get
14121414 = do i <- getWord8
14131415 case i of
@@ -1419,4 +1421,6 @@ instance Binary SSymbol where
14191421 return (Expr x1)
14201422 3 -> do x1 <- get
14211423 return (SimpleExpr x1)
1424+ 4 -> do x1 <- get
1425+ return (Binding x1)
14221426 _ -> error "Corrupted binary data for SSymbol"
src/Idris/Parser.hs+16−6
@@ -397,6 +397,8 @@ pSyntaxRule syn
397397pSynSym :: IParser SSymbol
398398pSynSym = try (do lchar '['; n <- pName; lchar ']'
399399 return (Expr n))
400+ <|> try (do lchar '{'; n <- pName; lchar '}'
401+ return (Binding n))
400402 <|> do n <- iName []
401403 return (Keyword n)
402404 <|> do sym <- strlit
@@ -556,6 +558,8 @@ pExtensions syn rules = choice (map (\x -> try (pExt syn x)) (filter valid rules
556558 valid (Rule _ _ TermSyntax) = not (inPattern syn)
557559
558560
561+data SynMatch = SynTm PTerm | SynBind Name
562+
559563pExt :: SyntaxInfo -> Syntax -> IParser PTerm
560564pExt syn (Rule ssym ptm _)
561565 = do smap <- mapM pSymbol ssym
@@ -564,21 +568,27 @@ pExt syn (Rule ssym ptm _)
564568 where
565569 pSymbol (Keyword n) = do reserved (show n); return Nothing
566570 pSymbol (Expr n) = do tm <- pExpr syn
567− return $ Just (n, tm)
571+ return $ Just (n, SynTm tm)
568572 pSymbol (SimpleExpr n) = do tm <- pSimpleExpr syn
569− return $ Just (n, tm)
573+ return $ Just (n, SynTm tm)
574+ pSymbol (Binding n) = do b <- pName
575+ return $ Just (n, SynBind b)
570576 pSymbol (Symbol s) = do symbol s
571577 return Nothing
572578 dropn n [] = []
573579 dropn n ((x,t) : xs) | n == x = xs
574580 | otherwise = (x,t):dropn n xs
575581
582+ updateB ns n = case lookup n ns of
583+ Just (SynBind t) -> t
584+ _ -> n
585+
576586 update ns (PRef fc n) = case lookup n ns of
577− Just t -> t
587+ Just (SynTm t) -> t
578588 _ -> PRef fc n
579− update ns (PLam n ty sc) = PLam n (update ns ty) (update (dropn n ns) sc)
580− update ns (PPi p n ty sc) = PPi p n (update ns ty) (update (dropn n ns) sc)
581− update ns (PLet n ty val sc) = PLet n (update ns ty) (update ns val)
589+ update ns (PLam n ty sc) = PLam (updateB ns n) (update ns ty) (update (dropn n ns) sc)
590+ update ns (PPi p n ty sc) = PPi p (updateB ns n) (update ns ty) (update (dropn n ns) sc)
591+ update ns (PLet n ty val sc) = PLet (updateB ns n) (update ns ty) (update ns val)
582592 (update (dropn n ns) sc)
583593 update ns (PApp fc t args) = PApp fc (update ns t) (map (fmap (update ns)) args)
584594 update ns (PCase fc c opts) = PCase fc (update ns c) (map (pmap (update ns)) opts)
src/RTS/Bytecode.hs+13−11
@@ -11,7 +11,7 @@ import Control.Monad.State
1111
1212type Local = Int
1313
14−data BAtom = BP Name | BL Local | BC Const
14+data BAtom = BP Name Int | BL Local | BC Const
1515 deriving Show
1616
1717-- Like SC, but with explicit evaluation, de Bruijn levels for locals, and all
@@ -38,12 +38,12 @@ data BAlt = BConCase Tag [Name] Int Bytecode
3838 deriving Show
3939
4040bcdefs :: [(Name, SCDef)] -> [(Name, (Int, Bytecode))]
41−bcdefs = map (\ (n, s) -> (n, bc s))
41+bcdefs xs = map (\ (n, s) -> (n, bc xs s)) xs
4242
43−bc (SCDef args max c) = (length args,
44− BGetArgs (map fst args) (bcExp max (length args) c))
43+bc all (SCDef args max c) = (length args,
44+ BGetArgs (map fst args) (bcExp all max (length args) c))
4545
46−bcExp v arity x
46+bcExp all v arity x
4747 = let (code, max) = runState (bc' True arity x) v
4848 space = max - arity in
4949 if (space > 0) then BReserve space code else code
@@ -53,14 +53,16 @@ bcExp v arity x
5353 next = do s <- get
5454 put (s + 1)
5555 return s
56−
56+ scarity n = case lookup n all of
57+ Just (SCDef args _ _) -> length args
58+
5759 bc' :: Bool -> Int -> SCExp -> State Int Bytecode
58− bc' tl d (SRef n) = if tl then return $ BTailApp (BP n) []
59− else return $ BApp (BP n) []
60+ bc' tl d (SRef n) = if tl then return $ BTailApp (BP n (scarity n)) []
61+ else return $ BApp (BP n (scarity n)) []
6062 bc' tl d (SLoc i) = do ref i; return $ BAtom (BL i)
6163 bc' tl d (SApp f args)
6264 = do f' <- case f of
63− SRef n -> return $ BAtom (BP n)
65+ SRef n -> return $ BAtom (BP n (scarity n))
6466 _ -> bc' False d f
6567 args' <- mapM (bc' False d) args
6668 let bapp = if tl then BTailApp else BApp
@@ -69,8 +71,8 @@ bcExp v arity x
6971 bc -> do v <- next
7072 mkApp (\x -> BLet v bc (bapp (BL v) x)) args' []
7173 bc' tl d (SLazyApp f args) = do args' <- mapM (bc' False d) args
72− let bapp = if tl then BTailApp else BApp
73− mkApp (\x -> bapp (BP f) x) args' []
74+ -- let bapp = if tl then BTailApp else BApp
75+ mkApp (\x -> BLazy (BP f (scarity f)) x) args' []
7476 bc' tl d (SLet n val sc) = do v' <- bc' False d val
7577 sc' <- bc' False (d + 1) sc
7678 return $ BLet d v' sc'
src/RTS/CodegenC.hs+57−3
@@ -17,6 +17,7 @@ import System.Process
1717import System.IO
1818import System.Directory
1919import System.Environment
20+import Debug.Trace
2021
2122import Paths_idris
2223
@@ -72,18 +73,19 @@ codegenC :: Name -> Int -> PreC -> String
7273codegenC n args prec
7374 = "/* " ++ show prec ++ " */\n\n" ++
7475 "void " ++ cname n ++ "(VM* vm) {\n" ++
76+ indent 1 ++ "int i;\n" ++
7577 concatMap (cg 1) prec ++ "}\n\n"
7678
7779indent i = take (i * 4) (repeat ' ')
7880
7981reg RVal = "vm->ret"
80−reg (LVar v) = "*(vm->stack-" ++ show v ++ ")"
82+reg (LVar v) = "*(vm->valstack_ptr-" ++ show v ++ ")"
8183
8284catom :: CAtom -> String
8385catom (CL l) = reg (LVar l)
8486catom (CC (I i)) = "MKINT(" ++ show i ++ ")"
8587catom (CC v) = "const(" ++ show v ++ ")"
86−catom (CP n) = cname n
88+catom (CP n i) = "MKCLOSURE(" ++ cname n ++ ", " ++ show i ++ ")"
8789
8890off o (CL i) = CL (i + o)
8991off o x = x
@@ -111,6 +113,22 @@ assignFn i r f args
111113 setArgs i (a : as) = reg (LVar i) ++ " = " ++ catom a ++ "; "
112114 ++ setArgs (i + 1) as
113115
116+assignClosure i lazy r atom args
117+ = indent i ++ reg r ++ " = APPLY(" ++ catom atom ++ ", " ++ show (length args) ++
118+ ");\n" ++
119+ indent i ++ setArgs 0 args ++ "\n" ++
120+ if not lazy then
121+ indent i ++ "if (READY(" ++ reg r ++ ")) {\n" ++
122+ indent (i + 1) ++ reg r ++ " = EVAL(" ++ reg r ++ ");\n" ++
123+ indent i ++ "} else {\n" ++
124+ indent (i + 1) ++ "// do nothing \n" ++
125+ indent i ++ "}\n"
126+ else ""
127+ where
128+ setArgs i [] = ""
129+ setArgs i (a : as) = "ADDARG(" ++ show i ++ ", " ++ reg r ++ ", " ++ catom a ++ "); "
130+ ++ setArgs (i + 1) as
131+
114132doTailCall i d f args
115133 = indent i ++ "EXTEND(" ++ show (length args) ++ ");\n" ++
116134 indent i ++ setArgs 1 (map (off (length args)) (reverse args)) ++ "\n" ++
@@ -121,11 +139,36 @@ doTailCall i d f args
121139 setArgs i (a : as) = reg (LVar i) ++ " = " ++ catom a ++ "; "
122140 ++ setArgs (i + 1) as
123141
142+assignFCall i r cfn rt args
143+ = indent i ++ reg r ++ " = " ++ fromC rt ++
144+ "(" ++
145+ cfn ++ "(" ++ showSep ", " (map toCa args) ++ "))" ++ ";\n"
146+ where fromC (Just IType) = "MKINT"
147+ fromC (Just StrType) = "MKSTR"
148+ fromC _ = "MKVAL"
149+
150+ toC (Just IType) = "GETINT"
151+ toC (Just StrType) = "GETSTR"
152+ toC _ = "GETVAL"
153+
154+ toCa (a, ty) = toC ty ++ "(" ++ catom a ++ ")"
155+
156+assignPrimOp i r p args
157+ = indent i ++ reg r ++ " = " ++ op p args ++ ";\n"
158+
124159cg :: Int -> CInst -> String
125160cg i (ASSIGN r (CCon t args))
126161 = assignCon i r t args
127162cg i (ASSIGN r (CExactApp f args))
128163 = assignFn i r f args
164+cg i (ASSIGN r (CApp f args))
165+ = assignClosure i False r f args
166+cg i (ASSIGN r (CLazy f args))
167+ = assignClosure i True r f args
168+cg i (ASSIGN r (CFCall cfn rt args))
169+ = assignFCall i r cfn rt args
170+cg i (ASSIGN r (CPrimOp p args))
171+ = assignPrimOp i r p args
129172cg i (ASSIGN r (CAtom e)) = indent i ++ reg r ++ " = " ++ catom e ++ ";\n"
130173cg i (RESERVE s) = indent i ++ "EXTEND(" ++ show s ++ ");\n"
131174cg i (CLEAR s) = indent i ++ "CLEAR(" ++ show s ++ ");\n"
@@ -145,9 +188,10 @@ cg i (SWITCH v bs def)
145188 branch (t, c) = indent i ++ "case " ++ show t ++ ":\n" ++
146189 concatMap (cg (i+1)) c ++
147190 indent (i+1) ++ "break;\n"
191+cg i (TAILCALL d f args) = assignClosure i False RVal f args -- doTailClosure i d f args
148192cg i (TAILCALLEXACT d f args) = doTailCall i d f args
149193cg i (ERROR s) = indent i ++ "ERROR(" ++ show s ++ ")\n";
150−cg i _ = indent i ++ "NOT DONE;\n"
194+cg i x = trace (show x ++ " not done") $ indent i ++ "NOT DONE;\n"
151195
152196cname :: Name -> String
153197cname (UN s) = "_I_" ++ toC s
@@ -162,3 +206,13 @@ toC s = concatMap special s
162206proto :: Name -> String
163207proto n = "void " ++ cname n ++ "(VM* vm);\n"
164208
209+op AddI [l, r] = "INTOP(+, " ++ catom l ++ ", " ++ catom r ++ ")"
210+op SubI [l, r] = "INTOP(-, " ++ catom l ++ ", " ++ catom r ++ ")"
211+op MulI [l, r] = "INTOP(*, " ++ catom l ++ ", " ++ catom r ++ ")"
212+op DivI [l, r] = "INTOP(/, " ++ catom l ++ ", " ++ catom r ++ ")"
213+
214+op ConcatS [l,r] = "CONCAT(" ++ catom l ++ ", " ++ catom r ++ ")"
215+
216+op o args = trace (show (op, args) ++ " operator undefined")
217+ $ "0 /* Op not defined " ++ show o ++ " */"
218+
src/RTS/PreC.hs+7−8
@@ -9,7 +9,7 @@ import RTS.SC
99
1010import Control.Monad.State
1111
12−data CAtom = CP Name | CL Local | CC Const
12+data CAtom = CP Name Int | CL Local | CC Const
1313 deriving Show
1414
1515data CExp = CAtom CAtom
@@ -46,19 +46,18 @@ type PreC = [CInst]
4646preCdefs :: [(Name, (Int, Bytecode))] -> [(Name, (Int, PreC))]
4747preCdefs xs = map (\ (n, (i, b)) -> (n, preC xs b)) xs
4848
49−atom res (BP n) = CP n
50−atom res (BL n) = CL (res - n)
51−atom res (BC c) = CC c
49+atom res (BP n i) = CP n i
50+atom res (BL n) = CL (res - n)
51+atom res (BC c) = CC c
5252
5353preC :: [(Name, (Int, Bytecode))] -> Bytecode -> (Int, PreC)
5454preC all (BGetArgs ns bc) = (length ns, pc RVal (length ns) bc)
5555 where arity n = do (i, b) <- lookup n all
5656 return i
57− exact (BP n) as = case arity n of
58− Just i -> i == length as
59− Nothing -> False
57+ exact (BP n i) as = i == length as
6058 exact _ as = False
61− getName (BP n) = n
59+
60+ getName (BP n i) = n
6261
6362 pc loc d (BAtom b) = [ASSIGN loc (CAtom (atom d b))]
6463 pc loc d (BApp f as)
test/README+1
@@ -12,3 +12,4 @@ Tests:
1212010: total
1313011: record projection and update
1414012: various error regressions
15+013: binding syntax
test/test013/expectednew file+12
@@ -0,0 +1,12 @@
1+Counting:
2+Number 1
3+Number 2
4+Number 3
5+Number 4
6+Number 5
7+Number 6
8+Number 7
9+Number 8
10+Number 9
11+Number 10
12+Done!
test/test013/runnew file+4
@@ -0,0 +1,4 @@
1+#!/bin/bash
2+idris test013.idr -o test013
3+./test013
4+rm -f test013 test013.ibc
test/test013/test013.idrnew file+15
@@ -0,0 +1,15 @@
1+module main
2+
3+forLoop : List a -> (a -> IO ()) -> IO ()
4+forLoop [] f = return ()
5+forLoop (x :: xs) f = do f x
6+ forLoop xs f
7+
8+syntax for {x} "in" [xs] [body] = forLoop xs (\x => body)
9+
10+main : IO ()
11+main = do putStrLn "Counting:"
12+ for x in [1..10] do
13+ putStrLn $ "Number " ++ show x
14+ putStrLn "Done!"
15+
tutorial/syntax.tex+24−1
@@ -41,7 +41,10 @@ be valid identifiers
4141and \texttt{[e]} here, which stand for arbitrary expressions. To avoid parsing ambiguities,
4242these expressions cannot use syntax extensions at the top level (though they can be used
4343in parentheses).
44−\item \textbf{Symbols} --- included in quotations marks, e.g. \texttt{":="}
44+\item \textbf{Names} --- included in braces, which stand for names which may be bound
45+on the right hand side.
46+\item \textbf{Symbols} --- included in quotations marks, e.g. \texttt{":="}. This can
47+also be used to include reserved words in syntax rules, such as \texttt{"let"} or \texttt{"in"}.
4548\end{itemize}
4649
4750\noindent
@@ -92,5 +95,25 @@ term syntax "[" [x] "..." [y] "]" = MkInterval x y ?bounds_lemma
9295In terms, the syntax \texttt{[x...y]} will generate a proof obligation
9396\texttt{bounds\_lemma} (possibly renamed).
9497
98+Finally, syntax rules may be used to introduce alternative binding forms. For
99+exampe, a \texttt{for} loop binds a variable on each iteration:
100+
101+\begin{SaveVerbatim}{forloop}
102+
103+syntax for {x} "in" [xs] [body] = forLoop xs (\x => body)
104+
105+main : IO ()
106+main = do for x in [1..10] do
107+ putStrLn ("Number " ++ show x)
108+ putStrLn "Done!"
109+
110+\end{SaveVerbatim}
111+\useverb{forloop}
112+
113+\noindent
114+Note that we have used the \texttt{\{x\}} form to state that \texttt{x} represents
115+a bound variable, substituted on the right hand side. We have also put \texttt{"in"} in
116+quotation marks since it is already a reserved word.
117+
95118\input{dsl}
96119