Skip to content

Commit 650acaf

Browse files
committed
function signature declarations
1 parent 013b2fb commit 650acaf

File tree

7 files changed

+51
-9
lines changed

7 files changed

+51
-9
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ For an example displaying the syntax and all the features, see `examples/fma.uni
1111
* define your own derived units
1212
* declare a variable's units and use it in expressions
1313
* define a variable to infer its units, then use it in expressions
14+
* define function signatures
1415
* common derived units (i.e. `N = [kg m s^-2]`), variables (i.e. `g :: [m s^-2]`), and functions (i.e. `sin :: ([]) -> []`) are included in prelude
1516
* has a REPL
1617

@@ -55,7 +56,7 @@ Unit mismatch: Expected units of [kg m s^-2], but got units of [kg] at examples/
5556
## Syntax
5657
a UnitChecker program consists of a list of statements.
5758
A statement can declare the units of a variable, define a variable and infer its units,
58-
define a derived unit (like Newtons), check the units of an expression,
59+
define a derived unit (like Newtons), define the signature of a function, check the units of an expression,
5960
and check the units of both sides of an equation and check that they're equivalent
6061

6162
An expression is an arithmetic expression of variables and numbers with operators `+-*/^`, function calls, and unit annotations
@@ -68,10 +69,13 @@ Here is the context free grammar for a program:
6869
6970
<statement> = 'def' <identifier> '=' <expression>
7071
| 'var' <identifier> '::' <unit>
72+
| 'fun' <identifier> '::' '(' <units>? ')' '->' <unit>
7173
| 'derived' <identifier> '=' <unit>
7274
| 'expr' <expr>
7375
| 'eq' <expr> '=' <expr>
7476
77+
<units> = <unit> | <unit> ',' <units>
78+
7579
<expr> = <expr> <binop> <expr>
7680
| '-' <expr>
7781
| '(' <expr> ')'

examples/fma.unit

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ eq exp(2) = e^2
7878
def Fg = m * (9.8 :: [m s^-2])
7979
eq F = Fg
8080

81+
82+
// defines a function which takes in meters and seconds and outputs meters per second
83+
fun getVel :: ([m], [s]) -> [m s^-1]
84+
def v = getVel(10 :: [m], 1 :: [s])
85+
86+
8187
/*
8288
Running a program outputs newly defined variables and derived units with their corresponding types.
8389
This example program outputs the following:
@@ -94,4 +100,6 @@ f :: [hz]
94100
t :: [s]
95101
x :: []
96102
Fg :: [kg m s^-2]
103+
getVel :: ([m], [s]) -> [m s^-1]
104+
v :: [m s^-1]
97105
*/

src/Check.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ checkWellFormednessWith wfenv (Program statements) = foldl go ([], wfenv) statem
195195
ExprStatement e _ -> (errs++checkExprWellFormedness env e, env)
196196
EqnStatement (Equation left right _) _ -> (errs++checkExprWellFormedness env left++checkExprWellFormedness env right, env)
197197
VarDefStatement name e _ -> (errs++checkExprWellFormedness env e, (deriveds, name:vars, funs))
198+
FunDefStatement name (Signature args ret _) _ -> (errs++concatMap (checkUnit deriveds) (args++[ret]), (deriveds, vars, name:funs))
198199

199200
-- | check the well-formedness of a program using the prelude's defined names as the initial environment
200201
checkWellFormedness :: Program a -> ([Error a], ([String], [String], [String]))
@@ -230,6 +231,7 @@ checkStatement (DerivedDeclStatement (DerivedDecl name unit _) _) = modify $ add
230231
checkStatement (VarDefStatement name e _) = do
231232
unit <- typeSynth e
232233
modify $ addVar name unit
234+
checkStatement (FunDefStatement name sig _) = modify $ addFun name sig
233235

234236
{--
235237
This is the real meat of the type checker. I use a simple bidirectional type system since there is the polymorphism is simple (just binops) and inference is easy.

src/Exprs.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ data Statement a = ExprStatement (Expr a) a
207207
| VarDeclStatement (VarDecl a) a
208208
| DerivedDeclStatement (DerivedDecl a) a
209209
| VarDefStatement String (Expr a) a
210+
| FunDefStatement String (Signature a) a
210211
deriving(Eq, Ord, Show)
211212

212213
-- | A program to be type-checked

src/ParseProgram.hs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,13 @@ statement = varDecl
5353
<|> eqn
5454
<|> derivedDecl
5555
<|> varDef
56+
<|> funDef
5657
<?> "statement"
5758

5859
varDecl :: Parser (Statement SS)
5960
varDecl = do
6061
((name, u), ss) <- wrapSS $ do
61-
() <- keyWordTok "var"
62+
() <- var
6263
name <- ident
6364
() <- annotTok
6465
u <- unit
@@ -71,7 +72,7 @@ exprStatement = uncurry ExprStatement <$> wrapSS (keyWordTok "expr" *> expr)
7172
eqn :: Parser (Statement SS)
7273
eqn = do
7374
((left, right), ss) <- wrapSS $ do
74-
() <- keyWordTok "eq"
75+
() <- eq
7576
left <- expr
7677
() <- eqTok
7778
right <- expr
@@ -81,7 +82,7 @@ eqn = do
8182
derivedDecl :: Parser (Statement SS)
8283
derivedDecl = do
8384
((name, u), ss) <- wrapSS $ do
84-
() <- keyWordTok "derived"
85+
() <- derived
8586
name <- ident
8687
() <- eqTok
8788
u <- unit
@@ -91,9 +92,19 @@ derivedDecl = do
9192
varDef :: Parser (Statement SS)
9293
varDef = do
9394
((name, e), ss) <- wrapSS $ do
94-
() <- keyWordTok "def"
95+
() <- def
9596
name <- ident
9697
() <- eqTok
9798
e <- expr
9899
return (name, e)
99-
return (VarDefStatement name e ss)
100+
return (VarDefStatement name e ss)
101+
102+
funDef :: Parser (Statement SS)
103+
funDef = do
104+
((name, sig), ss) <- wrapSS $ do
105+
fun
106+
name <- ident
107+
annotTok
108+
sig <- signatureP
109+
return (name, sig)
110+
return (FunDefStatement name sig ss)

src/ParseUnit.hs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module ParseUnit(unit, parseUnit) where
1+
module ParseUnit(unit, parseUnit, signatureP, parseSignature) where
22

33
import ParseUtils
44
import Exprs
@@ -39,5 +39,18 @@ basePow = do
3939
unit :: Parser (Unit SS)
4040
unit = fromBasesList <$> (P.brackets lexer (many basePow) <?> "unit")
4141

42+
4243
parseUnit :: String -> Either ParseError (Unit SS)
43-
parseUnit = parse (P.whiteSpace lexer *> unit <* eof) ""
44+
parseUnit = parse (P.whiteSpace lexer *> unit <* eof) ""
45+
46+
signatureP :: Parser (Signature SS)
47+
signatureP = do
48+
((args, ret), ss) <- wrapSS $ do
49+
args <- inParens $ sepBy unit commaTok
50+
arrowTok
51+
ret <- unit
52+
return (args, ret)
53+
return $ Signature args ret ss
54+
55+
parseSignature :: String -> Either ParseError (Signature SS)
56+
parseSignature = parse (P.whiteSpace lexer *> signatureP <* eof) ""

src/ParseUtils.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ lang = P.LanguageDef{
3030
P.opStart = oneOf "+-*/^=:,;",
3131
P.opLetter = oneOf ":",
3232
P.reservedNames = ["var", "def", "fun", "expr", "eq", "derived"],
33-
P.reservedOpNames = ["+", "-", "*", "/", "^", "=", "::", ",", ";"],
33+
P.reservedOpNames = ["+", "-", "*", "/", "^", "=", "::", ",", ";", "->"],
3434
P.caseSensitive = True}
3535

3636
lexer :: P.GenTokenParser String () Data.Functor.Identity.Identity
@@ -83,6 +83,9 @@ minusTok = P.reservedOp lexer "-"
8383
commaTok :: Parser ()
8484
commaTok = P.reservedOp lexer ","
8585

86+
arrowTok :: Parser ()
87+
arrowTok = P.reservedOp lexer "->"
88+
8689
ident :: Parser String
8790
ident = P.identifier lexer
8891

0 commit comments

Comments
 (0)