From 251359fc7ae21fad347d76ff14139a52ce874733 Mon Sep 17 00:00:00 2001 From: Stephan Brandauer Date: Mon, 16 Feb 2015 10:12:13 +0100 Subject: [PATCH] Breathe keyword The `breathe` keyword makes an actor "come up for air": it will check whether any thieves are trying to steal work from an actor and cooperate (if that is the case). The return type is `void`. The test just checks that nothing crashes, as breathe doesn't have any visible side effects, nor a return value. --- src/back/CodeGen/Expr.hs | 4 ++++ src/ir/AST/AST.hs | 1 + src/ir/AST/PrettyPrinter.hs | 14 ++++++++------ src/parser/Parser/Parser.hs | 12 ++++++++---- src/runtime/encore/encore.c | 6 ++++++ src/runtime/encore/encore.h | 4 ++++ src/tests/encore/basic/breathe.enc | 10 ++++++++++ src/tests/encore/basic/breathe.out | 2 ++ src/types/Typechecker/Typechecker.hs | 11 ++++++++--- 9 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 src/tests/encore/basic/breathe.enc create mode 100644 src/tests/encore/basic/breathe.out diff --git a/src/back/CodeGen/Expr.hs b/src/back/CodeGen/Expr.hs index 7863673ad..7e1655fc7 100644 --- a/src/back/CodeGen/Expr.hs +++ b/src/back/CodeGen/Expr.hs @@ -86,6 +86,10 @@ newtype VarLkp = VarLkp String instance Translatable A.Expr (State Ctx.Context (CCode Lval, CCode Stat)) where -- | Translate an expression into the corresponding C code translate skip@(A.Skip {}) = named_tmp_var "skip" (A.getType skip) (AsExpr unit) + translate breathe@(A.Breathe {}) = + named_tmp_var "breathe" + (A.getType breathe) + (Call (Nam "call_respond_with_current_scheduler") ([] :: [CCode Expr])) translate null@(A.Null {}) = named_tmp_var "literal" (A.getType null) Null translate true@(A.BTrue {}) = named_tmp_var "literal" (A.getType true) (Embed "1/*True*/"::CCode Expr) translate false@(A.BFalse {}) = named_tmp_var "literal" (A.getType false) (Embed "0/*False*/"::CCode Expr) diff --git a/src/ir/AST/AST.hs b/src/ir/AST/AST.hs index f85f5ed1b..8c07406ad 100644 --- a/src/ir/AST/AST.hs +++ b/src/ir/AST/AST.hs @@ -119,6 +119,7 @@ instance HasMeta MethodDecl where type Arguments = [Expr] data Expr = Skip {emeta :: Meta Expr} + | Breathe {emeta :: Meta Expr} | TypedExpr {emeta :: Meta Expr, body :: Expr, ty :: Type} diff --git a/src/ir/AST/PrettyPrinter.hs b/src/ir/AST/PrettyPrinter.hs index 45ff7086b..ed31dc491 100644 --- a/src/ir/AST/PrettyPrinter.hs +++ b/src/ir/AST/PrettyPrinter.hs @@ -21,6 +21,7 @@ import AST.AST ppClass = text "class" ppSkip = text "()" +ppBreathe = text "breathe" ppLet = text "let" ppIn = text "in" ppIf = text "if" @@ -128,15 +129,16 @@ ppSugared e = case getSugared e of ppExpr :: Expr -> Doc ppExpr Skip {} = ppSkip -ppExpr MethodCall {target, name, args} = - maybeParens target <> ppDot <> ppName name <> +ppExpr Breathe {} = ppBreathe +ppExpr MethodCall {target, name, args} = + maybeParens target <> ppDot <> ppName name <> parens (commaSep (map ppExpr args)) -ppExpr MessageSend {target, name, args} = - maybeParens target <> ppBang <> ppName name <> +ppExpr MessageSend {target, name, args} = + maybeParens target <> ppBang <> ppName name <> parens (commaSep (map ppExpr args)) -ppExpr FunctionCall {name, args} = +ppExpr FunctionCall {name, args} = ppName name <> parens (commaSep (map ppExpr args)) -ppExpr Closure {eparams, body} = +ppExpr Closure {eparams, body} = ppLambda <> parens (commaSep (map ppParamDecl eparams)) <+> ppArrow <+> ppExpr body ppExpr Let {decls, body} = ppLet <+> vcat (map (\(Name x, e) -> text x <+> equals <+> ppExpr e) decls) $+$ ppIn $+$ diff --git a/src/parser/Parser/Parser.hs b/src/parser/Parser/Parser.hs index 02f8b9a50..d43033efe 100644 --- a/src/parser/Parser/Parser.hs +++ b/src/parser/Parser/Parser.hs @@ -33,13 +33,13 @@ identifier_parser = identifier -- | This creates a tokenizer that reads a language derived from -- the empty language definition 'emptyDef' extended as shown. -lexer = - P.makeTokenParser $ +lexer = + P.makeTokenParser $ emptyDef { P.commentStart = "{-", P.commentEnd = "-}", P.commentLine = "--", P.identStart = letter, - P.reservedNames = ["passive", "class", "def", "stream", + P.reservedNames = ["passive", "class", "def", "stream", "breathe", "let", "in", "if", "unless", "then", "else", "repeat", "while", "get", "yield", "eos", "getNext", "new", "this", "await", "suspend", "and", "or", "not", "true", "false", "null", "embed", "body", "end", @@ -271,6 +271,7 @@ expression = buildExpressionParser opTable expr expr :: Parser Expr expr = unit + <|> breathe <|> try embed <|> try path <|> try functionCall @@ -312,8 +313,11 @@ expr = unit code <- manyTill anyChar $ try $ do {space; reserved "end"} return $ Embed (meta pos) ty code unit = do pos <- getPosition - reservedOp "()" + reservedOp "()" return $ Skip (meta pos) + breathe = do pos <- getPosition + reserved "breathe" + return $ Breathe (meta pos) path = do pos <- getPosition root <- parens expression <|> try functionCall <|> varAccess dot diff --git a/src/runtime/encore/encore.c b/src/runtime/encore/encore.c index 073c31748..55cea0101 100644 --- a/src/runtime/encore/encore.c +++ b/src/runtime/encore/encore.c @@ -4,6 +4,7 @@ #include #include #include +#include "../sched/scheduler.c" // ugh! Need this to call respond extern void pool_free(size_t index, void* p); bool has_flag(pony_actor_t* actor, uint8_t flag); @@ -212,3 +213,8 @@ bool encore_actor_handle_message_hook(encore_actor_t *actor, pony_msg_t* msg) } return false; } + +void call_respond_with_current_scheduler() +{ + respond(this_scheduler); +} diff --git a/src/runtime/encore/encore.h b/src/runtime/encore/encore.h index 2ea75b398..84afb9b2b 100644 --- a/src/runtime/encore/encore.h +++ b/src/runtime/encore/encore.h @@ -87,4 +87,8 @@ bool encore_actor_run_hook(encore_actor_t *actor); bool encore_actor_handle_message_hook(encore_actor_t *actor, pony_msg_t* msg); void actor_block(encore_actor_t *actor); void actor_set_resume(encore_actor_t *actor); + +/// calls the pony's respond with the current object's scheduler +void call_respond_with_current_scheduler(); + #endif /* end of include guard: ENCORE_H_6Q243YHL */ diff --git a/src/tests/encore/basic/breathe.enc b/src/tests/encore/basic/breathe.enc new file mode 100644 index 000000000..7b9adbb59 --- /dev/null +++ b/src/tests/encore/basic/breathe.enc @@ -0,0 +1,10 @@ +class Foo + def foo() : void { + print "out of air!"; + breathe; + print "that's better" + } + +class Main + def main() : void + (new Foo).foo() diff --git a/src/tests/encore/basic/breathe.out b/src/tests/encore/basic/breathe.out new file mode 100644 index 000000000..28907ca8a --- /dev/null +++ b/src/tests/encore/basic/breathe.out @@ -0,0 +1,2 @@ +out of air! +that's better diff --git a/src/types/Typechecker/Typechecker.hs b/src/types/Typechecker/Typechecker.hs index 62797baba..8d46629ac 100644 --- a/src/types/Typechecker/Typechecker.hs +++ b/src/types/Typechecker/Typechecker.hs @@ -234,17 +234,22 @@ instance Checkable Expr where do assertSubtypeOf exprType ty return eExpr where - coerceNull null ty - | isNullType ty || + coerceNull null ty + | isNullType ty || isTypeVar ty = tcError "Cannot infer type of null valued expression" | isRefType ty = return $ setType ty null | otherwise = tcError $ "Null valued expression cannot have type '" ++ show ty ++ "' (must have reference type)" - -- + -- -- ---------------- -- E |- () : void typecheck skip@(Skip {}) = return $ setType voidType skip + -- + -- ---------------- + -- E |- breathe : void + typecheck breathe@(Breathe {}) = return $ setType voidType breathe + --- |- t -- E |- body : t -- ----------------------