HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

DSL design -- C DSL

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
designdslstackoverflow

Problem

I am trying to design a DSL for writing C. Here is my code as a GitHub gist (Github does not allow me to have slashes in the filenames so I have used underscores instead). It depends on packages free and process.

My goal is to make the DSL low level enough that one can reasonably predict the output code, and convenient enough to build abstractions on top of.

I would like especially to receive comments on the design. How can I use standard idioms to make the code more maintainable, extendable, composable and easy to use?

Notes on design:

Some functions are prefixed with c- to avoid clashes with Haskell keywords/common functions, e.g. cunion, cwhile, others are not, e.g. struct, typedef. I realize this is confusing, comments on naming convention are welcome.

Operators are suffixed with :, e.g. +: (add), =: (assign), ~: (bitwise complement), ^: (xor).

Generally the constructors are implemented as functions which generate functions.

For example:

varDecl  :: Type -> Iden -> Free Stmt Expr
chgType  :: (Type -> Type) -> (Iden -> Free Stmt a) -> Iden -> Free Stmt Expr
ptr      :: (Iden -> Free Stmt a) -> Iden -> Free Stmt Expr
fun      :: (Iden -> Free Stmt a) -> Iden -> [Free Stmt b] -> Free Stmt () -> Free Stmt ([Expr] -> Free Stmt ())

varDecl t i = let
  v = Var $ TypedIden t i
  in liftF $ VarDecl v (VarExpr v)
int = varDecl CInt

chgType l f i = let
  t = unsafeExtractType f
  in varDecl (l t) i

ptr = chgType CPtr

fun l i vs s = let
  ti = unVar $ extractDecl $ unFree $ l i
  f  = Fun ti (map (extractDecl . unFree) vs) s
  in liftF $ FunDecl f (\es -> stmt $ FunCall f es)


This is ugly but it allows us to write statements like:

x <- ptr int "x"
f <- fun int "f" [int "x1"] $ do
  creturn $ x +: "x1"
f[x]


So, ptr simply takes a TypedIden-like generating function and gives another function which changes the Type in the output. fun takes a TypedIden-like generating function, identifier, list of arguments and a Free Stmt

Solution

Cool stuff! You might also be interested in Galois's Ivory DSL, which does similar things, and has been used to write the code for an autonomous quadcopter / some Boeing autonomous helicopter. It's full of cool tricks that may be relevant:

https://hackage.haskell.org/package/ivory

http://dl.acm.org/citation.cfm?id=2804318

For FFI with C, it might also be worth checking out http://hackage.haskell.org/package/inline-c

I'm not sure what to do about unsafeExtractType. I think you have to change the representation to not be a function in order to resolve this.


Another idiom which seems hack-ish, lift x into the monad and then immediately break the abstraction by extracting it from the monad.

One way to solve this is to make Stmt into a GADT. GADTs allow you to safely restrict which constructors are possible in a datatype, and ASTs are a classic use for it. You'll need tags, though. Something like:

data Stmt tag next where
  ExprStmt :: Expr -> next -> Stmt Expr next
  -- ...


Then, if no other constructors provide a Stmt Expr a, we can write a safe ExprLike (Free (Stmt Expr) a).

Code Snippets

data Stmt tag next where
  ExprStmt :: Expr -> next -> Stmt Expr next
  -- ...

Context

StackExchange Code Review Q#104263, answer score: 4

Revisions (0)

No revisions yet.