Skip to content

Commit d94ed5b

Browse files
committed
Made it even more oacml-like
Added explanatory comments to the example file
1 parent 14566af commit d94ed5b

File tree

5 files changed

+57
-31
lines changed

5 files changed

+57
-31
lines changed

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
# Parses an ML style language into ALang
22

3-
[![Build Status](https://travis-ci.org/ohua-dev/alang-sexpr-parser.svg?branch=master)](https://travis-ci.org/ohua-dev/alang-ml-parser)
3+
[![Build Status](https://travis-ci.org/ohua-dev/alang-ml-parser.svg?branch=master)](https://travis-ci.org/ohua-dev/alang-ml-parser)
4+
5+
See [the example test file](/test-resources/something.ohuaml) for an example and
6+
some comments on the syntax.

src/Ohua/Compat/ML/Lexer.x

+7-2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ $sep = [$white]
5353
"=" { direct OPEq }
5454
":" { direct OPColon }
5555
";" { direct OPSemicolon }
56+
";;" { direct OPDoubleSemicolon }
5657
"," { direct OPComma }
5758
"->" { direct OPArrow }
5859
"=>" { direct OPDoubleArrow }
@@ -66,8 +67,11 @@ $sep = [$white]
6667
$reserved { withMatchedInput $ \s -> alexError $ "Reserved symbol: " <> decodeUtf8 s }
6768
}
6869

69-
<comment> "*)" { begin 0 }
70-
<comment> . ;
70+
<comment> {
71+
"*)" { begin 0 }
72+
. ;
73+
\n ;
74+
}
7175

7276
{
7377
type Input = BS.ByteString
@@ -89,6 +93,7 @@ data Lexeme
8993
| OPEq -- ^ operator @=@
9094
| OPColon -- ^ operator @:@
9195
| OPSemicolon -- ^ operator @;@
96+
| OPDoubleSemicolon -- ^ operator @;;@
9297
| OPComma -- ^ operator @,@
9398
| OPArrow -- ^ operator @->@
9499
| OPDoubleArrow -- ^ operator @=>@

src/Ohua/Compat/ML/Parser.y

+16-11
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import Prelude ((!!))
5757
'=' { OPEq }
5858
':' { OPColon }
5959
';' { OPSemicolon }
60+
';;' { OPDoubleSemicolon }
6061
',' { OPComma }
6162
'->' { OPArrow }
6263
'\\' { OPBackslash }
@@ -83,6 +84,10 @@ opt(p)
8384
: p { Just $1 }
8485
| { Nothing }
8586

87+
or(a, b)
88+
: a { Left $1 }
89+
| b { Right $1 }
90+
8691
SomeId :: { SomeBinding }
8792
SomeId
8893
: id { Unqual $1 }
@@ -95,53 +100,53 @@ ModId
95100

96101
Module :: { Module }
97102
Module
98-
: ModHeader many(Import) many_sep(Decl, ';') { ($1, $2, $3) }
103+
: ModHeader many(Import) many(Decl) { ($1, $2, $3) }
99104

100105
ModHeader :: { ModHeader }
101106
ModHeader
102107
: module ModId { $2 }
103108

104109
Import :: { Import }
105110
Import
106-
: import ImportType ModId opt(Refers) { $2 ($3, fromMaybe [] $4) }
111+
: import ImportType ModId opt(Refers) opt(';;') { $2 ($3, fromMaybe [] $4) }
107112

108113
Refers :: { [Binding] }
109114
: '(' many_sep(id, ',') ')' { $2 }
110115

111116
ImportType :: { (NSRef, [Binding]) -> Import }
112117
ImportType
113118
: algo { Right }
114-
| sf { Left }
119+
| sf { Left }
115120

116121
Decl :: { Decl }
117122
Decl
118123
: ValDecl { $1 }
119124

120125
ValDecl :: { ValDecl }
121126
ValDecl
122-
: let LetRhs '=' Exp { case $2 of Left xs -> error $ "Destructuring not allowed for top level bindings: " <> show xs; Right (bnd, f) -> (bnd, f $4) }
127+
: let LetRhs '=' Exp ';;' { case $2 of Left xs -> error $ "Destructuring not allowed for top level bindings: " <> show xs; Right (bnd, f) -> (bnd, f $4) }
123128

124129
SimpleExp :: { Exp }
125130
SimpleExp
126131
: '(' TupleOrExp ')' { $2 }
127-
| SomeId { Var $1 }
128-
| '{' many_sep1(Exp, ';') '}' { let x : xs = $2; ys = x :| xs in foldr' ignoreArgLet (last ys) (init ys) }
132+
| SomeId { Var $1 }
129133

130134
Exp :: { Exp }
131135
Exp
132-
: Exp SimpleExp { Apply $1 $2 }
136+
: Exp SimpleExp { Apply $1 $2 }
133137
| '\\' many1(Pat) '->' Exp { foldr' Lambda $4 $2 }
134-
| let many_sep(Let, ';') in Exp { foldr' ($) $4 $2 }
138+
| let Let in Exp { $2 $4 }
135139
| if Exp then Exp else Exp { Refs.ifBuiltin `Apply` $2 `Apply` ignoreArgLambda $4 `Apply` ignoreArgLambda $6 }
136-
| SimpleExp { $1 }
140+
| Exp ';' Exp { ignoreArgLet $1 $3 }
141+
| SimpleExp { $1 }
137142
138143
Let :: { Exp -> Exp }
139144
Let
140145
: LetRhs '=' Exp { case $1 of Left xs -> Let xs $3; Right (bnd, f) -> Let (Direct bnd) (f $3) }
141146
142147
LetRhs :: { Either Assignment (Binding, Exp -> Exp) }
143148
LetRhs
144-
: Destructure { Left $1 }
149+
: Destructure { Left $1 }
145150
| id many(Pat) { Right ($1, \a -> foldr' Lambda a $2) }
146151

147152
TupleOrExp :: { Exp }
@@ -151,7 +156,7 @@ TupleOrExp
151156
Pat :: { Pat }
152157
Pat
153158
: Destructure { $1 }
154-
| id { Direct $1 }
159+
| id { Direct $1 }
155160
156161
Destructure :: { Pat }
157162
: '(' many_sep(id, ',') ')' { case $2 of [x] -> Direct x; xs -> Destructure xs }

test-resources/something.ohuaml

+24-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
1+
2+
(* Comments are eclosed thusly *)
3+
4+
(* Each module has a name *)
15
module some_ns
26

7+
8+
(* imports are either algos or stateful functions. Using `import` brings the
9+
*module* into scope. Individual items may be included in the refer list
10+
following it, which means they may be used unqualified. *)
11+
312
import sf ohua.math (add, isZero)
4-
import algo some.module (a)
13+
import algo some.module (a);; (* the `;;` is optional here *)
14+
15+
16+
(* top level bindings are defined with `let` and terminate with `;;` *)
17+
let square = \x -> add x x;;
518

6-
let square = \x -> add x x;
19+
(* top level bindings can use the function syntactic sugar of `name [patterns] =
20+
body` for `name = \pat0 -> \pat1 -> ... -> body` *)
721

822
let algo1 someParam =
9-
let a = square someParam;
10-
coll0 = ohua.lang/smap (\i -> square i) coll
11-
in
12-
if isZero a
13-
then coll0
14-
else a;
23+
(* lets are of the form `let pattern = expression in expression` *)
24+
let a = square someParam in
25+
let coll0 = ohua.lang/smap (\i -> square i) coll in
26+
(* if-then-else expressions are supported as one would exprect *)
27+
if isZero a
28+
then coll0
29+
else a;;
1530

1631
let main param param2 =
17-
algo0 param
32+
algo0 param;;

test/Spec.hs

+6-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import Ohua.Prelude
77
import Data.ByteString.Lazy as B
88
import Ohua.ALang.Lang
99
import Ohua.ALang.NS
10-
import Ohua.Compat.ML.Lexer
1110
import Ohua.Compat.ML.Parser
1211
import Test.Hspec
1312

@@ -32,24 +31,20 @@ main =
3231
("something" `Apply` "a" `Apply` "b" `Apply` "c")
3332
describe "let" $ do
3433
it "parses a let" $ lp "let a = b in b" `shouldBe` Let "a" "b" "b"
35-
-- it "parses a let terminating with ';'" $
36-
-- lp "let a = b; in b" `shouldBe` Let "a" "b" "b"
3734
it "parses longer let binds" $
38-
lp "let a = r; b = f; c = print j in a" `shouldBe`
35+
lp "let a = r in let b = f in let c = print j in a" `shouldBe`
3936
Let "a" "r" (Let "b" "f" $ Let "c" ("print" `Apply` "j") "a")
40-
it "parses a block" $
41-
lp "{ print q; a }" `shouldBe` Let "_" ("print" `Apply` "q") "a"
4237
describe "lambda" $ do
4338
it "parses a simple lambda" $
4439
lp "\\ a -> b" `shouldBe` Lambda "a" "b"
4540
it "parses consecutive lambdas" $
46-
lp "\\ a -> \\ (b, c) -> { print a; c }" `shouldBe`
41+
lp "\\ a -> \\ (b, c) -> print a; c" `shouldBe`
4742
Lambda
4843
"a"
4944
(Lambda (Destructure ["b", "c"]) $
5045
Let "_" ("print" `Apply` "a") "c")
5146
it "parses a lambda with 2 arguments" $
52-
lp "\\ a (b, c) -> { print a; c }" `shouldBe`
47+
lp "\\ a (b, c) -> print a; c" `shouldBe`
5348
Lambda
5449
"a"
5550
(Lambda (Destructure ["b", "c"]) $
@@ -59,6 +54,9 @@ main =
5954
lp "a (* comment *)" `shouldBe` "a"
6055
it "parses a comment in an application" $
6156
lp "a (* another comment *) b" `shouldBe` "a" `Apply` "b"
57+
it "supports the wildcard binding" $ do
58+
lp "_" `shouldBe` "_"
59+
lp "let (_, _) = a in b" `shouldBe` Let ["_", "_"] "a" "b"
6260
it "parses the example module" $ (parseMod <$> B.readFile "test-resources/something.ohuaml")
6361
`shouldReturn`
6462
Namespace ["some_ns"]

0 commit comments

Comments
 (0)