Skip to content

Commit 408425a

Browse files
committed
first commit
0 parents  commit 408425a

File tree

9 files changed

+251
-0
lines changed

9 files changed

+251
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.*
2+
!/.gitignore
3+
/output/
4+
/node_modules/
5+
/bower_components/
6+
/tmp/

Gruntfile.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
module.exports = function(grunt) {
2+
3+
"use strict";
4+
5+
grunt.initConfig({
6+
7+
libFiles: [
8+
"src/**/*.purs",
9+
"bower_components/purescript-*/src/**/*.purs"
10+
],
11+
12+
clean: ["tmp", "output"],
13+
14+
pscMake: {
15+
lib: {
16+
src: ["<%=libFiles%>"]
17+
},
18+
tests: {
19+
src: ["tests/Tests.purs", "<%=libFiles%>"]
20+
}
21+
},
22+
23+
dotPsci: ["<%=libFiles%>"],
24+
25+
copy: [
26+
{
27+
expand: true,
28+
cwd: "output",
29+
src: ["**"],
30+
dest: "tmp/node_modules/"
31+
}, {
32+
src: ["js/index.js"],
33+
dest: "tmp/index.js"
34+
}
35+
],
36+
37+
execute: {
38+
tests: {
39+
src: "tmp/index.js"
40+
}
41+
}
42+
});
43+
44+
grunt.loadNpmTasks("grunt-contrib-copy");
45+
grunt.loadNpmTasks("grunt-contrib-clean");
46+
grunt.loadNpmTasks("grunt-execute")
47+
grunt.loadNpmTasks("grunt-purescript");
48+
49+
grunt.registerTask("test", ["pscMake:tests", "copy", "execute:tests"]);
50+
grunt.registerTask("make", ["pscMake:lib", "dotPsci"]);
51+
grunt.registerTask("default", ["clean", "make", "test"]);
52+
};

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Copyright (c) 2014 Phil Freeman
2+
3+
Permission is hereby granted, free of charge, to any person
4+
obtaining a copy of this software and associated documentation
5+
files (the "Software"), to deal in the Software without
6+
restriction, including without limitation the rights to use,
7+
copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the
9+
Software is furnished to do so, subject to the following
10+
conditions:
11+
12+
The above copyright notice and this permission notice shall be
13+
included in all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# purescript-string-parsers
2+
3+
A free applicative for describing parsers which work on strings
4+
5+
## Building
6+
7+
```
8+
npm install
9+
bower update
10+
grunt
11+
```

bower.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "purescript-string-parsers",
3+
"description": "A free applicative for describing parsers which work on strings",
4+
"keywords": ["purescript"],
5+
"ignore": [
6+
"**/.*",
7+
"bower_components",
8+
"node_modules",
9+
"output",
10+
"tests",
11+
"js",
12+
"tmp",
13+
"bower.json",
14+
"Gruntfile.js",
15+
"package.json"
16+
],
17+
"dependencies": {
18+
"purescript-arrays" : "*",
19+
"purescript-maybe" : "*",
20+
"purescript-strings" : "*",
21+
"purescript-foldable-traversable" : "*"
22+
},
23+
"devDependencies": {
24+
"purescript-math" : "*",
25+
"purescript-quickcheck" : "*"
26+
}
27+
}

js/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require("Main").main();

package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "purescript-string-parsers",
3+
"version": "0.1.0",
4+
"description": "A free applicative for describing parsers which work on strings",
5+
"main": "",
6+
"private": true,
7+
"author": "Phil Freeman",
8+
"license": "MIT",
9+
"dependencies": {
10+
"grunt": "~0.4.4",
11+
"grunt-contrib-copy": "~0.5.0",
12+
"grunt-contrib-clean": "~0.5.0",
13+
"grunt-execute": "~0.1.5",
14+
"grunt-purescript": "~0.5.0"
15+
}
16+
}

src/Text/Parsing/StringParser.purs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
module Text.Parsing.StringParser where
2+
3+
import Data.String (charAt, length, take)
4+
import Data.Either (Either(..))
5+
6+
--
7+
-- Strings are represented as a string with an index from the
8+
-- start of the string.
9+
--
10+
-- { str: s, pos: n } is interpreted as the substring of s
11+
-- starting at index n.
12+
--
13+
-- This allows us to avoid repeatedly finding substrings
14+
-- every time we match a character.
15+
--
16+
type PosString = { str :: String, pos :: Number }
17+
18+
--
19+
-- The type of parsing errors
20+
--
21+
data ParseError = ParseError String
22+
23+
instance showParseError :: Show ParseError where
24+
show (ParseError msg) = msg
25+
26+
--
27+
-- A parser is represented as a function which takes a pair of
28+
-- continuations for failure and success.
29+
--
30+
data Parser a = Parser (forall r. PosString -> (ParseError -> r) -> (a -> PosString -> r) -> r)
31+
32+
unParser :: forall a r. Parser a -> PosString -> (ParseError -> r) -> (a -> PosString -> r) -> r
33+
unParser (Parser p) = p
34+
35+
runParser :: forall a. Parser a -> String -> Either ParseError a
36+
runParser p s = unParser p { str: s, pos: 0 } Left (\a _ -> Right a)
37+
38+
--
39+
-- Parser type class instances
40+
--
41+
42+
instance functorParser :: Functor Parser where
43+
(<$>) f p = Parser (\s fc sc ->
44+
unParser p s fc (\a s' -> sc (f a) s'))
45+
46+
instance applyParser :: Apply Parser where
47+
(<*>) f x = Parser (\s fc sc ->
48+
unParser f s fc (\f' s' ->
49+
unParser x s' fc (\x' s'' -> sc (f' x') s'')))
50+
51+
instance applicativeParser :: Applicative Parser where
52+
pure a = Parser (\s _ sc -> sc a s)
53+
54+
instance bindParser :: Bind Parser where
55+
(>>=) p f = Parser (\s fc sc ->
56+
unParser p s fc (\a s' ->
57+
unParser (f a) s' fc sc))
58+
59+
instance monadParser :: Monad Parser
60+
61+
instance alternativeParser :: Alternative Parser where
62+
empty = Parser (\_ fc _ -> fc (ParseError "No alternative"))
63+
(<|>) p1 p2 = Parser (\s fc sc ->
64+
unParser p1 s (\_ ->
65+
unParser p2 s fc sc) sc)
66+
67+
--
68+
-- Error handling combinator
69+
--
70+
(<?>) :: forall a. Parser a -> String -> Parser a
71+
(<?>) p msg = Parser (\s fc sc -> unParser p s (\_ -> fc (ParseError msg)) sc)
72+
73+
--
74+
-- Some elementary parsers
75+
--
76+
eof :: Parser {}
77+
eof = Parser (\s fc sc -> case s of
78+
{ str = str, pos = i } | i < length str -> fc (ParseError "Expected EOF")
79+
_ -> sc {} s)
80+
81+
anyChar :: Parser String
82+
anyChar = Parser (\s fc sc -> case s of
83+
{ str = str, pos = i } | i < length str -> sc (charAt i str) { str: str, pos: i + 1 }
84+
_ -> fc (ParseError "Unexpected EOF"))
85+
86+
foreign import indexOf'
87+
"function indexOf$prime(x) {\
88+
\ return function(startAt) {\
89+
\ return function(s) {\
90+
\ return s.indexOf(x, startAt);\
91+
\ }; \
92+
\ }; \
93+
\}" :: String -> Number -> String -> Number
94+
95+
string :: String -> Parser String
96+
string nt = Parser (\s fc sc -> case s of
97+
{ str = str, pos = i } | indexOf' nt i str == 0 -> sc nt { str: str, pos: i + length nt }
98+
_ -> fc (ParseError $ "Expected '" ++ nt ++ "'"))
99+

tests/Tests.purs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Main where
2+
3+
import Data.Array
4+
import Data.Maybe
5+
6+
import Debug.Trace
7+
8+
import qualified Text.Parsing.StringParser as P
9+
10+
import qualified Test.QuickCheck as QC
11+
12+
main = do
13+
14+
let test1 = P.string "test" :: P.Parser String
15+
16+
print $ P.runParser test1 "testing"
17+
print $ P.runParser test1 "foo"

0 commit comments

Comments
 (0)