Skip to content
This repository has been archived by the owner on Jan 21, 2022. It is now read-only.

Commit

Permalink
v0.2.0.0 GHCJS support added!
Browse files Browse the repository at this point in the history
  • Loading branch information
boramalper committed Mar 6, 2018
1 parent b27b60b commit fbbed8b
Show file tree
Hide file tree
Showing 13 changed files with 378,546 additions and 81 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### ghcjs ###
*.js_hi
*.js_o


# Created by https://www.gitignore.io/api/haskell,visualstudiocode

Expand Down
6 changes: 5 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Revision history for boolexman

## 0.1.0.0 -- YYYY-mm-dd
## 0.1.0.0 -- 2018-02-26

* First version. Released on an unsuspecting world.

## 0.2.0.0 -- 2018-03-06

* GHCJS support added.
38 changes: 36 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ those (functions) for fully-automated resolution, entailment, and
partial-evaluation. All commands shows *their working* step-by-step, with
detailed explanations of each rule that was used.

## Installation
## Setup
1. Clone the repository
```
$ git clone https://github.com/boramalper/boolexman
Expand Down Expand Up @@ -54,11 +54,45 @@ the tests should fail.
If you intend to contribute to __boolexman__, contact me at
<[email protected]>.

### Compiling the Web Application from the Sources
__boolexman__ can be transmogrified into JavaScript, which in turn allows it to
be used as a Web application in browser, all thanks to
[GHCJS](https://github.com/ghcjs/ghcjs). Although it might not be as reliable as
the traditional method, it also makes __boolexman__ significantly more
*affordable*.

1. Install AND setup GHCJS, and all of its requirements by following the
documentation:

https://github.com/ghcjs/ghcjs

* Booting (*i.e.* `ghcjs-boot`) might take a while, be patient.

2. Enter the `src/` directory:
```
cd src/
```

2. Transmogrify __boolexman__:
```
ghcjs -main-is WebMain --make WebMain.hs -o boolexman
```
3. Copy the JavaScript files:
```
cp boolexman.jsexe/lib.js boolexman.jsexe/out.js boolexman.jsexe/rts.js boolexman.jsexe/runmain.js ../web/
```
3. (Optional) Get rid of the `.js_hi` and `.js_o` files:
```
rm -r *.js* Engine/*.js*
```
## Quick Manual
Each time you run __boolexman__, you will be greeted with a screen like follows:
```
boolexman - boolean expression manipulator | v0.1.0.0
boolexman - boolean expression manipulator | v0.2.0.0

1>
```
Expand Down
6 changes: 3 additions & 3 deletions boolexman.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ name: boolexman
-- PVP summary: +-+------- breaking API changes
-- | | +----- non-breaking API additions
-- | | | +--- code changes with no API change
version: 0.1.0.0
version: 0.2.0.0

-- A short (one-line) description of the package.
synopsis: boolean expression manipulator
Expand All @@ -35,7 +35,7 @@ author: Mert Bora ALPER
maintainer: [email protected]

-- A copyright notice.
-- copyright:
copyright: Copyright (c) 2018 Mert Bora ALPER <[email protected]>

-- category:

Expand All @@ -62,7 +62,7 @@ executable boolexman
-- Other library packages from which modules are imported.
build-depends: base >=4.8 && <4.10
, regex-pcre-builtin >= 0.94.4.8.8.35 && == 0.94.*
-- , transformers >= 0.4.2.0 && == 0.4.*
, transformers >= 0.4.2.0 && == 0.4.*
, QuickCheck >= 2.9.2 && == 2.*
, regex-tdfa >= 1.2.2 && == 1.*
, split >= 0.2.3.1 && == 0.2.*
Expand Down
79 changes: 4 additions & 75 deletions src/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,15 @@ them, and it shows:

import Control.Monad.IO.Class (liftIO)
import Data.Char (toLower)
import Data.List.Split (splitOn)
import System.Console.Haskeline
import Text.Regex.TDFA

import DataTypes
import Engine.Commands
import Parser
import View
import Parser (normaliseString)
import Process
import View (printError, viewLess)

main :: IO ()
main = do
putStrLn "boolexman - boolean expression manipulator | v0.1.0.0"
putStrLn "boolexman - boolean expression manipulator | v0.2.0.0"
runInputT defaultSettings (loop 1)

loop :: Integer -> InputT IO ()
Expand All @@ -58,71 +55,3 @@ loop no = do
formatNo minLength no =
let noStr = show no
in replicate (minLength - length noStr) ' ' ++ noStr

process :: String -> Either String String
process line =
let command = map toLower $ head $ splitOn " " line
argument = drop (length command + 1) line -- +1 for the space character
in case command of
"tabulate" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewTabulate expr $ tabulate expr
"subexpressions" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewSubexpressions expr $ subexpressions expr
"symbols" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewSymbols expr $ symbols expr
-- TODO: This looks really ugly, isn't there a neater way?
"eval" -> -- eval [P, Q] [R, S, T] ((P and Q and R) or (S implies T))
let (_, _, _, matches) = argument =~ (symbolListCRE ++ ' ' : symbolListCRE ++ ' ' : expressionCRE) :: (String, String, String, [String])
in if length matches /= 3
then Left "Parsing Error: supply two lists of symbols, and an expression!"
else case parseCsSymbols $ matches !! 0 of
Left err -> Left $ "Parsing Error: " ++ err ++ " (in the first list)"
Right trueSymbols -> case parseCsSymbols $ matches !! 1 of
Left err -> Left $ "Parsing Error: " ++ err ++ " (in the second list)"
Right falseSymbols -> case parse $ matches !! 2 of
Left err -> Left $ "Parsing Error: " ++ err ++ " (in the expression)"
Right expr -> Right $ viewEval trueSymbols falseSymbols expr $ eval trueSymbols falseSymbols expr -- "tS: " ++ show trueSymbols ++ " fS: " ++ show falseSymbols ++ " ex: " ++ show exp
"todnf" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewDNF expr $ toDNF expr
"tocnf" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewCNF expr $ toCNF expr
"resolve" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewResolution expr $ resolve expr
"entail" ->
let (_, _, _, expressions) = argument =~ (expressionCRE ++ " " ++ expressionCRE)
:: (String, String, String, [String])
in if length expressions /= 2
then Left $ "Parsing Error: could not parse the argument! (make"
++ " sure you enclose the expressions in parantheses)"
else case parseAll expressions of
Left err -> Left $ "Parsing Error: " ++ err
Right [cond, expr] ->
if all (not . (`subexprOf` cond)) [Etrue, Efalse] && all (not . (`subexprOf` expr)) [Etrue, Efalse]
then Right $ viewEntailment cond expr $ entail cond expr
else Left $ "Semantic Error: True and/or False cannot appear in neither"
++ " condition nor expression of an entailment!"
command ->
Left $ "Error: Unknown command: " ++ command ++ " "
where
-- CAPTURES the expression enclosed in parantheses
expressionCRE = "\\((.*)\\)"
-- CAPTURES the comma-separated list of symbols between the square
-- parantheses
-- symbolListCRE = "\\[(" ++ symbolRE ++ "(?: ?, ?" ++ symbolRE ++ ")*)\\]"
symbolListCRE = "\\[(.*)\\]"

parseSoleExpression :: String -> Either String Expr
parseSoleExpression str =
let (a, expression, b) = str =~ expressionCRE :: (String, String, String)
in if null expression || not (null a) || not (null b)
then Left $ "Parsing Error: could not parse the argument! (make"
++ " sure you enclose the expression in parantheses)"
else case parse str of
Left err -> Left $ "Parsing Error: " ++ err
Right expr -> Right expr
93 changes: 93 additions & 0 deletions src/Process.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{- boolexman -- boolean expression manipulator
Copyright (c) 2018 Mert Bora ALPER <[email protected]>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
-}
module Process where

import Data.Char (toLower)
import Data.List.Split (splitOn)
import Text.Regex.TDFA

import DataTypes
import Engine.Commands
import Parser
import View

process :: String -> Either String String
process line =
let command = map toLower $ head $ splitOn " " line
argument = drop (length command + 1) line -- +1 for the space character
in case command of
"tabulate" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewTabulate expr $ tabulate expr
"subexpressions" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewSubexpressions expr $ subexpressions expr
"symbols" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewSymbols expr $ symbols expr
-- TODO: This looks really ugly, isn't there a neater way?
"eval" -> -- eval [P, Q] [R, S, T] ((P and Q and R) or (S implies T))
let (_, _, _, matches) = argument =~ (symbolListCRE ++ ' ' : symbolListCRE ++ ' ' : expressionCRE) :: (String, String, String, [String])
in if length matches /= 3
then Left "Parsing Error: supply two lists of symbols, and an expression!"
else case parseCsSymbols $ matches !! 0 of
Left err -> Left $ "Parsing Error: " ++ err ++ " (in the first list)"
Right trueSymbols -> case parseCsSymbols $ matches !! 1 of
Left err -> Left $ "Parsing Error: " ++ err ++ " (in the second list)"
Right falseSymbols -> case parse $ matches !! 2 of
Left err -> Left $ "Parsing Error: " ++ err ++ " (in the expression)"
Right expr -> Right $ viewEval trueSymbols falseSymbols expr $ eval trueSymbols falseSymbols expr -- "tS: " ++ show trueSymbols ++ " fS: " ++ show falseSymbols ++ " ex: " ++ show exp
"todnf" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewDNF expr $ toDNF expr
"tocnf" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewCNF expr $ toCNF expr
"resolve" -> case parseSoleExpression argument of
Left err -> Left err
Right expr -> Right $ viewResolution expr $ resolve expr
"entail" ->
let (_, _, _, expressions) = argument =~ (expressionCRE ++ " " ++ expressionCRE)
:: (String, String, String, [String])
in if length expressions /= 2
then Left $ "Parsing Error: could not parse the argument! (make"
++ " sure you enclose the expressions in parantheses)"
else case parseAll expressions of
Left err -> Left $ "Parsing Error: " ++ err
Right [cond, expr] ->
if all (not . (`subexprOf` cond)) [Etrue, Efalse] && all (not . (`subexprOf` expr)) [Etrue, Efalse]
then Right $ viewEntailment cond expr $ entail cond expr
else Left $ "Semantic Error: True and/or False cannot appear in neither"
++ " condition nor expression of an entailment!"
command ->
Left $ "Error: Unknown command: " ++ command ++ " "
where
-- CAPTURES the expression enclosed in parantheses
expressionCRE = "\\((.*)\\)"
-- CAPTURES the comma-separated list of symbols between the square
-- parantheses
-- symbolListCRE = "\\[(" ++ symbolRE ++ "(?: ?, ?" ++ symbolRE ++ ")*)\\]"
symbolListCRE = "\\[(.*)\\]"

parseSoleExpression :: String -> Either String Expr
parseSoleExpression str =
let (a, expression, b) = str =~ expressionCRE :: (String, String, String)
in if null expression || not (null a) || not (null b)
then Left $ "Parsing Error: could not parse the argument! (make"
++ " sure you enclose the expression in parantheses)"
else case parse str of
Left err -> Left $ "Parsing Error: " ++ err
Right expr -> Right expr
40 changes: 40 additions & 0 deletions src/WebMain.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{- boolexman -- boolean expression manipulator
Copyright (c) 2018 Mert Bora ALPER <[email protected]>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
-}
module WebMain where

import GHCJS.Types (JSRef, JSVal)
import GHCJS.Foreign.Callback (syncCallback1', releaseCallback, Callback)
import GHCJS.Marshal.Pure
import Data.JSString (pack, unpack, JSString, JSString)

import Process

foreign import javascript unsafe "boolexman = $1"
js_set_somethingUseful :: Callback (JSVal -> IO JSVal) -> IO JSVal

-- https://stackoverflow.com/a/31611311/4466589
main :: IO ()
main = do
cb <- syncCallback1' somethingUseful
js_set_somethingUseful cb
releaseCallback cb

somethingUseful :: JSVal -> IO JSVal
somethingUseful = return . pToJSVal . pack . xxx . process . unpack . pFromJSVal
where
xxx :: Either String String -> String
xxx (Left err) = "I" ++ err -- (I)nline
xxx (Right res) = "D" ++ res -- (D)isplay
64 changes: 64 additions & 0 deletions web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!doctype html>
<!-- boolexman - boolean expression manipulator
Copyright (c) 2018 Mert Bora ALPER <[email protected]>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
-->
<html lang="en-GB">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>boolexman - labs.boramalper.org</title>
<meta name="description" content="boolean expression manipulator for educational purposes" />
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,700&amp;subset=cyrillic,greek" rel="stylesheet">

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="index.css" />

<script src="rts.js"></script>
<script src="lib.js"></script>
<script src="out.js"></script>

<style>
a {
color: black;
}

a:hover, a:focus {
background-color: black;
color: white;
}
</style>
</head>

<body style="display: flex; flex-direction: column; margin: 16px 8px 8px 8px; height: calc(100vh - 16px - 8px);">
<header style="margin-bottom: 1em;">
<strong><a href="http://labs.boramalper.org">labs.</a><a href="http://boramalper.org">boramalper.org</a>/boolexman</strong>
</header>
<noscript>
Wouldn't work!
</noscript>
<main style="display: flex; flex-direction: column; height: 100%">
<div id="terminal" style="margin-bottom: 1em; border: 2px solid black; overflow: auto; font-family: 'Roboto Mono', monospace; white-space: pre; flex-grow: 2;">boolexman -- boolean expression manipulator
Copyright (c) 2018 Mert Bora ALPER &lt;[email protected]&gt;
See <a href="https://github.com/boramalper/boolexman">https://github.com/boramalper/boolexman</a> for help and the source code.

</div>

<div style="border: 2px solid black; display: flex; align-items: baseline; font-family: 'Roboto Mono', monospace;">
<span id="prompt">0001</span><span>&gt;&nbsp;</span><input id="line" type="text" autofocus autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="Enter your commands here." style="flex-grow: 2; border: none; font-family: 'Roboto Mono', monospace; font-size: 1em;">
</div>
</main>
<script src="runmain.js" defer></script>
<script src="index.js"></script>
</body>
</html>
Loading

0 comments on commit fbbed8b

Please sign in to comment.